1package crr
2
3import (
4	"net/url"
5	"reflect"
6	"testing"
7)
8
9func urlParse(uri string) *url.URL {
10	u, _ := url.Parse(uri)
11	return u
12}
13
14func TestCacheAdd(t *testing.T) {
15	cases := []struct {
16		limit        int64
17		endpoints    []Endpoint
18		validKeys    map[string]Endpoint
19		expectedSize int
20	}{
21		{
22			limit: 5,
23			endpoints: []Endpoint{
24				{
25					Key: "foo",
26					Addresses: []WeightedAddress{
27						{
28							URL: urlParse("http://0"),
29						},
30					},
31				},
32				{
33					Key: "bar",
34					Addresses: []WeightedAddress{
35						{
36							URL: urlParse("http://1"),
37						},
38					},
39				},
40				{
41					Key: "baz",
42					Addresses: []WeightedAddress{
43						{
44							URL: urlParse("http://2"),
45						},
46					},
47				},
48				{
49					Key: "qux",
50					Addresses: []WeightedAddress{
51						{
52							URL: urlParse("http://3"),
53						},
54					},
55				},
56				{
57					Key: "moo",
58					Addresses: []WeightedAddress{
59						{
60							URL: urlParse("http://4"),
61						},
62					},
63				},
64			},
65			validKeys: map[string]Endpoint{
66				"foo": Endpoint{
67					Key: "foo",
68					Addresses: []WeightedAddress{
69						{
70							URL: urlParse("http://0"),
71						},
72					},
73				},
74				"bar": Endpoint{
75					Key: "bar",
76					Addresses: []WeightedAddress{
77						{
78							URL: urlParse("http://1"),
79						},
80					},
81				},
82				"baz": Endpoint{
83					Key: "baz",
84					Addresses: []WeightedAddress{
85						{
86							URL: urlParse("http://2"),
87						},
88					},
89				},
90				"qux": Endpoint{
91					Key: "qux",
92					Addresses: []WeightedAddress{
93						{
94							URL: urlParse("http://3"),
95						},
96					},
97				},
98				"moo": Endpoint{
99					Key: "moo",
100					Addresses: []WeightedAddress{
101						{
102							URL: urlParse("http://4"),
103						},
104					},
105				},
106			},
107			expectedSize: 5,
108		},
109		{
110			limit: 2,
111			endpoints: []Endpoint{
112				{
113					Key: "bar",
114					Addresses: []WeightedAddress{
115						{
116							URL: urlParse("http://1"),
117						},
118					},
119				},
120				{
121					Key: "foo",
122					Addresses: []WeightedAddress{
123						{
124							URL: urlParse("http://0"),
125						},
126					},
127				},
128				{
129					Key: "baz",
130					Addresses: []WeightedAddress{
131						{
132							URL: urlParse("http://2"),
133						},
134					},
135				},
136				{
137					Key: "qux",
138					Addresses: []WeightedAddress{
139						{
140							URL: urlParse("http://3"),
141						},
142					},
143				},
144				{
145					Key: "moo",
146					Addresses: []WeightedAddress{
147						{
148							URL: urlParse("http://4"),
149						},
150					},
151				},
152			},
153			validKeys: map[string]Endpoint{
154				"foo": Endpoint{
155					Key: "foo",
156					Addresses: []WeightedAddress{
157						{
158							URL: urlParse("http://0"),
159						},
160					},
161				},
162				"bar": Endpoint{
163					Key: "bar",
164					Addresses: []WeightedAddress{
165						{
166							URL: urlParse("http://1"),
167						},
168					},
169				},
170				"baz": Endpoint{
171					Key: "baz",
172					Addresses: []WeightedAddress{
173						{
174							URL: urlParse("http://2"),
175						},
176					},
177				},
178				"qux": Endpoint{
179					Key: "qux",
180					Addresses: []WeightedAddress{
181						{
182							URL: urlParse("http://3"),
183						},
184					},
185				},
186				"moo": Endpoint{
187					Key: "moo",
188					Addresses: []WeightedAddress{
189						{
190							URL: urlParse("http://4"),
191						},
192					},
193				},
194			},
195			expectedSize: 2,
196		},
197	}
198
199	for _, c := range cases {
200		cache := NewEndpointCache(c.limit)
201
202		for _, endpoint := range c.endpoints {
203			cache.Add(endpoint)
204		}
205
206		count := 0
207		endpoints := map[string]Endpoint{}
208		cache.endpoints.Range(func(key, value interface{}) bool {
209			count++
210
211			endpoints[key.(string)] = value.(Endpoint)
212			return true
213		})
214
215		if e, a := c.expectedSize, cache.size; int64(e) != a {
216			t.Errorf("expected %v, but received %v", e, a)
217		}
218
219		if e, a := c.expectedSize, count; e != a {
220			t.Errorf("expected %v, but received %v", e, a)
221		}
222
223		for k, ep := range endpoints {
224			endpoint, ok := c.validKeys[k]
225			if !ok {
226				t.Errorf("unrecognized key %q in cache", k)
227			}
228			if e, a := endpoint, ep; !reflect.DeepEqual(e, a) {
229				t.Errorf("expected %v, but received %v", e, a)
230			}
231		}
232	}
233}
234
235func TestCacheGet(t *testing.T) {
236	cases := []struct {
237		addEndpoints []Endpoint
238		validKeys    map[string]Endpoint
239		limit        int64
240	}{
241		{
242			limit: 5,
243			addEndpoints: []Endpoint{
244				{
245					Key: "foo",
246					Addresses: []WeightedAddress{
247						{
248							URL: urlParse("http://0"),
249						},
250					},
251				},
252				{
253					Key: "bar",
254					Addresses: []WeightedAddress{
255						{
256							URL: urlParse("http://1"),
257						},
258					},
259				},
260				{
261					Key: "baz",
262					Addresses: []WeightedAddress{
263						{
264							URL: urlParse("http://2"),
265						},
266					},
267				},
268				{
269					Key: "qux",
270					Addresses: []WeightedAddress{
271						{
272							URL: urlParse("http://3"),
273						},
274					},
275				},
276				{
277					Key: "moo",
278					Addresses: []WeightedAddress{
279						{
280							URL: urlParse("http://4"),
281						},
282					},
283				},
284			},
285			validKeys: map[string]Endpoint{
286				"foo": Endpoint{
287					Key: "foo",
288					Addresses: []WeightedAddress{
289						{
290							URL: urlParse("http://0"),
291						},
292					},
293				},
294				"bar": Endpoint{
295					Key: "bar",
296					Addresses: []WeightedAddress{
297						{
298							URL: urlParse("http://1"),
299						},
300					},
301				},
302				"baz": Endpoint{
303					Key: "baz",
304					Addresses: []WeightedAddress{
305						{
306							URL: urlParse("http://2"),
307						},
308					},
309				},
310				"qux": Endpoint{
311					Key: "qux",
312					Addresses: []WeightedAddress{
313						{
314							URL: urlParse("http://3"),
315						},
316					},
317				},
318				"moo": Endpoint{
319					Key: "moo",
320					Addresses: []WeightedAddress{
321						{
322							URL: urlParse("http://4"),
323						},
324					},
325				},
326			},
327		},
328		{
329			limit: 2,
330			addEndpoints: []Endpoint{
331				{
332					Key: "bar",
333					Addresses: []WeightedAddress{
334						{
335							URL: urlParse("http://1"),
336						},
337					},
338				},
339				{
340					Key: "foo",
341					Addresses: []WeightedAddress{
342						{
343							URL: urlParse("http://0"),
344						},
345					},
346				},
347				{
348					Key: "baz",
349					Addresses: []WeightedAddress{
350						{
351							URL: urlParse("http://2"),
352						},
353					},
354				},
355				{
356					Key: "qux",
357					Addresses: []WeightedAddress{
358						{
359							URL: urlParse("http://3"),
360						},
361					},
362				},
363				{
364					Key: "moo",
365					Addresses: []WeightedAddress{
366						{
367							URL: urlParse("http://4"),
368						},
369					},
370				},
371			},
372			validKeys: map[string]Endpoint{
373				"foo": Endpoint{
374					Key: "foo",
375					Addresses: []WeightedAddress{
376						{
377							URL: urlParse("http://0"),
378						},
379					},
380				},
381				"bar": Endpoint{
382					Key: "bar",
383					Addresses: []WeightedAddress{
384						{
385							URL: urlParse("http://1"),
386						},
387					},
388				},
389				"baz": Endpoint{
390					Key: "baz",
391					Addresses: []WeightedAddress{
392						{
393							URL: urlParse("http://2"),
394						},
395					},
396				},
397				"qux": Endpoint{
398					Key: "qux",
399					Addresses: []WeightedAddress{
400						{
401							URL: urlParse("http://3"),
402						},
403					},
404				},
405				"moo": Endpoint{
406					Key: "moo",
407					Addresses: []WeightedAddress{
408						{
409							URL: urlParse("http://4"),
410						},
411					},
412				},
413			},
414		},
415	}
416
417	for _, c := range cases {
418		cache := NewEndpointCache(c.limit)
419
420		for _, endpoint := range c.addEndpoints {
421			cache.Add(endpoint)
422		}
423
424		keys := []string{}
425		cache.endpoints.Range(func(key, value interface{}) bool {
426			a := value.(Endpoint)
427			e, ok := c.validKeys[key.(string)]
428			if !ok {
429				t.Errorf("unrecognized key %q in cache", key.(string))
430			}
431
432			if !reflect.DeepEqual(e, a) {
433				t.Errorf("expected %v, but received %v", e, a)
434			}
435
436			keys = append(keys, key.(string))
437			return true
438		})
439
440		for _, key := range keys {
441			a, ok := cache.get(key)
442			if !ok {
443				t.Errorf("expected key to be present: %q", key)
444			}
445
446			e := c.validKeys[key]
447			if !reflect.DeepEqual(e, a) {
448				t.Errorf("expected %v, but received %v", e, a)
449			}
450		}
451	}
452}
453