]>
Commit | Line | Data |
---|---|---|
903853f4 | 1 | #!/usr/bin/env python |
1ea747c0 | 2 | import base64 |
903853f4 RG |
3 | import time |
4 | import dns | |
5 | from dnsdisttests import DNSDistTest | |
6 | ||
7 | class TestCaching(DNSDistTest): | |
8 | ||
9 | _config_template = """ | |
fe1c60f2 | 10 | pc = newPacketCache(100, 86400, 1) |
903853f4 RG |
11 | getPool(""):setCache(pc) |
12 | addAction(makeRule("nocache.cache.tests.powerdns.com."), SkipCacheAction()) | |
816dff3d RG |
13 | function skipViaLua(dq) |
14 | dq.skipCache = true | |
15 | return DNSAction.None, "" | |
16 | end | |
a2ff35e3 | 17 | addAction("nocachevialua.cache.tests.powerdns.com.", LuaAction(skipViaLua)) |
903853f4 RG |
18 | newServer{address="127.0.0.1:%s"} |
19 | """ | |
fe1c60f2 | 20 | |
903853f4 RG |
21 | def testCached(self): |
22 | """ | |
23 | Cache: Served from cache | |
24 | ||
25 | dnsdist is configured to cache entries, we are sending several | |
26 | identical requests and checking that the backend only receive | |
27 | the first one. | |
28 | """ | |
29 | numberOfQueries = 10 | |
30 | name = 'cached.cache.tests.powerdns.com.' | |
31 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
32 | response = dns.message.make_response(query) | |
33 | rrset = dns.rrset.from_text(name, | |
34 | 3600, | |
35 | dns.rdataclass.IN, | |
36 | dns.rdatatype.AAAA, | |
37 | '::1') | |
38 | response.answer.append(rrset) | |
39 | ||
40 | # first query to fill the cache | |
41 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
42 | self.assertTrue(receivedQuery) | |
43 | self.assertTrue(receivedResponse) | |
44 | receivedQuery.id = query.id | |
45 | self.assertEquals(query, receivedQuery) | |
46 | self.assertEquals(receivedResponse, response) | |
47 | ||
48 | for _ in range(numberOfQueries): | |
49 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
50 | self.assertEquals(receivedResponse, response) | |
51 | ||
52 | total = 0 | |
02bbf9eb RG |
53 | for key in self._responsesCounter: |
54 | total += self._responsesCounter[key] | |
903853f4 RG |
55 | TestCaching._responsesCounter[key] = 0 |
56 | ||
57 | self.assertEquals(total, 1) | |
58 | ||
59 | # TCP should not be cached | |
60 | # first query to fill the cache | |
61 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
62 | self.assertTrue(receivedQuery) | |
63 | self.assertTrue(receivedResponse) | |
64 | receivedQuery.id = query.id | |
65 | self.assertEquals(query, receivedQuery) | |
66 | self.assertEquals(receivedResponse, response) | |
67 | ||
68 | for _ in range(numberOfQueries): | |
69 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
70 | self.assertEquals(receivedResponse, response) | |
71 | ||
72 | total = 0 | |
02bbf9eb RG |
73 | for key in self._responsesCounter: |
74 | total += self._responsesCounter[key] | |
903853f4 RG |
75 | TestCaching._responsesCounter[key] = 0 |
76 | ||
77 | self.assertEquals(total, 1) | |
78 | ||
79 | def testSkipCache(self): | |
80 | """ | |
81 | Cache: SkipCacheAction | |
82 | ||
83 | dnsdist is configured to not cache entries for nocache.cache.tests.powerdns.com. | |
84 | we are sending several requests and checking that the backend get them all. | |
85 | """ | |
86 | name = 'nocache.cache.tests.powerdns.com.' | |
87 | numberOfQueries = 10 | |
88 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
89 | response = dns.message.make_response(query) | |
816dff3d RG |
90 | rrset = dns.rrset.from_text(name, |
91 | 3600, | |
92 | dns.rdataclass.IN, | |
93 | dns.rdatatype.AAAA, | |
94 | '::1') | |
95 | response.answer.append(rrset) | |
96 | ||
97 | for _ in range(numberOfQueries): | |
98 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
99 | self.assertTrue(receivedQuery) | |
100 | self.assertTrue(receivedResponse) | |
101 | receivedQuery.id = query.id | |
102 | self.assertEquals(query, receivedQuery) | |
103 | self.assertEquals(receivedResponse, response) | |
104 | ||
105 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
106 | self.assertTrue(receivedQuery) | |
107 | self.assertTrue(receivedResponse) | |
108 | receivedQuery.id = query.id | |
109 | self.assertEquals(query, receivedQuery) | |
110 | self.assertEquals(receivedResponse, response) | |
111 | ||
02bbf9eb RG |
112 | for key in self._responsesCounter: |
113 | value = self._responsesCounter[key] | |
816dff3d RG |
114 | self.assertEquals(value, numberOfQueries) |
115 | ||
116 | def testSkipCacheViaLua(self): | |
117 | """ | |
118 | Cache: SkipCache via Lua | |
119 | ||
120 | dnsdist is configured to not cache entries for nocachevialua.cache.tests.powerdns.com. | |
121 | we are sending several requests and checking that the backend get them all. | |
122 | """ | |
123 | name = 'nocachevialua.cache.tests.powerdns.com.' | |
124 | numberOfQueries = 10 | |
125 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
126 | response = dns.message.make_response(query) | |
903853f4 RG |
127 | rrset = dns.rrset.from_text(name, |
128 | 3600, | |
129 | dns.rdataclass.IN, | |
130 | dns.rdatatype.AAAA, | |
131 | '::1') | |
132 | response.answer.append(rrset) | |
133 | ||
134 | for _ in range(numberOfQueries): | |
135 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
136 | self.assertTrue(receivedQuery) | |
137 | self.assertTrue(receivedResponse) | |
138 | receivedQuery.id = query.id | |
139 | self.assertEquals(query, receivedQuery) | |
140 | self.assertEquals(receivedResponse, response) | |
141 | ||
142 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
143 | self.assertTrue(receivedQuery) | |
144 | self.assertTrue(receivedResponse) | |
145 | receivedQuery.id = query.id | |
146 | self.assertEquals(query, receivedQuery) | |
147 | self.assertEquals(receivedResponse, response) | |
148 | ||
02bbf9eb RG |
149 | for key in self._responsesCounter: |
150 | value = self._responsesCounter[key] | |
903853f4 RG |
151 | self.assertEquals(value, numberOfQueries) |
152 | ||
153 | def testCacheExpiration(self): | |
154 | """ | |
155 | Cache: Cache expiration | |
156 | ||
157 | dnsdist is configured to cache entries, we are sending one request | |
158 | (cache miss) with a very short TTL, checking that the next requests | |
159 | are cached. Then we wait for the TTL to expire, check that the | |
160 | next request is a miss but the following one a hit. | |
161 | """ | |
162 | ttl = 2 | |
163 | misses = 0 | |
164 | name = 'cacheexpiration.cache.tests.powerdns.com.' | |
165 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
166 | response = dns.message.make_response(query) | |
167 | rrset = dns.rrset.from_text(name, | |
168 | ttl, | |
169 | dns.rdataclass.IN, | |
170 | dns.rdatatype.AAAA, | |
171 | '::1') | |
172 | response.answer.append(rrset) | |
173 | ||
174 | # first query to fill the cache | |
175 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
176 | self.assertTrue(receivedQuery) | |
177 | self.assertTrue(receivedResponse) | |
178 | receivedQuery.id = query.id | |
179 | self.assertEquals(query, receivedQuery) | |
180 | self.assertEquals(receivedResponse, response) | |
181 | misses += 1 | |
182 | ||
183 | # next queries should hit the cache | |
184 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
185 | self.assertEquals(receivedResponse, response) | |
186 | ||
187 | # now we wait a bit for the cache entry to expire | |
188 | time.sleep(ttl + 1) | |
189 | ||
190 | # next query should be a miss, fill the cache again | |
191 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
192 | self.assertTrue(receivedQuery) | |
193 | self.assertTrue(receivedResponse) | |
194 | receivedQuery.id = query.id | |
195 | self.assertEquals(query, receivedQuery) | |
196 | self.assertEquals(receivedResponse, response) | |
197 | misses += 1 | |
198 | ||
199 | # following queries should hit the cache again | |
200 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
201 | self.assertEquals(receivedResponse, response) | |
202 | ||
203 | total = 0 | |
02bbf9eb RG |
204 | for key in self._responsesCounter: |
205 | total += self._responsesCounter[key] | |
903853f4 RG |
206 | |
207 | self.assertEquals(total, misses) | |
208 | ||
209 | def testCacheExpirationDifferentSets(self): | |
210 | """ | |
211 | Cache: Cache expiration with different sets | |
212 | ||
213 | dnsdist is configured to cache entries, we are sending one request | |
214 | (cache miss) whose response has a long and a very short TTL, | |
215 | checking that the next requests are cached. Then we wait for the | |
216 | short TTL to expire, check that the | |
217 | next request is a miss but the following one a hit. | |
218 | """ | |
219 | ttl = 2 | |
220 | misses = 0 | |
221 | name = 'cacheexpirationdifferentsets.cache.tests.powerdns.com.' | |
222 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
223 | response = dns.message.make_response(query) | |
224 | rrset = dns.rrset.from_text(name, | |
225 | ttl, | |
226 | dns.rdataclass.IN, | |
227 | dns.rdatatype.CNAME, | |
228 | 'cname.cacheexpirationdifferentsets.cache.tests.powerdns.com.') | |
229 | response.answer.append(rrset) | |
230 | rrset = dns.rrset.from_text('cname.cacheexpirationdifferentsets.cache.tests.powerdns.com.', | |
231 | ttl + 3600, | |
232 | dns.rdataclass.IN, | |
233 | dns.rdatatype.A, | |
234 | '192.2.0.1') | |
235 | response.additional.append(rrset) | |
236 | ||
237 | # first query to fill the cache | |
238 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
239 | self.assertTrue(receivedQuery) | |
240 | self.assertTrue(receivedResponse) | |
241 | receivedQuery.id = query.id | |
242 | self.assertEquals(query, receivedQuery) | |
243 | self.assertEquals(receivedResponse, response) | |
244 | misses += 1 | |
245 | ||
246 | # next queries should hit the cache | |
247 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
248 | self.assertEquals(receivedResponse, response) | |
249 | ||
250 | # now we wait a bit for the cache entry to expire | |
251 | time.sleep(ttl + 1) | |
252 | ||
253 | # next query should be a miss, fill the cache again | |
254 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
255 | self.assertTrue(receivedQuery) | |
256 | self.assertTrue(receivedResponse) | |
257 | receivedQuery.id = query.id | |
258 | self.assertEquals(query, receivedQuery) | |
259 | self.assertEquals(receivedResponse, response) | |
260 | misses += 1 | |
261 | ||
262 | # following queries should hit the cache again | |
263 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
264 | self.assertEquals(receivedResponse, response) | |
265 | ||
266 | total = 0 | |
02bbf9eb RG |
267 | for key in self._responsesCounter: |
268 | total += self._responsesCounter[key] | |
903853f4 RG |
269 | |
270 | self.assertEquals(total, misses) | |
271 | ||
272 | def testCacheDecreaseTTL(self): | |
273 | """ | |
274 | Cache: Cache decreases TTL | |
275 | ||
276 | dnsdist is configured to cache entries, we are sending one request | |
277 | (cache miss) and verify that the cache hits have a decreasing TTL. | |
278 | """ | |
279 | ttl = 600 | |
280 | misses = 0 | |
281 | name = 'cachedecreasettl.cache.tests.powerdns.com.' | |
282 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
283 | response = dns.message.make_response(query) | |
284 | rrset = dns.rrset.from_text(name, | |
285 | ttl, | |
286 | dns.rdataclass.IN, | |
287 | dns.rdatatype.AAAA, | |
288 | '::1') | |
289 | response.answer.append(rrset) | |
290 | ||
291 | # first query to fill the cache | |
292 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
293 | self.assertTrue(receivedQuery) | |
294 | self.assertTrue(receivedResponse) | |
295 | receivedQuery.id = query.id | |
296 | self.assertEquals(query, receivedQuery) | |
297 | self.assertEquals(receivedResponse, response) | |
298 | misses += 1 | |
299 | ||
300 | # next queries should hit the cache | |
301 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
302 | self.assertEquals(receivedResponse, response) | |
303 | for an in receivedResponse.answer: | |
304 | self.assertTrue(an.ttl <= ttl) | |
305 | ||
306 | # now we wait a bit for the TTL to decrease | |
307 | time.sleep(1) | |
308 | ||
309 | # next queries should hit the cache | |
310 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
311 | self.assertEquals(receivedResponse, response) | |
312 | for an in receivedResponse.answer: | |
313 | self.assertTrue(an.ttl < ttl) | |
314 | ||
315 | total = 0 | |
02bbf9eb RG |
316 | for key in self._responsesCounter: |
317 | total += self._responsesCounter[key] | |
903853f4 RG |
318 | |
319 | self.assertEquals(total, misses) | |
320 | ||
321 | def testCacheDifferentCase(self): | |
322 | """ | |
323 | Cache: Cache matches different case | |
324 | ||
325 | dnsdist is configured to cache entries, we are sending one request | |
326 | (cache miss) and verify that the same one with a different case | |
327 | matches. | |
328 | """ | |
329 | ttl = 600 | |
330 | name = 'cachedifferentcase.cache.tests.powerdns.com.' | |
331 | differentCaseName = 'CacheDifferentCASE.cache.tests.powerdns.com.' | |
332 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
333 | differentCaseQuery = dns.message.make_query(differentCaseName, 'AAAA', 'IN') | |
334 | response = dns.message.make_response(query) | |
335 | differentCaseResponse = dns.message.make_response(differentCaseQuery) | |
336 | rrset = dns.rrset.from_text(name, | |
337 | ttl, | |
338 | dns.rdataclass.IN, | |
339 | dns.rdatatype.AAAA, | |
340 | '::1') | |
341 | response.answer.append(rrset) | |
342 | differentCaseResponse.answer.append(rrset) | |
343 | ||
344 | # first query to fill the cache | |
345 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
346 | self.assertTrue(receivedQuery) | |
347 | self.assertTrue(receivedResponse) | |
348 | receivedQuery.id = query.id | |
349 | self.assertEquals(query, receivedQuery) | |
350 | self.assertEquals(receivedResponse, response) | |
351 | ||
352 | # different case query should still hit the cache | |
353 | (_, receivedResponse) = self.sendUDPQuery(differentCaseQuery, response=None, useQueue=False) | |
354 | self.assertEquals(receivedResponse, differentCaseResponse) | |
355 | ||
356 | ||
a2c4a339 CH |
357 | class TestTempFailureCacheTTLAction(DNSDistTest): |
358 | ||
359 | _config_template = """ | |
360 | pc = newPacketCache(100, 86400, 1) | |
361 | getPool(""):setCache(pc) | |
362 | addAction("servfail.cache.tests.powerdns.com.", TempFailureCacheTTLAction(1)) | |
363 | newServer{address="127.0.0.1:%s"} | |
364 | """ | |
365 | ||
366 | def testTempFailureCacheTTLAction(self): | |
367 | """ | |
368 | Cache: When a TempFailure TTL is set, it should be honored | |
369 | ||
370 | dnsdist is configured to cache packets, plus a specific qname is | |
371 | set up with a lower TempFailure Cache TTL. we are sending one request | |
372 | (cache miss) and verify that the cache is hit for the following query, | |
373 | but the TTL then expires before the larger "good" packetcache TTL. | |
374 | """ | |
375 | name = 'servfail.cache.tests.powerdns.com.' | |
376 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
377 | response = dns.message.make_response(query) | |
378 | response.set_rcode(dns.rcode.SERVFAIL) | |
379 | ||
380 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
381 | self.assertTrue(receivedQuery) | |
382 | self.assertTrue(receivedResponse) | |
383 | receivedQuery.id = query.id | |
384 | self.assertEquals(query, receivedQuery) | |
385 | self.assertEquals(receivedResponse, response) | |
386 | ||
387 | # next query should hit the cache | |
45fc7a50 | 388 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) |
a2c4a339 CH |
389 | self.assertFalse(receivedQuery) |
390 | self.assertTrue(receivedResponse) | |
391 | self.assertEquals(receivedResponse, response) | |
392 | ||
393 | # now we wait a bit for the Failure-Cache TTL to expire | |
394 | time.sleep(2) | |
395 | ||
396 | # next query should NOT hit the cache | |
397 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
398 | self.assertTrue(receivedQuery) | |
399 | self.assertTrue(receivedResponse) | |
400 | self.assertEquals(receivedResponse, response) | |
401 | ||
402 | ||
903853f4 RG |
403 | class TestCachingWithExistingEDNS(DNSDistTest): |
404 | ||
405 | _config_template = """ | |
406 | pc = newPacketCache(5, 86400, 1) | |
407 | getPool(""):setCache(pc) | |
408 | newServer{address="127.0.0.1:%s"} | |
409 | """ | |
410 | def testCacheWithEDNS(self): | |
411 | """ | |
412 | Cache: Cache should not match different EDNS value | |
413 | ||
414 | dnsdist is configured to cache entries, we are sending one request | |
415 | (cache miss) and verify that the same one with a different EDNS UDP | |
416 | Payload size is not served from the cache. | |
417 | """ | |
418 | misses = 0 | |
419 | name = 'cachedifferentedns.cache.tests.powerdns.com.' | |
420 | query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512) | |
421 | response = dns.message.make_response(query) | |
422 | rrset = dns.rrset.from_text(name, | |
423 | 3600, | |
424 | dns.rdataclass.IN, | |
425 | dns.rdatatype.A, | |
426 | '127.0.0.1') | |
427 | response.answer.append(rrset) | |
428 | ||
429 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
430 | self.assertTrue(receivedQuery) | |
431 | self.assertTrue(receivedResponse) | |
432 | receivedQuery.id = query.id | |
433 | self.assertEquals(query, receivedQuery) | |
434 | self.assertEquals(response, receivedResponse) | |
435 | misses += 1 | |
436 | ||
437 | query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
438 | response = dns.message.make_response(query) | |
439 | rrset = dns.rrset.from_text(name, | |
440 | 3600, | |
441 | dns.rdataclass.IN, | |
442 | dns.rdatatype.A, | |
443 | '127.0.0.1') | |
444 | response.answer.append(rrset) | |
445 | ||
446 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
447 | self.assertTrue(receivedQuery) | |
448 | self.assertTrue(receivedResponse) | |
449 | receivedQuery.id = query.id | |
450 | self.assertEquals(query, receivedQuery) | |
451 | self.assertEquals(response, receivedResponse) | |
452 | misses += 1 | |
453 | ||
454 | total = 0 | |
02bbf9eb RG |
455 | for key in self._responsesCounter: |
456 | total += self._responsesCounter[key] | |
903853f4 RG |
457 | |
458 | self.assertEquals(total, misses) | |
fe1c60f2 RG |
459 | |
460 | class TestCachingCacheFull(DNSDistTest): | |
461 | ||
462 | _config_template = """ | |
463 | pc = newPacketCache(1, 86400, 1) | |
464 | getPool(""):setCache(pc) | |
465 | newServer{address="127.0.0.1:%s"} | |
466 | """ | |
467 | def testCacheFull(self): | |
468 | """ | |
469 | Cache: No new entries are cached when the cache is full | |
470 | ||
471 | """ | |
472 | misses = 0 | |
473 | name = 'cachenotfullyet.cache.tests.powerdns.com.' | |
474 | query = dns.message.make_query(name, 'A', 'IN') | |
475 | response = dns.message.make_response(query) | |
476 | rrset = dns.rrset.from_text(name, | |
477 | 3600, | |
478 | dns.rdataclass.IN, | |
479 | dns.rdatatype.A, | |
480 | '127.0.0.1') | |
481 | response.answer.append(rrset) | |
482 | ||
483 | # Miss | |
484 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
485 | self.assertTrue(receivedQuery) | |
486 | self.assertTrue(receivedResponse) | |
487 | receivedQuery.id = query.id | |
488 | self.assertEquals(query, receivedQuery) | |
489 | self.assertEquals(response, receivedResponse) | |
490 | misses += 1 | |
491 | ||
492 | # next queries should hit the cache | |
493 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
494 | self.assertEquals(receivedResponse, response) | |
495 | ||
496 | # ok, now the cache is full, send another query | |
497 | name = 'cachefull.cache.tests.powerdns.com.' | |
498 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
499 | response = dns.message.make_response(query) | |
500 | rrset = dns.rrset.from_text(name, | |
501 | 3600, | |
502 | dns.rdataclass.IN, | |
503 | dns.rdatatype.AAAA, | |
504 | '::1') | |
505 | response.answer.append(rrset) | |
506 | ||
507 | # Miss | |
508 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
509 | self.assertTrue(receivedQuery) | |
510 | self.assertTrue(receivedResponse) | |
511 | receivedQuery.id = query.id | |
512 | self.assertEquals(query, receivedQuery) | |
513 | self.assertEquals(response, receivedResponse) | |
514 | misses += 1 | |
515 | ||
516 | # next queries should NOT hit the cache | |
517 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
518 | self.assertTrue(receivedQuery) | |
519 | self.assertTrue(receivedResponse) | |
520 | receivedQuery.id = query.id | |
521 | self.assertEquals(query, receivedQuery) | |
522 | self.assertEquals(response, receivedResponse) | |
523 | misses += 1 | |
524 | ||
525 | total = 0 | |
02bbf9eb RG |
526 | for key in self._responsesCounter: |
527 | total += self._responsesCounter[key] | |
fe1c60f2 RG |
528 | |
529 | self.assertEquals(total, misses) | |
1ea747c0 RG |
530 | |
531 | class TestCachingNoStale(DNSDistTest): | |
532 | ||
533 | _consoleKey = DNSDistTest.generateConsoleKey() | |
b4f23783 | 534 | _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii') |
1ea747c0 RG |
535 | _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort'] |
536 | _config_template = """ | |
537 | pc = newPacketCache(100, 86400, 1) | |
538 | getPool(""):setCache(pc) | |
539 | setKey("%s") | |
540 | controlSocket("127.0.0.1:%s") | |
541 | newServer{address="127.0.0.1:%s"} | |
542 | """ | |
543 | def testCacheNoStale(self): | |
544 | """ | |
545 | Cache: Cache entry, set backend down, we should not get a stale entry | |
546 | ||
547 | """ | |
548 | ttl = 1 | |
549 | name = 'nostale.cache.tests.powerdns.com.' | |
550 | query = dns.message.make_query(name, 'A', 'IN') | |
551 | response = dns.message.make_response(query) | |
552 | rrset = dns.rrset.from_text(name, | |
553 | 1, | |
554 | dns.rdataclass.IN, | |
555 | dns.rdatatype.A, | |
556 | '127.0.0.1') | |
557 | response.answer.append(rrset) | |
558 | ||
559 | # Miss | |
560 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
561 | self.assertTrue(receivedQuery) | |
562 | self.assertTrue(receivedResponse) | |
563 | receivedQuery.id = query.id | |
564 | self.assertEquals(query, receivedQuery) | |
565 | self.assertEquals(response, receivedResponse) | |
566 | ||
567 | # next queries should hit the cache | |
568 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
569 | self.assertEquals(receivedResponse, response) | |
570 | ||
571 | # ok, we mark the backend as down | |
572 | self.sendConsoleCommand("getServer(0):setDown()") | |
573 | # and we wait for the entry to expire | |
574 | time.sleep(ttl + 1) | |
575 | ||
576 | # we should NOT get a cached, stale, entry | |
577 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
578 | self.assertEquals(receivedResponse, None) | |
579 | ||
580 | ||
581 | class TestCachingStale(DNSDistTest): | |
582 | ||
583 | _consoleKey = DNSDistTest.generateConsoleKey() | |
b4f23783 | 584 | _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii') |
1ea747c0 RG |
585 | _staleCacheTTL = 60 |
586 | _config_params = ['_staleCacheTTL', '_consoleKeyB64', '_consolePort', '_testServerPort'] | |
587 | _config_template = """ | |
588 | pc = newPacketCache(100, 86400, 1, %s) | |
589 | getPool(""):setCache(pc) | |
590 | setStaleCacheEntriesTTL(600) | |
591 | setKey("%s") | |
592 | controlSocket("127.0.0.1:%s") | |
593 | newServer{address="127.0.0.1:%s"} | |
594 | """ | |
595 | def testCacheStale(self): | |
596 | """ | |
597 | Cache: Cache entry, set backend down, get stale entry | |
598 | ||
599 | """ | |
600 | misses = 0 | |
601 | ttl = 1 | |
602 | name = 'stale.cache.tests.powerdns.com.' | |
603 | query = dns.message.make_query(name, 'A', 'IN') | |
604 | response = dns.message.make_response(query) | |
605 | rrset = dns.rrset.from_text(name, | |
606 | ttl, | |
607 | dns.rdataclass.IN, | |
608 | dns.rdatatype.A, | |
609 | '127.0.0.1') | |
610 | response.answer.append(rrset) | |
611 | ||
612 | # Miss | |
613 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
614 | self.assertTrue(receivedQuery) | |
615 | self.assertTrue(receivedResponse) | |
616 | receivedQuery.id = query.id | |
617 | self.assertEquals(query, receivedQuery) | |
618 | self.assertEquals(response, receivedResponse) | |
619 | misses += 1 | |
620 | ||
621 | # next queries should hit the cache | |
622 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
623 | self.assertEquals(receivedResponse, response) | |
624 | ||
625 | # ok, we mark the backend as down | |
626 | self.sendConsoleCommand("getServer(0):setDown()") | |
627 | # and we wait for the entry to expire | |
628 | time.sleep(ttl + 1) | |
629 | ||
630 | # we should get a cached, stale, entry | |
631 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
632 | self.assertEquals(receivedResponse, response) | |
633 | for an in receivedResponse.answer: | |
634 | self.assertEquals(an.ttl, self._staleCacheTTL) | |
635 | ||
636 | total = 0 | |
02bbf9eb RG |
637 | for key in self._responsesCounter: |
638 | total += self._responsesCounter[key] | |
1ea747c0 RG |
639 | |
640 | self.assertEquals(total, misses) | |
641 | ||
642 | class TestCacheManagement(DNSDistTest): | |
643 | ||
644 | _consoleKey = DNSDistTest.generateConsoleKey() | |
b4f23783 | 645 | _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii') |
1ea747c0 RG |
646 | _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort'] |
647 | _config_template = """ | |
648 | pc = newPacketCache(100, 86400, 1) | |
649 | getPool(""):setCache(pc) | |
650 | setKey("%s") | |
651 | controlSocket("127.0.0.1:%s") | |
652 | newServer{address="127.0.0.1:%s"} | |
653 | """ | |
654 | def testCacheExpunge(self): | |
655 | """ | |
656 | Cache: Expunge | |
657 | ||
658 | """ | |
659 | misses = 0 | |
660 | ttl = 600 | |
661 | name = 'expunge.cache.tests.powerdns.com.' | |
662 | query = dns.message.make_query(name, 'A', 'IN') | |
663 | response = dns.message.make_response(query) | |
664 | rrset = dns.rrset.from_text(name, | |
665 | ttl, | |
666 | dns.rdataclass.IN, | |
667 | dns.rdatatype.A, | |
668 | '127.0.0.1') | |
669 | response.answer.append(rrset) | |
670 | ||
671 | # Miss | |
672 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
673 | self.assertTrue(receivedQuery) | |
674 | self.assertTrue(receivedResponse) | |
675 | receivedQuery.id = query.id | |
676 | self.assertEquals(query, receivedQuery) | |
677 | self.assertEquals(response, receivedResponse) | |
678 | misses += 1 | |
679 | ||
680 | # next queries should hit the cache | |
681 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
682 | self.assertEquals(receivedResponse, response) | |
683 | ||
684 | # remove cached entries | |
685 | self.sendConsoleCommand("getPool(\"\"):getCache():expunge(0)") | |
686 | ||
687 | # Miss | |
688 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
689 | self.assertTrue(receivedQuery) | |
690 | self.assertTrue(receivedResponse) | |
691 | receivedQuery.id = query.id | |
692 | self.assertEquals(query, receivedQuery) | |
693 | self.assertEquals(response, receivedResponse) | |
694 | misses += 1 | |
695 | ||
696 | # next queries should hit the cache again | |
697 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
698 | self.assertEquals(receivedResponse, response) | |
699 | ||
700 | total = 0 | |
02bbf9eb RG |
701 | for key in self._responsesCounter: |
702 | total += self._responsesCounter[key] | |
1ea747c0 RG |
703 | |
704 | self.assertEquals(total, misses) | |
705 | ||
706 | def testCacheExpungeByName(self): | |
707 | """ | |
708 | Cache: Expunge by name | |
709 | ||
710 | """ | |
711 | misses = 0 | |
712 | ttl = 600 | |
713 | name = 'expungebyname.cache.tests.powerdns.com.' | |
714 | query = dns.message.make_query(name, 'A', 'IN') | |
715 | response = dns.message.make_response(query) | |
716 | rrset = dns.rrset.from_text(name, | |
717 | ttl, | |
718 | dns.rdataclass.IN, | |
719 | dns.rdatatype.A, | |
720 | '127.0.0.1') | |
721 | response.answer.append(rrset) | |
722 | ||
723 | name2 = 'expungebynameother.cache.tests.powerdns.com.' | |
724 | query2 = dns.message.make_query(name2, 'A', 'IN') | |
725 | response2 = dns.message.make_response(query2) | |
726 | rrset2 = dns.rrset.from_text(name2, | |
727 | ttl, | |
728 | dns.rdataclass.IN, | |
729 | dns.rdatatype.A, | |
730 | '127.0.0.1') | |
731 | response2.answer.append(rrset2) | |
732 | ||
733 | # Miss | |
734 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
735 | self.assertTrue(receivedQuery) | |
736 | self.assertTrue(receivedResponse) | |
737 | receivedQuery.id = query.id | |
738 | self.assertEquals(query, receivedQuery) | |
739 | self.assertEquals(response, receivedResponse) | |
740 | misses += 1 | |
741 | ||
742 | # next queries should hit the cache | |
743 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
744 | self.assertEquals(receivedResponse, response) | |
745 | ||
746 | # cache another entry | |
747 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2) | |
748 | self.assertTrue(receivedQuery) | |
749 | self.assertTrue(receivedResponse) | |
750 | receivedQuery.id = query2.id | |
751 | self.assertEquals(query2, receivedQuery) | |
752 | self.assertEquals(response2, receivedResponse) | |
753 | misses += 1 | |
754 | ||
755 | # queries for name and name 2 should hit the cache | |
756 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
757 | self.assertEquals(receivedResponse, response) | |
758 | ||
759 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
760 | self.assertEquals(receivedResponse, response2) | |
761 | ||
762 | # remove cached entries from name | |
763 | self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"" + name + "\"))") | |
764 | ||
765 | # Miss for name | |
766 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
767 | self.assertTrue(receivedQuery) | |
768 | self.assertTrue(receivedResponse) | |
769 | receivedQuery.id = query.id | |
770 | self.assertEquals(query, receivedQuery) | |
771 | self.assertEquals(response, receivedResponse) | |
772 | misses += 1 | |
773 | ||
774 | # next queries for name should hit the cache again | |
775 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
776 | self.assertEquals(receivedResponse, response) | |
777 | ||
778 | # queries for name2 should still hit the cache | |
779 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
780 | self.assertEquals(receivedResponse, response2) | |
781 | ||
782 | total = 0 | |
02bbf9eb RG |
783 | for key in self._responsesCounter: |
784 | total += self._responsesCounter[key] | |
1ea747c0 RG |
785 | |
786 | self.assertEquals(total, misses) | |
787 | ||
788 | def testCacheExpungeByNameAndType(self): | |
789 | """ | |
790 | Cache: Expunge by name and type | |
791 | ||
792 | """ | |
793 | misses = 0 | |
794 | ttl = 600 | |
795 | name = 'expungebynameandtype.cache.tests.powerdns.com.' | |
796 | query = dns.message.make_query(name, 'A', 'IN') | |
797 | response = dns.message.make_response(query) | |
798 | rrset = dns.rrset.from_text(name, | |
799 | ttl, | |
800 | dns.rdataclass.IN, | |
801 | dns.rdatatype.A, | |
802 | '127.0.0.1') | |
803 | response.answer.append(rrset) | |
804 | ||
805 | query2 = dns.message.make_query(name, 'AAAA', 'IN') | |
806 | response2 = dns.message.make_response(query2) | |
807 | rrset2 = dns.rrset.from_text(name, | |
808 | ttl, | |
809 | dns.rdataclass.IN, | |
810 | dns.rdatatype.AAAA, | |
811 | '::1') | |
812 | response2.answer.append(rrset2) | |
813 | ||
814 | # Miss | |
815 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
816 | self.assertTrue(receivedQuery) | |
817 | self.assertTrue(receivedResponse) | |
818 | receivedQuery.id = query.id | |
819 | self.assertEquals(query, receivedQuery) | |
820 | self.assertEquals(response, receivedResponse) | |
821 | misses += 1 | |
822 | ||
823 | # next queries should hit the cache | |
824 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
825 | self.assertEquals(receivedResponse, response) | |
826 | ||
827 | # cache another entry | |
828 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2) | |
829 | self.assertTrue(receivedQuery) | |
830 | self.assertTrue(receivedResponse) | |
831 | receivedQuery.id = query2.id | |
832 | self.assertEquals(query2, receivedQuery) | |
833 | self.assertEquals(response2, receivedResponse) | |
834 | misses += 1 | |
835 | ||
836 | # queries for name A and AAAA should hit the cache | |
837 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
838 | self.assertEquals(receivedResponse, response) | |
839 | ||
840 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
841 | self.assertEquals(receivedResponse, response2) | |
842 | ||
843 | # remove cached entries from name A | |
844 | self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"" + name + "\"), dnsdist.A)") | |
845 | ||
846 | # Miss for name A | |
847 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
848 | self.assertTrue(receivedQuery) | |
849 | self.assertTrue(receivedResponse) | |
850 | receivedQuery.id = query.id | |
851 | self.assertEquals(query, receivedQuery) | |
852 | self.assertEquals(response, receivedResponse) | |
853 | misses += 1 | |
854 | ||
855 | # next queries for name A should hit the cache again | |
856 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
857 | self.assertEquals(receivedResponse, response) | |
858 | ||
859 | # queries for name AAAA should still hit the cache | |
860 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
490dc586 RG |
861 | self.assertEquals(receivedResponse, response2) |
862 | ||
863 | total = 0 | |
864 | for key in self._responsesCounter: | |
865 | total += self._responsesCounter[key] | |
866 | self.assertEquals(total, misses) | |
867 | ||
868 | def testCacheExpungeByNameAndSuffix(self): | |
869 | """ | |
870 | Cache: Expunge by name | |
871 | ||
872 | """ | |
873 | misses = 0 | |
874 | ttl = 600 | |
875 | name = 'expungebyname.suffix.cache.tests.powerdns.com.' | |
876 | query = dns.message.make_query(name, 'A', 'IN') | |
877 | response = dns.message.make_response(query) | |
878 | rrset = dns.rrset.from_text(name, | |
879 | ttl, | |
880 | dns.rdataclass.IN, | |
881 | dns.rdatatype.A, | |
882 | '127.0.0.1') | |
883 | response.answer.append(rrset) | |
884 | ||
885 | name2 = 'expungebyname.suffixother.cache.tests.powerdns.com.' | |
886 | query2 = dns.message.make_query(name2, 'A', 'IN') | |
887 | response2 = dns.message.make_response(query2) | |
888 | rrset2 = dns.rrset.from_text(name2, | |
889 | ttl, | |
890 | dns.rdataclass.IN, | |
891 | dns.rdatatype.A, | |
892 | '127.0.0.1') | |
893 | response2.answer.append(rrset2) | |
894 | ||
895 | # Miss | |
896 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
897 | self.assertTrue(receivedQuery) | |
898 | self.assertTrue(receivedResponse) | |
899 | receivedQuery.id = query.id | |
900 | self.assertEquals(query, receivedQuery) | |
901 | self.assertEquals(response, receivedResponse) | |
902 | misses += 1 | |
903 | ||
904 | # next queries should hit the cache | |
905 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
906 | self.assertEquals(receivedResponse, response) | |
907 | ||
908 | # cache another entry | |
909 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2) | |
910 | self.assertTrue(receivedQuery) | |
911 | self.assertTrue(receivedResponse) | |
912 | receivedQuery.id = query2.id | |
913 | self.assertEquals(query2, receivedQuery) | |
914 | self.assertEquals(response2, receivedResponse) | |
915 | misses += 1 | |
916 | ||
917 | # queries for name and name 2 should hit the cache | |
918 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
919 | self.assertEquals(receivedResponse, response) | |
920 | ||
921 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
922 | self.assertEquals(receivedResponse, response2) | |
923 | ||
924 | # remove cached entries from name | |
925 | self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"suffix.cache.tests.powerdns.com.\"), dnsdist.ANY, true)") | |
926 | ||
927 | # Miss for name | |
928 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
929 | self.assertTrue(receivedQuery) | |
930 | self.assertTrue(receivedResponse) | |
931 | receivedQuery.id = query.id | |
932 | self.assertEquals(query, receivedQuery) | |
933 | self.assertEquals(response, receivedResponse) | |
934 | misses += 1 | |
935 | ||
936 | # next queries for name should hit the cache again | |
937 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
938 | self.assertEquals(receivedResponse, response) | |
939 | ||
940 | # queries for name2 should still hit the cache | |
941 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
942 | self.assertEquals(receivedResponse, response2) | |
943 | ||
944 | total = 0 | |
945 | for key in self._responsesCounter: | |
946 | total += self._responsesCounter[key] | |
947 | ||
948 | self.assertEquals(total, misses) | |
949 | ||
950 | def testCacheExpungeByNameAndTypeAndSuffix(self): | |
951 | """ | |
952 | Cache: Expunge by name and type | |
953 | ||
954 | """ | |
955 | misses = 0 | |
956 | ttl = 600 | |
957 | name = 'expungebynameandtype.suffixtype.cache.tests.powerdns.com.' | |
958 | query = dns.message.make_query(name, 'A', 'IN') | |
959 | response = dns.message.make_response(query) | |
960 | rrset = dns.rrset.from_text(name, | |
961 | ttl, | |
962 | dns.rdataclass.IN, | |
963 | dns.rdatatype.A, | |
964 | '127.0.0.1') | |
965 | response.answer.append(rrset) | |
966 | ||
967 | query2 = dns.message.make_query(name, 'AAAA', 'IN') | |
968 | response2 = dns.message.make_response(query2) | |
969 | rrset2 = dns.rrset.from_text(name, | |
970 | ttl, | |
971 | dns.rdataclass.IN, | |
972 | dns.rdatatype.AAAA, | |
973 | '::1') | |
974 | response2.answer.append(rrset2) | |
975 | ||
976 | # Miss | |
977 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
978 | self.assertTrue(receivedQuery) | |
979 | self.assertTrue(receivedResponse) | |
980 | receivedQuery.id = query.id | |
981 | self.assertEquals(query, receivedQuery) | |
982 | self.assertEquals(response, receivedResponse) | |
983 | misses += 1 | |
984 | ||
985 | # next queries should hit the cache | |
986 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
987 | self.assertEquals(receivedResponse, response) | |
988 | ||
989 | # cache another entry | |
990 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2) | |
991 | self.assertTrue(receivedQuery) | |
992 | self.assertTrue(receivedResponse) | |
993 | receivedQuery.id = query2.id | |
994 | self.assertEquals(query2, receivedQuery) | |
995 | self.assertEquals(response2, receivedResponse) | |
996 | misses += 1 | |
997 | ||
998 | # queries for name A and AAAA should hit the cache | |
999 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1000 | self.assertEquals(receivedResponse, response) | |
1001 | ||
1002 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
1003 | self.assertEquals(receivedResponse, response2) | |
1004 | ||
1005 | # remove cached entries from name A | |
1006 | self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"suffixtype.cache.tests.powerdns.com.\"), dnsdist.A, true)") | |
1007 | ||
1008 | # Miss for name A | |
1009 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1010 | self.assertTrue(receivedQuery) | |
1011 | self.assertTrue(receivedResponse) | |
1012 | receivedQuery.id = query.id | |
1013 | self.assertEquals(query, receivedQuery) | |
1014 | self.assertEquals(response, receivedResponse) | |
1015 | misses += 1 | |
1016 | ||
1017 | # next queries for name A should hit the cache again | |
1018 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1019 | self.assertEquals(receivedResponse, response) | |
1020 | ||
1021 | # queries for name AAAA should still hit the cache | |
1022 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
1ea747c0 RG |
1023 | self.assertEquals(receivedResponse, response2) |
1024 | ||
1025 | total = 0 | |
02bbf9eb RG |
1026 | for key in self._responsesCounter: |
1027 | total += self._responsesCounter[key] | |
1ea747c0 | 1028 | self.assertEquals(total, misses) |
cc8cefe1 RG |
1029 | |
1030 | class TestCachingTTL(DNSDistTest): | |
1031 | ||
1032 | _maxCacheTTL = 86400 | |
1033 | _minCacheTTL = 600 | |
1034 | _config_params = ['_maxCacheTTL', '_minCacheTTL', '_testServerPort'] | |
1035 | _config_template = """ | |
1036 | pc = newPacketCache(1000, %s, %s) | |
1037 | getPool(""):setCache(pc) | |
1038 | newServer{address="127.0.0.1:%s"} | |
1039 | """ | |
1040 | def testCacheShortTTL(self): | |
1041 | """ | |
1042 | Cache: Entries with a TTL shorter than minTTL | |
1043 | ||
1044 | """ | |
1045 | misses = 0 | |
1046 | ttl = 60 | |
1047 | name = 'ttltooshort.cache.tests.powerdns.com.' | |
1048 | query = dns.message.make_query(name, 'A', 'IN') | |
1049 | response = dns.message.make_response(query) | |
1050 | rrset = dns.rrset.from_text(name, | |
1051 | ttl, | |
1052 | dns.rdataclass.IN, | |
1053 | dns.rdatatype.A, | |
1054 | '127.0.0.1') | |
1055 | response.answer.append(rrset) | |
1056 | ||
1057 | # Miss | |
1058 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1059 | self.assertTrue(receivedQuery) | |
1060 | self.assertTrue(receivedResponse) | |
1061 | receivedQuery.id = query.id | |
1062 | self.assertEquals(query, receivedQuery) | |
1063 | self.assertEquals(response, receivedResponse) | |
1064 | for an in receivedResponse.answer: | |
1065 | self.assertEquals(an.ttl, ttl) | |
1066 | misses += 1 | |
1067 | ||
1068 | # We should not have been cached | |
1069 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1070 | self.assertTrue(receivedQuery) | |
1071 | self.assertTrue(receivedResponse) | |
1072 | receivedQuery.id = query.id | |
1073 | self.assertEquals(query, receivedQuery) | |
1074 | self.assertEquals(response, receivedResponse) | |
1075 | for an in receivedResponse.answer: | |
1076 | self.assertEquals(an.ttl, ttl) | |
1077 | misses += 1 | |
1078 | ||
1079 | total = 0 | |
1080 | for key in self._responsesCounter: | |
1081 | total += self._responsesCounter[key] | |
1082 | ||
1083 | self.assertEquals(total, misses) | |
1084 | ||
a3824e43 RG |
1085 | def testCacheNXWithNoRR(self): |
1086 | """ | |
1087 | Cache: NX with no RR | |
1088 | ||
1089 | """ | |
1090 | misses = 0 | |
1091 | name = 'nxwithnorr.cache.tests.powerdns.com.' | |
1092 | query = dns.message.make_query(name, 'A', 'IN') | |
1093 | response = dns.message.make_response(query) | |
1094 | response.set_rcode(dns.rcode.NXDOMAIN) | |
1095 | ||
1096 | # Miss | |
1097 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1098 | self.assertTrue(receivedQuery) | |
1099 | self.assertTrue(receivedResponse) | |
1100 | receivedQuery.id = query.id | |
1101 | self.assertEquals(query, receivedQuery) | |
1102 | self.assertEquals(response, receivedResponse) | |
1103 | misses += 1 | |
1104 | ||
1105 | # We should not have been cached | |
1106 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1107 | self.assertTrue(receivedQuery) | |
1108 | self.assertTrue(receivedResponse) | |
1109 | receivedQuery.id = query.id | |
1110 | self.assertEquals(query, receivedQuery) | |
1111 | self.assertEquals(response, receivedResponse) | |
1112 | misses += 1 | |
1113 | ||
1114 | total = 0 | |
1115 | for key in self._responsesCounter: | |
1116 | total += self._responsesCounter[key] | |
1117 | ||
1118 | self.assertEquals(total, misses) | |
1119 | ||
cc8cefe1 RG |
1120 | class TestCachingLongTTL(DNSDistTest): |
1121 | ||
1122 | _maxCacheTTL = 2 | |
1123 | _config_params = ['_maxCacheTTL', '_testServerPort'] | |
1124 | _config_template = """ | |
1125 | pc = newPacketCache(1000, %s) | |
1126 | getPool(""):setCache(pc) | |
1127 | newServer{address="127.0.0.1:%s"} | |
1128 | """ | |
1129 | def testCacheLongTTL(self): | |
1130 | """ | |
1131 | Cache: Entries with a longer TTL than the maximum | |
1132 | ||
1133 | """ | |
1134 | misses = 0 | |
1135 | ttl = 172800 | |
1136 | name = 'longttl.cache.tests.powerdns.com.' | |
1137 | query = dns.message.make_query(name, 'A', 'IN') | |
1138 | response = dns.message.make_response(query) | |
1139 | rrset = dns.rrset.from_text(name, | |
1140 | ttl, | |
1141 | dns.rdataclass.IN, | |
1142 | dns.rdatatype.A, | |
1143 | '127.0.0.1') | |
1144 | response.answer.append(rrset) | |
1145 | ||
1146 | # Miss | |
1147 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1148 | self.assertTrue(receivedQuery) | |
1149 | self.assertTrue(receivedResponse) | |
1150 | receivedQuery.id = query.id | |
1151 | self.assertEquals(query, receivedQuery) | |
1152 | self.assertEquals(response, receivedResponse) | |
1153 | for an in receivedResponse.answer: | |
1154 | self.assertEquals(an.ttl, ttl) | |
1155 | misses += 1 | |
1156 | ||
1157 | # next queries should hit the cache | |
1158 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1159 | self.assertEquals(receivedResponse, response) | |
1160 | for an in receivedResponse.answer: | |
1161 | self.assertTrue(an.ttl <= ttl) | |
1162 | ||
1163 | time.sleep(self._maxCacheTTL + 1) | |
1164 | ||
1165 | # we should not have cached for longer than max cache | |
1166 | # so it should be a miss | |
1167 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1168 | self.assertTrue(receivedQuery) | |
1169 | self.assertTrue(receivedResponse) | |
1170 | receivedQuery.id = query.id | |
1171 | self.assertEquals(query, receivedQuery) | |
1172 | self.assertEquals(response, receivedResponse) | |
1173 | for an in receivedResponse.answer: | |
1174 | self.assertEquals(an.ttl, ttl) | |
1175 | misses += 1 | |
1176 | ||
1177 | total = 0 | |
1178 | for key in self._responsesCounter: | |
1179 | total += self._responsesCounter[key] | |
1180 | ||
1181 | self.assertEquals(total, misses) | |
2714396e RG |
1182 | |
1183 | class TestCachingFailureTTL(DNSDistTest): | |
1184 | ||
1185 | _failureCacheTTL = 2 | |
1186 | _config_params = ['_failureCacheTTL', '_testServerPort'] | |
1187 | _config_template = """ | |
1188 | pc = newPacketCache(1000, 86400, 0, %d, 60) | |
1189 | getPool(""):setCache(pc) | |
1190 | newServer{address="127.0.0.1:%s"} | |
1191 | """ | |
1192 | def testCacheServFailTTL(self): | |
1193 | """ | |
1194 | Cache: ServFail TTL | |
1195 | ||
1196 | """ | |
1197 | misses = 0 | |
1198 | name = 'servfail.failure.cache.tests.powerdns.com.' | |
1199 | query = dns.message.make_query(name, 'A', 'IN') | |
1200 | response = dns.message.make_response(query) | |
1201 | response.set_rcode(dns.rcode.SERVFAIL) | |
1202 | ||
1203 | # Miss | |
1204 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1205 | self.assertTrue(receivedQuery) | |
1206 | self.assertTrue(receivedResponse) | |
1207 | receivedQuery.id = query.id | |
1208 | self.assertEquals(query, receivedQuery) | |
1209 | self.assertEquals(response, receivedResponse) | |
1210 | misses += 1 | |
1211 | ||
1212 | # next queries should hit the cache | |
1213 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1214 | self.assertEquals(receivedResponse, response) | |
1215 | ||
1216 | time.sleep(self._failureCacheTTL + 1) | |
1217 | ||
1218 | # we should not have cached for longer than failure cache | |
1219 | # so it should be a miss | |
1220 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1221 | self.assertTrue(receivedQuery) | |
1222 | self.assertTrue(receivedResponse) | |
1223 | receivedQuery.id = query.id | |
1224 | self.assertEquals(query, receivedQuery) | |
1225 | self.assertEquals(response, receivedResponse) | |
1226 | misses += 1 | |
1227 | ||
1228 | total = 0 | |
1229 | for key in self._responsesCounter: | |
1230 | total += self._responsesCounter[key] | |
1231 | ||
1232 | self.assertEquals(total, misses) | |
1233 | ||
1234 | def testCacheRefusedTTL(self): | |
1235 | """ | |
1236 | Cache: Refused TTL | |
1237 | ||
1238 | """ | |
1239 | misses = 0 | |
1240 | name = 'refused.failure.cache.tests.powerdns.com.' | |
1241 | query = dns.message.make_query(name, 'A', 'IN') | |
1242 | response = dns.message.make_response(query) | |
1243 | response.set_rcode(dns.rcode.REFUSED) | |
1244 | ||
1245 | # Miss | |
1246 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1247 | self.assertTrue(receivedQuery) | |
1248 | self.assertTrue(receivedResponse) | |
1249 | receivedQuery.id = query.id | |
1250 | self.assertEquals(query, receivedQuery) | |
1251 | self.assertEquals(response, receivedResponse) | |
1252 | misses += 1 | |
1253 | ||
1254 | # next queries should hit the cache | |
1255 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1256 | self.assertEquals(receivedResponse, response) | |
1257 | ||
1258 | time.sleep(self._failureCacheTTL + 1) | |
1259 | ||
1260 | # we should not have cached for longer than failure cache | |
1261 | # so it should be a miss | |
1262 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1263 | self.assertTrue(receivedQuery) | |
1264 | self.assertTrue(receivedResponse) | |
1265 | receivedQuery.id = query.id | |
1266 | self.assertEquals(query, receivedQuery) | |
1267 | self.assertEquals(response, receivedResponse) | |
1268 | misses += 1 | |
1269 | ||
1270 | total = 0 | |
1271 | for key in self._responsesCounter: | |
1272 | total += self._responsesCounter[key] | |
1273 | ||
1274 | self.assertEquals(total, misses) | |
1275 | ||
1276 | def testCacheHeaderOnlyRefusedTTL(self): | |
1277 | """ | |
1278 | Cache: Header-Only Refused TTL | |
1279 | ||
1280 | """ | |
1281 | misses = 0 | |
1282 | name = 'header-only-refused.failure.cache.tests.powerdns.com.' | |
1283 | query = dns.message.make_query(name, 'A', 'IN') | |
1284 | response = dns.message.make_response(query) | |
1285 | response.set_rcode(dns.rcode.REFUSED) | |
1286 | response.question = [] | |
1287 | ||
1288 | # Miss | |
1289 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1290 | self.assertTrue(receivedQuery) | |
1291 | self.assertTrue(receivedResponse) | |
1292 | receivedQuery.id = query.id | |
1293 | self.assertEquals(query, receivedQuery) | |
1294 | self.assertEquals(response, receivedResponse) | |
1295 | misses += 1 | |
1296 | ||
1297 | # next queries should hit the cache | |
1298 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1299 | self.assertEquals(receivedResponse, response) | |
1300 | ||
1301 | time.sleep(self._failureCacheTTL + 1) | |
1302 | ||
1303 | # we should not have cached for longer than failure cache | |
1304 | # so it should be a miss | |
1305 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1306 | self.assertTrue(receivedQuery) | |
1307 | self.assertTrue(receivedResponse) | |
1308 | receivedQuery.id = query.id | |
1309 | self.assertEquals(query, receivedQuery) | |
1310 | self.assertEquals(response, receivedResponse) | |
1311 | misses += 1 | |
1312 | ||
1313 | total = 0 | |
1314 | for key in self._responsesCounter: | |
1315 | total += self._responsesCounter[key] | |
1316 | ||
1317 | self.assertEquals(total, misses) | |
2b67180c RG |
1318 | |
1319 | class TestCachingDontAge(DNSDistTest): | |
1320 | ||
1321 | _config_template = """ | |
1322 | pc = newPacketCache(100, 86400, 0, 60, 60, true) | |
1323 | getPool(""):setCache(pc) | |
1324 | newServer{address="127.0.0.1:%s"} | |
1325 | """ | |
1326 | def testCacheDoesntDecreaseTTL(self): | |
1327 | """ | |
1328 | Cache: Cache doesn't decrease TTL with 'don't age' set | |
1329 | ||
1330 | dnsdist is configured to cache entries but without aging the TTL, | |
1331 | we are sending one request (cache miss) and verify that the cache | |
1332 | hits don't have a decreasing TTL. | |
1333 | """ | |
1334 | ttl = 600 | |
1335 | misses = 0 | |
1336 | name = 'cachedoesntdecreasettl.cache-dont-age.tests.powerdns.com.' | |
1337 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
1338 | response = dns.message.make_response(query) | |
1339 | rrset = dns.rrset.from_text(name, | |
1340 | ttl, | |
1341 | dns.rdataclass.IN, | |
1342 | dns.rdatatype.AAAA, | |
1343 | '::1') | |
1344 | response.answer.append(rrset) | |
1345 | ||
1346 | # first query to fill the cache | |
1347 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1348 | self.assertTrue(receivedQuery) | |
1349 | self.assertTrue(receivedResponse) | |
1350 | receivedQuery.id = query.id | |
1351 | self.assertEquals(query, receivedQuery) | |
1352 | self.assertEquals(receivedResponse, response) | |
1353 | misses += 1 | |
1354 | ||
1355 | # next queries should hit the cache | |
1356 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1357 | self.assertEquals(receivedResponse, response) | |
1358 | for an in receivedResponse.answer: | |
1359 | self.assertTrue(an.ttl == ttl) | |
1360 | ||
1361 | # now we wait a bit for the TTL to decrease | |
1362 | time.sleep(1) | |
1363 | ||
1364 | # next queries should hit the cache | |
1365 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1366 | self.assertEquals(receivedResponse, response) | |
1367 | for an in receivedResponse.answer: | |
1368 | self.assertTrue(an.ttl == ttl) | |
1369 | ||
1370 | total = 0 | |
1371 | for key in self._responsesCounter: | |
1372 | total += self._responsesCounter[key] | |
1373 | ||
1374 | self.assertEquals(total, misses) |