github.com/elfadel/cilium@v1.6.12/pkg/fqdn/cache_test.go (about) 1 // Copyright 2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build !privileged_tests 16 17 package fqdn 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "math/rand" 23 "net" 24 "regexp" 25 "sort" 26 "time" 27 28 "github.com/cilium/cilium/pkg/checker" 29 . "gopkg.in/check.v1" 30 ) 31 32 type DNSCacheTestSuite struct{} 33 34 var _ = Suite(&DNSCacheTestSuite{}) 35 36 // TestUpdateLookup tests that we can insert DNS data and retrieve it. We 37 // iterate through time, ensuring that data is expired as appropriate. We also 38 // insert redundant DNS entries that should not change the output. 39 func (ds *DNSCacheTestSuite) TestUpdateLookup(c *C) { 40 name := "test.com" 41 now := time.Now() 42 cache := NewDNSCache(0) 43 endTimeSeconds := 4 44 45 // Add 1 new entry "per second", and one with a redundant IP (with ttl/2). 46 // The IP reflects the second in which it will expire, and should show up for 47 // all now+ttl that is less than it. 48 for i := 1; i <= endTimeSeconds; i++ { 49 ttl := i 50 cache.Update(now, 51 name, 52 []net.IP{net.ParseIP(fmt.Sprintf("1.1.1.%d", i)), net.ParseIP(fmt.Sprintf("2.2.2.%d", i))}, 53 ttl) 54 55 cache.Update(now, 56 name, 57 []net.IP{net.ParseIP(fmt.Sprintf("1.1.1.%d", i))}, 58 ttl/2) 59 } 60 61 // lookup our entries 62 // - no redundant entries (the 1.1.1.x is not repeated) 63 // - with each step of secondsPastNow, fewer entries are returned 64 for secondsPastNow := 1; secondsPastNow <= endTimeSeconds; secondsPastNow++ { 65 ips := cache.lookupByTime(now.Add(time.Duration(secondsPastNow)*time.Second), name) 66 c.Assert(len(ips), Equals, 2*(endTimeSeconds-secondsPastNow+1), Commentf("Incorrect number of IPs returned")) 67 68 // Check that we returned each 1.1.1.x entry where x={1..endTimeSeconds} 69 // These are sorted, and are in the first half of the array 70 // Similarly, check the 2.2.2.x entries in the second half of the array 71 j := secondsPastNow 72 halfIndex := endTimeSeconds - secondsPastNow + 1 73 for _, ip := range ips[:halfIndex] { 74 c.Assert(ip.String(), Equals, fmt.Sprintf("1.1.1.%d", j), Commentf("Incorrect IP returned (j=%d, secondsPastNow=%d)", j, secondsPastNow)) 75 j++ 76 } 77 j = secondsPastNow 78 for _, ip := range ips[halfIndex:] { 79 c.Assert(ip.String(), Equals, fmt.Sprintf("2.2.2.%d", j), Commentf("Incorrect IP returned (j=%d, secondsPastNow=%d)", j, secondsPastNow)) 80 j++ 81 } 82 } 83 } 84 85 // TestDelete tests that we can forcibly clear parts of the cache. 86 func (ds *DNSCacheTestSuite) TestDelete(c *C) { 87 names := map[string]net.IP{ 88 "test1.com": net.ParseIP("2.2.2.1"), 89 "test2.com": net.ParseIP("2.2.2.2"), 90 "test3.com": net.ParseIP("2.2.2.3")} 91 sharedIP := net.ParseIP("1.1.1.1") 92 now := time.Now() 93 cache := NewDNSCache(0) 94 95 // Insert 3 records with 1 shared IP and 3 with different IPs 96 cache.Update(now, "test1.com", []net.IP{sharedIP, names["test1.com"]}, 5) 97 cache.Update(now, "test2.com", []net.IP{sharedIP, names["test2.com"]}, 5) 98 cache.Update(now, "test3.com", []net.IP{sharedIP, names["test3.com"]}, 5) 99 100 now = now.Add(time.Second) 101 102 // Test that a non-matching ForceExpire doesn't do anything. All data should 103 // still be present. 104 nameMatch, err := regexp.Compile("^notatest.com$") 105 c.Assert(err, IsNil) 106 namesAffected := cache.ForceExpire(now, nameMatch) 107 c.Assert(len(namesAffected), Equals, 0, Commentf("Incorrect count of names removed %v", namesAffected)) 108 for _, name := range []string{"test1.com", "test2.com", "test3.com"} { 109 ips := cache.lookupByTime(now, name) 110 c.Assert(len(ips), Equals, 2, Commentf("Wrong count of IPs returned (%v) for non-deleted name '%s'", ips, name)) 111 } 112 113 // Delete a single name and check that 114 // - It is returned in namesAffected 115 // - Lookups for it show no data, but data remains for other names 116 nameMatch, err = regexp.Compile("^test1.com$") 117 c.Assert(err, IsNil) 118 namesAffected = cache.ForceExpire(now, nameMatch) 119 c.Assert(len(namesAffected), Equals, 1, Commentf("Incorrect count of names removed %v", namesAffected)) 120 c.Assert(namesAffected[0], Equals, "test1.com", Commentf("Incorrect affected name returned on forced expire: %s", namesAffected)) 121 ips := cache.lookupByTime(now, "test1.com") 122 c.Assert(len(ips), Equals, 0, Commentf("IPs returned (%v) for deleted name 'test1.com'", ips)) 123 for _, name := range []string{"test2.com", "test3.com"} { 124 ips = cache.lookupByTime(now, name) 125 c.Assert(len(ips), Equals, 2, Commentf("Wrong count of IPs returned (%v) for non-deleted name '%s'", ips, name)) 126 } 127 128 // Delete the whole cache. This should leave no data. 129 namesAffected = cache.ForceExpire(now, nil) 130 sort.Strings(namesAffected) // simplify the checks below 131 c.Assert(len(namesAffected), Equals, 2, Commentf("Incorrect count of names removed %v", namesAffected)) 132 for i, name := range []string{"test2.com", "test3.com"} { 133 c.Assert(namesAffected[i], Equals, name, Commentf("Incorrect affected name returned on forced expire")) 134 } 135 for name := range names { 136 ips = cache.lookupByTime(now, name) 137 c.Assert(len(ips), Equals, 0, Commentf("Returned IP data for %s after the cache was fully cleared: %v", name, ips)) 138 } 139 dump := cache.Dump() 140 c.Assert(len(dump), Equals, 0, Commentf("Returned cache entries from cache dump after the cache was fully cleared: %v", dump)) 141 } 142 143 func (ds *DNSCacheTestSuite) TestForceExpiredByNames(c *C) { 144 names := []string{"test1.com", "test2.com"} 145 cache := NewDNSCache(0) 146 for i := 1; i < 4; i++ { 147 cache.Update( 148 now, 149 fmt.Sprintf("test%d.com", i), 150 []net.IP{net.ParseIP(fmt.Sprintf("1.1.1.%d", i))}, 151 5) 152 } 153 154 c.Assert(cache.forward, HasLen, 3) 155 result := cache.ForceExpireByNames(time.Now(), names) 156 c.Assert(result, checker.DeepEquals, names) 157 c.Assert(result, HasLen, 2) 158 c.Assert(cache.forward["test3.com"], Not(IsNil)) 159 160 invalidName := cache.ForceExpireByNames(now, []string{"invalid.name"}) 161 c.Assert(invalidName, HasLen, 0) 162 } 163 164 func (ds *DNSCacheTestSuite) TestReverseUpdateLookup(c *C) { 165 names := map[string]net.IP{ 166 "test1.com": net.ParseIP("2.2.2.1"), 167 "test2.com": net.ParseIP("2.2.2.2"), 168 "test3.com": net.ParseIP("2.2.2.3")} 169 sharedIP := net.ParseIP("1.1.1.1") 170 now := time.Now() 171 cache := NewDNSCache(0) 172 173 // insert 2 records, with 1 shared IP 174 cache.Update(now, "test1.com", []net.IP{sharedIP, names["test1.com"]}, 2) 175 cache.Update(now, "test2.com", []net.IP{sharedIP, names["test2.com"]}, 4) 176 177 // lookup within the TTL for both names should return 2 names for sharedIPs, 178 // and one name for the 2.2.2.* IPs 179 currentTime := now.Add(time.Second) 180 lookupNames := cache.lookupIPByTime(currentTime, sharedIP) 181 c.Assert(len(lookupNames), Equals, 2, Commentf("Incorrect number of names returned")) 182 for _, name := range lookupNames { 183 _, found := names[name] 184 c.Assert(found, Equals, true, Commentf("Returned a DNS name that doesn't match IP")) 185 } 186 187 lookupNames = cache.lookupIPByTime(currentTime, names["test1.com"]) 188 c.Assert(len(lookupNames), Equals, 1, Commentf("Incorrect number of names returned")) 189 c.Assert(lookupNames[0], Equals, "test1.com", Commentf("Returned a DNS name that doesn't match IP")) 190 191 lookupNames = cache.lookupIPByTime(currentTime, names["test2.com"]) 192 c.Assert(len(lookupNames), Equals, 1, Commentf("Incorrect number of names returned")) 193 c.Assert(lookupNames[0], Equals, "test2.com", Commentf("Returned a DNS name that doesn't match IP")) 194 195 lookupNames = cache.lookupIPByTime(currentTime, names["test3.com"]) 196 c.Assert(len(lookupNames), Equals, 0, Commentf("Returned names for IP not in cache")) 197 198 // lookup between 2-4 seconds later (test1.com has expired) for both names 199 // should return 2 names for sharedIPs, and one name for the 2.2.2.* IPs 200 currentTime = now.Add(3 * time.Second) 201 lookupNames = cache.lookupIPByTime(currentTime, sharedIP) 202 c.Assert(len(lookupNames), Equals, 1, Commentf("Incorrect number of names returned")) 203 c.Assert(lookupNames[0], Equals, "test2.com", Commentf("Returned a DNS name that doesn't match IP")) 204 205 lookupNames = cache.lookupIPByTime(currentTime, names["test1.com"]) 206 c.Assert(len(lookupNames), Equals, 0, Commentf("Incorrect number of names returned")) 207 208 lookupNames = cache.lookupIPByTime(currentTime, names["test2.com"]) 209 c.Assert(len(lookupNames), Equals, 1, Commentf("Incorrect number of names returned")) 210 c.Assert(lookupNames[0], Equals, "test2.com", Commentf("Returned a DNS name that doesn't match IP")) 211 212 lookupNames = cache.lookupIPByTime(currentTime, names["test3.com"]) 213 c.Assert(len(lookupNames), Equals, 0, Commentf("Returned names for IP not in cache")) 214 215 // lookup between after 4 seconds later (all have expired) for both names 216 // should return no names in all cases. 217 currentTime = now.Add(5 * time.Second) 218 lookupNames = cache.lookupIPByTime(currentTime, sharedIP) 219 c.Assert(len(lookupNames), Equals, 0, Commentf("Incorrect number of names returned")) 220 221 lookupNames = cache.lookupIPByTime(currentTime, names["test1.com"]) 222 c.Assert(len(lookupNames), Equals, 0, Commentf("Incorrect number of names returned")) 223 224 lookupNames = cache.lookupIPByTime(currentTime, names["test2.com"]) 225 c.Assert(len(lookupNames), Equals, 0, Commentf("Incorrect number of names returned")) 226 227 lookupNames = cache.lookupIPByTime(currentTime, names["test3.com"]) 228 c.Assert(len(lookupNames), Equals, 0, Commentf("Returned names for IP not in cache")) 229 } 230 231 func (ds *DNSCacheTestSuite) TestJSONMarshal(c *C) { 232 names := map[string]net.IP{ 233 "test1.com": net.ParseIP("2.2.2.1"), 234 "test2.com": net.ParseIP("2.2.2.2"), 235 "test3.com": net.ParseIP("2.2.2.3")} 236 sharedIP := net.ParseIP("1.1.1.1") 237 now := time.Now() 238 cache := NewDNSCache(0) 239 240 // insert 3 records with 1 shared IP and 3 with different IPs 241 cache.Update(now, "test1.com", []net.IP{sharedIP}, 5) 242 cache.Update(now, "test2.com", []net.IP{sharedIP}, 5) 243 cache.Update(now, "test3.com", []net.IP{sharedIP}, 5) 244 cache.Update(now, "test1.com", []net.IP{names["test1.com"]}, 5) 245 cache.Update(now, "test2.com", []net.IP{names["test2.com"]}, 5) 246 cache.Update(now, "test3.com", []net.IP{names["test3.com"]}, 5) 247 248 // Marshal and unmarshal 249 data, err := cache.MarshalJSON() 250 c.Assert(err, IsNil) 251 252 newCache := NewDNSCache(0) 253 err = newCache.UnmarshalJSON(data) 254 c.Assert(err, IsNil) 255 256 // Marshalled data should have no duplicate entries Note: this is tightly 257 // coupled with the implementation of DNSCache.MarshalJSON because the 258 // unmarshalled instance will hide duplicates. We simply check the length 259 // since we control the inserted data, and we test its correctness below. 260 rawList := make([]*cacheEntry, 0) 261 err = json.Unmarshal(data, &rawList) 262 c.Assert(err, IsNil) 263 c.Assert(len(rawList), Equals, 6) 264 265 // Check that the unmarshalled instance contains all the data at now 266 currentTime := now 267 for name := range names { 268 IPs := cache.lookupByTime(currentTime, name) 269 c.Assert(len(IPs), Equals, 2, Commentf("Incorrect number of IPs returned for %s", name)) 270 c.Assert(IPs[0].String(), Equals, sharedIP.String(), Commentf("Returned an IP that doesn't match %s", name)) 271 c.Assert(IPs[1].String(), Equals, names[name].String(), Commentf("Returned an IP name that doesn't match %s", name)) 272 } 273 274 // Check that the unmarshalled data expires correctly 275 currentTime = now.Add(10 * time.Second) 276 for name := range names { 277 IPs := cache.lookupByTime(currentTime, name) 278 c.Assert(len(IPs), Equals, 0, Commentf("Returned IPs that should be expired for %s", name)) 279 } 280 } 281 282 /* Benchmarks 283 * These are here to help gauge the relative costs of operations in DNSCache. 284 * Note: some are on arrays `size` elements, so the benchmark "op time" is too 285 * large. 286 */ 287 288 var ( 289 now = time.Now() 290 size = uint32(1000) // size of array to operate on 291 entriesOrig = makeEntries(now, 1+size/3, 1+size/3, 1+size/3) 292 ipsOrig = makeIPs(size) 293 ) 294 295 // makeIPs generates count sequential IPv4 IPs 296 func makeIPs(count uint32) []net.IP { 297 ips := make([]net.IP, 0, count) 298 for i := uint32(0); i < count; i++ { 299 ips = append(ips, net.IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i>>0))) 300 } 301 return ips 302 } 303 304 func makeEntries(now time.Time, live, redundant, expired uint32) (entries []*cacheEntry) { 305 liveTTL := 120 306 redundantTTL := 60 307 308 for ; live > 0; live-- { 309 ip := net.IPv4(byte(live>>24), byte(live>>16), byte(live>>8), byte(live>>0)) 310 311 entries = append(entries, &cacheEntry{ 312 Name: fmt.Sprintf("live-%s", ip.String()), 313 LookupTime: now, 314 ExpirationTime: now.Add(time.Duration(liveTTL) * time.Second), 315 TTL: liveTTL, 316 IPs: []net.IP{ip}}) 317 318 if redundant > 0 { 319 redundant-- 320 entries = append(entries, &cacheEntry{ 321 Name: fmt.Sprintf("redundant-%s", ip.String()), 322 LookupTime: now, 323 ExpirationTime: now.Add(time.Duration(redundantTTL) * time.Second), 324 TTL: redundantTTL, 325 IPs: []net.IP{ip}}) 326 } 327 328 if expired > 0 { 329 expired-- 330 entries = append(entries, &cacheEntry{ 331 Name: fmt.Sprintf("expired-%s", ip.String()), 332 LookupTime: now.Add(-time.Duration(liveTTL) * time.Second), 333 ExpirationTime: now.Add(-time.Second), 334 TTL: liveTTL, 335 IPs: []net.IP{ip}}) 336 } 337 } 338 339 rand.Shuffle(len(entries), func(i, j int) { 340 entries[i], entries[j] = entries[j], entries[i] 341 }) 342 343 return entries 344 } 345 346 // Note: each "op" works on size things 347 func (ds *DNSCacheTestSuite) BenchmarkGetIPs(c *C) { 348 c.StopTimer() 349 now := time.Now() 350 cache := NewDNSCache(0) 351 cache.Update(now, "test.com", []net.IP{net.ParseIP("1.2.3.4")}, 60) 352 entries := cache.forward["test.com"] 353 for _, entry := range entriesOrig { 354 cache.updateWithEntryIPs(entries, entry) 355 } 356 c.StartTimer() 357 358 for i := 0; i < c.N; i++ { 359 entries.getIPs(now) 360 } 361 } 362 363 // Note: each "op" works on size things 364 func (ds *DNSCacheTestSuite) BenchmarkUpdateIPs(c *C) { 365 for i := 0; i < c.N; i++ { 366 c.StopTimer() 367 now := time.Now() 368 cache := NewDNSCache(0) 369 cache.Update(now, "test.com", []net.IP{net.ParseIP("1.2.3.4")}, 60) 370 entries := cache.forward["test.com"] 371 c.StartTimer() 372 373 for _, entry := range entriesOrig { 374 cache.updateWithEntryIPs(entries, entry) 375 cache.removeExpired(entries, now, time.Time{}) 376 } 377 } 378 } 379 380 func (ds *DNSCacheTestSuite) BenchmarkIPString(c *C) { 381 for i := 0; i < c.N; i++ { 382 _ = net.IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i>>0)).String() 383 } 384 } 385 386 func (ds *DNSCacheTestSuite) BenchmarkParseIPSimple(c *C) { 387 ip := ipsOrig[0].String() 388 for i := 0; i < c.N; i++ { 389 _ = net.ParseIP(ip) 390 } 391 } 392 393 // Note: each "op" works on size things 394 func (ds *DNSCacheTestSuite) BenchmarkParseIP(c *C) { 395 c.StopTimer() 396 ips := make([]string, 0, len(ipsOrig)) 397 for _, ip := range ipsOrig { 398 ips = append(ips, ip.String()) 399 } 400 c.StartTimer() 401 402 for i := 0; i < c.N; i++ { 403 for _, ipStr := range ips { 404 _ = net.ParseIP(ipStr) 405 } 406 } 407 } 408 409 // JSON Marshal/Unmarshal benchmarks 410 var numIPsPerEntry = 10 // number of IPs to generate in each entry 411 412 func (ds *DNSCacheTestSuite) BenchmarkMarshalJSON10(c *C) { benchmarkMarshalJSON(c, 10) } 413 func (ds *DNSCacheTestSuite) BenchmarkMarshalJSON100(c *C) { benchmarkMarshalJSON(c, 100) } 414 func (ds *DNSCacheTestSuite) BenchmarkMarshalJSON1000(c *C) { benchmarkMarshalJSON(c, 1000) } 415 func (ds *DNSCacheTestSuite) BenchmarkMarshalJSON10000(c *C) { benchmarkMarshalJSON(c, 10000) } 416 417 func (ds *DNSCacheTestSuite) BenchmarkUnmarshalJSON10(c *C) { benchmarkUnmarshalJSON(c, 10) } 418 func (ds *DNSCacheTestSuite) BenchmarkUnmarshalJSON100(c *C) { benchmarkUnmarshalJSON(c, 100) } 419 func (ds *DNSCacheTestSuite) BenchmarkUnmarshalJSON1000(c *C) { benchmarkUnmarshalJSON(c, 1000) } 420 func (ds *DNSCacheTestSuite) BenchmarkUnmarshalJSON10000(c *C) { benchmarkUnmarshalJSON(c, 10000) } 421 422 // BenchmarkMarshalJSON100Repeat2 tests whether repeating the whole 423 // serialization is notably slower than a single run. 424 func (ds *DNSCacheTestSuite) BenchmarkMarshalJSON100Repeat2(c *C) { 425 benchmarkMarshalJSON(c, 50) 426 benchmarkMarshalJSON(c, 50) 427 } 428 429 func (ds *DNSCacheTestSuite) BenchmarkMarshalJSON1000Repeat2(c *C) { 430 benchmarkMarshalJSON(c, 500) 431 benchmarkMarshalJSON(c, 500) 432 } 433 434 // benchmarkMarshalJSON benchmarks the cost of creating a json representation 435 // of DNSCache. Each benchmark "op" is on numDNSEntries. 436 // Note: It assumes the JSON only uses data in DNSCache.forward when generating 437 // the data. Changes to the implementation need to also change this benchmark. 438 func benchmarkMarshalJSON(c *C, numDNSEntries int) { 439 c.StopTimer() 440 ips := makeIPs(uint32(numIPsPerEntry)) 441 442 cache := NewDNSCache(0) 443 for i := 0; i < numDNSEntries; i++ { 444 // TTL needs to be far enough in the future that the entry is serialized 445 cache.Update(time.Now(), fmt.Sprintf("domain-%v.com", i), ips, 86400) 446 } 447 c.StartTimer() 448 449 for i := 0; i < c.N; i++ { 450 _, err := cache.MarshalJSON() 451 c.Assert(err, IsNil) 452 } 453 } 454 455 // benchmarkUnmarshalJSON benchmarks the cost of parsing a json representation 456 // of DNSCache. Each benchmark "op" is on numDNSEntries. 457 // Note: It assumes the JSON only uses data in DNSCache.forward when generating 458 // the data. Changes to the implementation need to also change this benchmark. 459 func benchmarkUnmarshalJSON(c *C, numDNSEntries int) { 460 c.StopTimer() 461 ips := makeIPs(uint32(numIPsPerEntry)) 462 463 cache := NewDNSCache(0) 464 for i := 0; i < numDNSEntries; i++ { 465 // TTL needs to be far enough in the future that the entry is serialized 466 cache.Update(time.Now(), fmt.Sprintf("domain-%v.com", i), ips, 86400) 467 } 468 469 data, err := cache.MarshalJSON() 470 c.Assert(err, IsNil) 471 472 emptyCaches := make([]*DNSCache, c.N) 473 for i := 0; i < c.N; i++ { 474 emptyCaches[i] = NewDNSCache(0) 475 } 476 c.StartTimer() 477 478 for i := 0; i < c.N; i++ { 479 err := emptyCaches[i].UnmarshalJSON(data) 480 c.Assert(err, IsNil) 481 } 482 } 483 484 func (ds *DNSCacheTestSuite) TestTTLInsertWithMinValue(c *C) { 485 now := time.Now() 486 cache := NewDNSCache(60) 487 cache.Update(now, "test.com", []net.IP{net.ParseIP("1.2.3.4")}, 3) 488 489 // Checking just now to validate that is inserted correctly 490 res := cache.lookupByTime(now, "test.com") 491 c.Assert(res, HasLen, 1) 492 c.Assert(res[0].String(), Equals, "1.2.3.4") 493 494 // Checking the latest match 495 res = cache.lookupByTime(now.Add(time.Second*3), "test.com") 496 c.Assert(res, HasLen, 1) 497 c.Assert(res[0].String(), Equals, "1.2.3.4") 498 499 // Validate that in future time the value is correct 500 future := time.Now().Add(time.Second * 70) 501 res = cache.lookupByTime(future, "test.com") 502 c.Assert(res, HasLen, 0) 503 } 504 505 func (ds *DNSCacheTestSuite) TestTTLInsertWithZeroValue(c *C) { 506 now := time.Now() 507 cache := NewDNSCache(0) 508 cache.Update(now, "test.com", []net.IP{net.ParseIP("1.2.3.4")}, 10) 509 510 // Checking just now to validate that is inserted correctly 511 res := cache.lookupByTime(now, "test.com") 512 c.Assert(res, HasLen, 1) 513 c.Assert(res[0].String(), Equals, "1.2.3.4") 514 515 // Checking the latest match 516 res = cache.lookupByTime(now.Add(time.Second*10), "test.com") 517 c.Assert(res, HasLen, 1) 518 c.Assert(res[0].String(), Equals, "1.2.3.4") 519 520 // Checking that expires correctly 521 future := now.Add(time.Second * 11) 522 res = cache.lookupByTime(future, "test.com") 523 c.Assert(res, HasLen, 0) 524 } 525 526 func (ds *DNSCacheTestSuite) TestTTLCleanupEntries(c *C) { 527 cache := NewDNSCache(0) 528 cache.Update(now, "test.com", []net.IP{net.ParseIP("1.2.3.4")}, 3) 529 c.Assert(len(cache.cleanup), Equals, 1) 530 entries, _ := cache.cleanupExpiredEntries(time.Now().Add(5 * time.Second)) 531 c.Assert(entries, HasLen, 1) 532 c.Assert(cache.cleanup, HasLen, 0) 533 c.Assert(cache.Lookup("test.com"), HasLen, 0) 534 } 535 536 func (ds *DNSCacheTestSuite) TestTTLCleanupWithoutForward(c *C) { 537 cache := NewDNSCache(0) 538 now := time.Now() 539 cache.cleanup[now.Unix()] = []string{"test.com"} 540 // To make sure that all entries are validated correctly 541 cache.lastCleanup = time.Now().Add(-1 * time.Minute) 542 entries, _ := cache.cleanupExpiredEntries(time.Now().Add(5 * time.Second)) 543 c.Assert(entries, HasLen, 0) 544 c.Assert(cache.cleanup, HasLen, 0) 545 } 546 547 func (ds *DNSCacheTestSuite) TestOverlimitEntriesWithValidLimit(c *C) { 548 limit := 5 549 cache := NewDNSCacheWithLimit(0, limit) 550 551 cache.Update(now, "foo.bar", []net.IP{net.ParseIP("1.1.1.1")}, 1) 552 cache.Update(now, "bar.foo", []net.IP{net.ParseIP("2.1.1.1")}, 1) 553 for i := 1; i < limit+2; i++ { 554 cache.Update(now, "test.com", []net.IP{net.ParseIP(fmt.Sprintf("1.1.1.%d", i))}, i) 555 } 556 c.Assert(cache.cleanupOverLimitEntries(), checker.DeepEquals, []string{"test.com"}) 557 c.Assert(cache.Lookup("test.com"), HasLen, limit) 558 c.Assert(cache.LookupIP(net.ParseIP("1.1.1.1")), checker.DeepEquals, []string{"foo.bar"}) 559 c.Assert(cache.forward["test.com"]["1.1.1.1"], IsNil) 560 c.Assert(cache.Lookup("foo.bar"), HasLen, 1) 561 c.Assert(cache.Lookup("bar.foo"), HasLen, 1) 562 c.Assert(cache.overLimit, HasLen, 0) 563 } 564 565 func (ds *DNSCacheTestSuite) TestOverlimitEntriesWithoutLimit(c *C) { 566 limit := 0 567 cache := NewDNSCacheWithLimit(0, limit) 568 for i := 0; i < 5; i++ { 569 cache.Update(now, "test.com", []net.IP{net.ParseIP(fmt.Sprintf("1.1.1.%d", i))}, i) 570 } 571 c.Assert(cache.cleanupOverLimitEntries(), checker.DeepEquals, []string{}) 572 c.Assert(cache.Lookup("test.com"), HasLen, 4) 573 } 574 575 func (ds *DNSCacheTestSuite) TestGCOverlimitAfterTTLCleanup(c *C) { 576 limit := 5 577 cache := NewDNSCacheWithLimit(0, limit) 578 579 // Make sure that the cleanup takes all the changes from 1 minute ago. 580 cache.lastCleanup = time.Now().Add(-1 * time.Minute) 581 for i := 1; i < limit+2; i++ { 582 cache.Update(now, "test.com", []net.IP{net.ParseIP(fmt.Sprintf("1.1.1.%d", i))}, 1) 583 } 584 585 c.Assert(cache.Lookup("test.com"), HasLen, limit+1) 586 c.Assert(cache.overLimit, HasLen, 1) 587 588 result, _ := cache.cleanupExpiredEntries(time.Now().Add(5 * time.Second)) 589 c.Assert(result, checker.DeepEquals, []string{"test.com"}) 590 591 // Due all entries are deleted on TTL, the overlimit should return 0 entries. 592 c.Assert(cache.cleanupOverLimitEntries(), checker.DeepEquals, []string{}) 593 } 594 595 func (ds *DNSCacheTestSuite) TestOverlimitAfterDeleteForwardEntry(c *C) { 596 // Validate if something delete the forward entry no invalid key access on 597 // CG operation 598 dnsCache := NewDNSCache(0) 599 dnsCache.overLimit["test.com"] = true 600 c.Assert(dnsCache.cleanupOverLimitEntries(), checker.DeepEquals, []string{}) 601 }