1package quic
2
3import (
4	"fmt"
5
6	. "github.com/onsi/ginkgo"
7	. "github.com/onsi/gomega"
8)
9
10var _ = Describe("Token Cache", func() {
11	var s TokenStore
12
13	BeforeEach(func() {
14		s = NewLRUTokenStore(3, 4)
15	})
16
17	mockToken := func(num int) *ClientToken {
18		return &ClientToken{data: []byte(fmt.Sprintf("%d", num))}
19	}
20
21	Context("for a single origin", func() {
22		const origin = "localhost"
23
24		It("adds and gets tokens", func() {
25			s.Put(origin, mockToken(1))
26			s.Put(origin, mockToken(2))
27			Expect(s.Pop(origin)).To(Equal(mockToken(2)))
28			Expect(s.Pop(origin)).To(Equal(mockToken(1)))
29			Expect(s.Pop(origin)).To(BeNil())
30		})
31
32		It("overwrites old tokens", func() {
33			s.Put(origin, mockToken(1))
34			s.Put(origin, mockToken(2))
35			s.Put(origin, mockToken(3))
36			s.Put(origin, mockToken(4))
37			s.Put(origin, mockToken(5))
38			Expect(s.Pop(origin)).To(Equal(mockToken(5)))
39			Expect(s.Pop(origin)).To(Equal(mockToken(4)))
40			Expect(s.Pop(origin)).To(Equal(mockToken(3)))
41			Expect(s.Pop(origin)).To(Equal(mockToken(2)))
42			Expect(s.Pop(origin)).To(BeNil())
43		})
44
45		It("continues after getting a token", func() {
46			s.Put(origin, mockToken(1))
47			s.Put(origin, mockToken(2))
48			s.Put(origin, mockToken(3))
49			Expect(s.Pop(origin)).To(Equal(mockToken(3)))
50			s.Put(origin, mockToken(4))
51			s.Put(origin, mockToken(5))
52			Expect(s.Pop(origin)).To(Equal(mockToken(5)))
53			Expect(s.Pop(origin)).To(Equal(mockToken(4)))
54			Expect(s.Pop(origin)).To(Equal(mockToken(2)))
55			Expect(s.Pop(origin)).To(Equal(mockToken(1)))
56			Expect(s.Pop(origin)).To(BeNil())
57		})
58	})
59
60	Context("for multiple origins", func() {
61		It("adds and gets tokens", func() {
62			s.Put("host1", mockToken(1))
63			s.Put("host2", mockToken(2))
64			Expect(s.Pop("host1")).To(Equal(mockToken(1)))
65			Expect(s.Pop("host1")).To(BeNil())
66			Expect(s.Pop("host2")).To(Equal(mockToken(2)))
67			Expect(s.Pop("host2")).To(BeNil())
68		})
69
70		It("evicts old entries", func() {
71			s.Put("host1", mockToken(1))
72			s.Put("host2", mockToken(2))
73			s.Put("host3", mockToken(3))
74			s.Put("host4", mockToken(4))
75			Expect(s.Pop("host1")).To(BeNil())
76			Expect(s.Pop("host2")).To(Equal(mockToken(2)))
77			Expect(s.Pop("host3")).To(Equal(mockToken(3)))
78			Expect(s.Pop("host4")).To(Equal(mockToken(4)))
79		})
80
81		It("moves old entries to the front, when new tokens are added", func() {
82			s.Put("host1", mockToken(1))
83			s.Put("host2", mockToken(2))
84			s.Put("host3", mockToken(3))
85			s.Put("host1", mockToken(11))
86			// make sure one is evicted
87			s.Put("host4", mockToken(4))
88			Expect(s.Pop("host2")).To(BeNil())
89			Expect(s.Pop("host1")).To(Equal(mockToken(11)))
90			Expect(s.Pop("host1")).To(Equal(mockToken(1)))
91			Expect(s.Pop("host3")).To(Equal(mockToken(3)))
92			Expect(s.Pop("host4")).To(Equal(mockToken(4)))
93		})
94
95		It("deletes hosts that are empty", func() {
96			s.Put("host1", mockToken(1))
97			s.Put("host2", mockToken(2))
98			s.Put("host3", mockToken(3))
99			Expect(s.Pop("host2")).To(Equal(mockToken(2)))
100			Expect(s.Pop("host2")).To(BeNil())
101			// host2 is now empty and should have been deleted, making space for host4
102			s.Put("host4", mockToken(4))
103			Expect(s.Pop("host1")).To(Equal(mockToken(1)))
104			Expect(s.Pop("host3")).To(Equal(mockToken(3)))
105			Expect(s.Pop("host4")).To(Equal(mockToken(4)))
106		})
107	})
108})
109