]>
git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.dnsdist/test_Routing.py
6 from dnsdisttests
import DNSDistTest
, pickAvailablePort
8 class TestRoutingPoolRouting(DNSDistTest
):
10 _config_template
= """
11 newServer{address="127.0.0.1:%s", pool="real"}
12 addAction(makeRule("poolaction.routing.tests.powerdns.com"), PoolAction("real"))
13 -- by default PoolAction stops the processing so the second rule should not be executed
14 addAction(makeRule("poolaction.routing.tests.powerdns.com"), PoolAction("not-real"))
16 -- this time we configure PoolAction to not stop the processing
17 addAction(makeRule("poolaction-nostop.routing.tests.powerdns.com"), PoolAction("no-real", false))
18 -- so the second rule should be executed
19 addAction(makeRule("poolaction-nostop.routing.tests.powerdns.com"), PoolAction("real"))
22 def testPolicyPoolAction(self
):
24 Routing: Set pool by qname via PoolAction
26 Send an A query to "poolaction.routing.tests.powerdns.com.",
27 check that dnsdist routes the query to the "real" pool.
29 name
= 'poolaction.routing.tests.powerdns.com.'
30 query
= dns
.message
.make_query(name
, 'A', 'IN')
31 response
= dns
.message
.make_response(query
)
32 rrset
= dns
.rrset
.from_text(name
,
37 response
.answer
.append(rrset
)
39 for method
in ("sendUDPQuery", "sendTCPQuery"):
40 sender
= getattr(self
, method
)
41 (receivedQuery
, receivedResponse
) = sender(query
, response
)
42 receivedQuery
.id = query
.id
43 self
.assertEqual(query
, receivedQuery
)
44 self
.assertEqual(response
, receivedResponse
)
46 def testPolicyPoolActionNoStop(self
):
48 Routing: Set pool by qname via PoolAction (no stop)
50 name
= 'poolaction-nostop.routing.tests.powerdns.com.'
51 query
= dns
.message
.make_query(name
, 'A', 'IN')
52 response
= dns
.message
.make_response(query
)
53 rrset
= dns
.rrset
.from_text(name
,
58 response
.answer
.append(rrset
)
60 for method
in ("sendUDPQuery", "sendTCPQuery"):
61 sender
= getattr(self
, method
)
62 (receivedQuery
, receivedResponse
) = sender(query
, response
)
63 receivedQuery
.id = query
.id
64 self
.assertEqual(query
, receivedQuery
)
65 self
.assertEqual(response
, receivedResponse
)
67 def testDefaultPool(self
):
69 Routing: Set pool by qname canary
71 Send an A query to "notpool.routing.tests.powerdns.com.",
72 check that dnsdist sends no response (no servers
75 name
= 'notpool.routing.tests.powerdns.com.'
76 query
= dns
.message
.make_query(name
, 'A', 'IN')
78 for method
in ("sendUDPQuery", "sendTCPQuery"):
79 sender
= getattr(self
, method
)
80 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
81 self
.assertEqual(receivedResponse
, None)
83 class TestRoutingQPSPoolRouting(DNSDistTest
):
84 _config_template
= """
85 newServer{address="127.0.0.1:%s", pool="regular"}
86 addAction(makeRule("qpspoolaction.routing.tests.powerdns.com"), QPSPoolAction(10, "regular"))
89 def testQPSPoolAction(self
):
91 Routing: Set pool by QPS via action
93 Send queries to "qpspoolaction.routing.tests.powerdns.com."
94 check that dnsdist does not route the query to the "regular" pool
95 when the max QPS has been reached.
98 name
= 'qpspoolaction.routing.tests.powerdns.com.'
99 query
= dns
.message
.make_query(name
, 'A', 'IN')
100 response
= dns
.message
.make_response(query
)
101 rrset
= dns
.rrset
.from_text(name
,
106 response
.answer
.append(rrset
)
108 for _
in range(maxQPS
):
109 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
110 receivedQuery
.id = query
.id
111 self
.assertEqual(query
, receivedQuery
)
112 self
.assertEqual(response
, receivedResponse
)
114 # we should now be sent to the "abuse" pool which is empty,
115 # so the queries should be dropped
116 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
117 self
.assertEqual(receivedResponse
, None)
121 # again, over TCP this time
122 for _
in range(maxQPS
):
123 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
124 receivedQuery
.id = query
.id
125 self
.assertEqual(query
, receivedQuery
)
126 self
.assertEqual(response
, receivedResponse
)
129 (_
, receivedResponse
) = self
.sendTCPQuery(query
, response
=None, useQueue
=False)
130 self
.assertEqual(receivedResponse
, None)
133 class TestRoutingRoundRobinLB(DNSDistTest
):
135 _testServer2Port
= pickAvailablePort()
136 _config_params
= ['_testServerPort', '_testServer2Port']
137 _config_template
= """
138 setServerPolicy(roundrobin)
139 s1 = newServer{address="127.0.0.1:%s"}
141 s2 = newServer{address="127.0.0.1:%s"}
146 def startResponders(cls
):
147 print("Launching responders..")
148 cls
._UDPResponder
= threading
.Thread(name
='UDP Responder', target
=cls
.UDPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
149 cls
._UDPResponder
.daemon
= True
150 cls
._UDPResponder
.start()
151 cls
._UDPResponder
2 = threading
.Thread(name
='UDP Responder 2', target
=cls
.UDPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
152 cls
._UDPResponder
2.daemon
= True
153 cls
._UDPResponder
2.start()
155 cls
._TCPResponder
= threading
.Thread(name
='TCP Responder', target
=cls
.TCPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
156 cls
._TCPResponder
.daemon
= True
157 cls
._TCPResponder
.start()
159 cls
._TCPResponder
2 = threading
.Thread(name
='TCP Responder 2', target
=cls
.TCPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
160 cls
._TCPResponder
2.daemon
= True
161 cls
._TCPResponder
2.start()
167 Send 10 A queries to "rr.routing.tests.powerdns.com.",
168 check that dnsdist routes half of it to each backend.
171 name
= 'rr.routing.tests.powerdns.com.'
172 query
= dns
.message
.make_query(name
, 'A', 'IN')
173 response
= dns
.message
.make_response(query
)
174 rrset
= dns
.rrset
.from_text(name
,
179 response
.answer
.append(rrset
)
181 # the round robin counter is shared for UDP and TCP,
182 # so we need to do UDP then TCP to have a clean count
183 for _
in range(numberOfQueries
):
184 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
185 receivedQuery
.id = query
.id
186 self
.assertEqual(query
, receivedQuery
)
187 self
.assertEqual(response
, receivedResponse
)
189 for _
in range(numberOfQueries
):
190 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
191 receivedQuery
.id = query
.id
192 self
.assertEqual(query
, receivedQuery
)
193 self
.assertEqual(response
, receivedResponse
)
195 for key
in self
._responsesCounter
:
196 value
= self
._responsesCounter
[key
]
197 self
.assertEqual(value
, numberOfQueries
/ 2)
199 class TestRoutingRoundRobinLBOneDown(DNSDistTest
):
201 _testServer2Port
= pickAvailablePort()
202 _config_params
= ['_testServerPort', '_testServer2Port']
203 _config_template
= """
204 setServerPolicy(roundrobin)
205 s1 = newServer{address="127.0.0.1:%s"}
207 s2 = newServer{address="127.0.0.1:%s"}
211 def testRRWithOneDown(self
):
213 Routing: Round Robin with one server down
215 Send 100 A queries to "rr.routing.tests.powerdns.com.",
216 check that dnsdist routes all of it to the only backend up.
219 name
= 'rr.routing.tests.powerdns.com.'
220 query
= dns
.message
.make_query(name
, 'A', 'IN')
221 response
= dns
.message
.make_response(query
)
222 rrset
= dns
.rrset
.from_text(name
,
227 response
.answer
.append(rrset
)
229 # the round robin counter is shared for UDP and TCP,
230 # so we need to do UDP then TCP to have a clean count
231 for _
in range(numberOfQueries
):
232 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
233 receivedQuery
.id = query
.id
234 self
.assertEqual(query
, receivedQuery
)
235 self
.assertEqual(response
, receivedResponse
)
237 for _
in range(numberOfQueries
):
238 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
239 receivedQuery
.id = query
.id
240 self
.assertEqual(query
, receivedQuery
)
241 self
.assertEqual(response
, receivedResponse
)
244 for key
in self
._responsesCounter
:
245 value
= self
._responsesCounter
[key
]
246 self
.assertTrue(value
== numberOfQueries
or value
== 0)
249 self
.assertEqual(total
, numberOfQueries
* 2)
251 class TestRoutingRoundRobinLBAllDown(DNSDistTest
):
253 _testServer2Port
= pickAvailablePort()
254 _config_params
= ['_testServerPort', '_testServer2Port']
255 _config_template
= """
256 setServerPolicy(roundrobin)
257 setRoundRobinFailOnNoServer(true)
258 s1 = newServer{address="127.0.0.1:%s"}
260 s2 = newServer{address="127.0.0.1:%s"}
264 def testRRWithAllDown(self
):
266 Routing: Round Robin with all servers down
269 name
= 'alldown.rr.routing.tests.powerdns.com.'
270 query
= dns
.message
.make_query(name
, 'A', 'IN')
271 response
= dns
.message
.make_response(query
)
272 rrset
= dns
.rrset
.from_text(name
,
277 response
.answer
.append(rrset
)
279 for method
in ("sendUDPQuery", "sendTCPQuery"):
280 sender
= getattr(self
, method
)
281 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
282 self
.assertEqual(receivedResponse
, None)
284 class TestRoutingLuaFFIPerThreadRoundRobinLB(DNSDistTest
):
286 _testServer2Port
= pickAvailablePort()
287 _config_params
= ['_testServerPort', '_testServer2Port']
288 _config_template
= """
289 -- otherwise we start too many TCP workers, and as each thread
290 -- uses it own counter this makes the TCP queries distribution hard to predict
291 setMaxTCPClientThreads(1)
292 setServerPolicyLuaFFIPerThread("luaffiroundrobin", [[
293 local ffi = require("ffi")
297 return function(servers_list, dq)
298 counter = counter + 1
299 return (counter %% tonumber(C.dnsdist_ffi_servers_list_get_count(servers_list)))
303 s1 = newServer{address="127.0.0.1:%s"}
305 s2 = newServer{address="127.0.0.1:%s"}
310 def startResponders(cls
):
311 print("Launching responders..")
312 cls
._UDPResponder
= threading
.Thread(name
='UDP Responder', target
=cls
.UDPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
313 cls
._UDPResponder
.daemon
= True
314 cls
._UDPResponder
.start()
315 cls
._UDPResponder
2 = threading
.Thread(name
='UDP Responder 2', target
=cls
.UDPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
316 cls
._UDPResponder
2.daemon
= True
317 cls
._UDPResponder
2.start()
319 cls
._TCPResponder
= threading
.Thread(name
='TCP Responder', target
=cls
.TCPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
320 cls
._TCPResponder
.daemon
= True
321 cls
._TCPResponder
.start()
323 cls
._TCPResponder
2 = threading
.Thread(name
='TCP Responder 2', target
=cls
.TCPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
324 cls
._TCPResponder
2.daemon
= True
325 cls
._TCPResponder
2.start()
331 Send 10 A queries to "rr.routing.tests.powerdns.com.",
332 check that dnsdist routes half of it to each backend.
335 name
= 'rr.routing.tests.powerdns.com.'
336 query
= dns
.message
.make_query(name
, 'A', 'IN')
337 response
= dns
.message
.make_response(query
)
338 rrset
= dns
.rrset
.from_text(name
,
343 response
.answer
.append(rrset
)
345 # the round robin counter is shared for UDP and TCP,
346 # so we need to do UDP then TCP to have a clean count
347 for _
in range(numberOfQueries
):
348 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
349 receivedQuery
.id = query
.id
350 self
.assertEqual(query
, receivedQuery
)
351 self
.assertEqual(response
, receivedResponse
)
353 for _
in range(numberOfQueries
):
354 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
355 receivedQuery
.id = query
.id
356 self
.assertEqual(query
, receivedQuery
)
357 self
.assertEqual(response
, receivedResponse
)
359 for key
in self
._responsesCounter
:
360 value
= self
._responsesCounter
[key
]
361 self
.assertEqual(value
, numberOfQueries
/ 2)
363 class TestRoutingOrder(DNSDistTest
):
365 _testServer2Port
= pickAvailablePort()
366 _config_params
= ['_testServerPort', '_testServer2Port']
367 _config_template
= """
368 setServerPolicy(firstAvailable)
369 s1 = newServer{address="127.0.0.1:%s", order=2}
371 s2 = newServer{address="127.0.0.1:%s", order=1}
376 def startResponders(cls
):
377 print("Launching responders..")
378 cls
._UDPResponder
= threading
.Thread(name
='UDP Responder', target
=cls
.UDPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
379 cls
._UDPResponder
.daemon
= True
380 cls
._UDPResponder
.start()
381 cls
._UDPResponder
2 = threading
.Thread(name
='UDP Responder 2', target
=cls
.UDPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
382 cls
._UDPResponder
2.daemon
= True
383 cls
._UDPResponder
2.start()
385 cls
._TCPResponder
= threading
.Thread(name
='TCP Responder', target
=cls
.TCPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
386 cls
._TCPResponder
.daemon
= True
387 cls
._TCPResponder
.start()
389 cls
._TCPResponder
2 = threading
.Thread(name
='TCP Responder 2', target
=cls
.TCPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
390 cls
._TCPResponder
2.daemon
= True
391 cls
._TCPResponder
2.start()
395 Routing: firstAvailable policy based on 'order'
397 Send 50 A queries to "order.routing.tests.powerdns.com.",
398 check that dnsdist routes all of it to the second backend
399 because it has the lower order value.
402 name
= 'order.routing.tests.powerdns.com.'
403 query
= dns
.message
.make_query(name
, 'A', 'IN')
404 response
= dns
.message
.make_response(query
)
405 rrset
= dns
.rrset
.from_text(name
,
410 response
.answer
.append(rrset
)
412 for _
in range(numberOfQueries
):
413 for method
in ("sendUDPQuery", "sendTCPQuery"):
414 sender
= getattr(self
, method
)
415 (receivedQuery
, receivedResponse
) = sender(query
, response
)
416 receivedQuery
.id = query
.id
417 self
.assertEqual(query
, receivedQuery
)
418 self
.assertEqual(response
, receivedResponse
)
421 if 'UDP Responder' in self
._responsesCounter
:
422 self
.assertEqual(self
._responsesCounter
['UDP Responder'], 0)
423 self
.assertEqual(self
._responsesCounter
['UDP Responder 2'], numberOfQueries
)
424 if 'TCP Responder' in self
._responsesCounter
:
425 self
.assertEqual(self
._responsesCounter
['TCP Responder'], 0)
426 self
.assertEqual(self
._responsesCounter
['TCP Responder 2'], numberOfQueries
)
428 class TestFirstAvailableQPSPacketCacheHits(DNSDistTest
):
431 _testServer2Port
= pickAvailablePort()
432 _config_params
= ['_testServerPort', '_testServer2Port']
433 _config_template
= """
434 setServerPolicy(firstAvailable)
435 s1 = newServer{address="127.0.0.1:%s", order=2}
437 s2 = newServer{address="127.0.0.1:%s", order=1, qps=10}
439 pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
440 getPool(""):setCache(pc)
444 def startResponders(cls
):
445 print("Launching responders..")
446 cls
._UDPResponder
= threading
.Thread(name
='UDP Responder', target
=cls
.UDPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
447 cls
._UDPResponder
.daemon
= True
448 cls
._UDPResponder
.start()
449 cls
._UDPResponder
2 = threading
.Thread(name
='UDP Responder 2', target
=cls
.UDPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
450 cls
._UDPResponder
2.daemon
= True
451 cls
._UDPResponder
2.start()
453 cls
._TCPResponder
= threading
.Thread(name
='TCP Responder', target
=cls
.TCPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
454 cls
._TCPResponder
.daemon
= True
455 cls
._TCPResponder
.start()
457 cls
._TCPResponder
2 = threading
.Thread(name
='TCP Responder 2', target
=cls
.TCPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
458 cls
._TCPResponder
2.daemon
= True
459 cls
._TCPResponder
2.start()
461 def testOrderQPSCacheHits(self
):
463 Routing: firstAvailable policy with QPS limit and packet cache
465 Send 50 A queries for "order-qps-cache.routing.tests.powerdns.com.",
466 then 10 A queries for "order-qps-cache-2.routing.tests.powerdns.com." (uncached)
467 check that dnsdist routes all of the (uncached) queries to the second backend, because it has the lower order value,
468 and the QPS should only be counted for cache misses.
471 name
= 'order-qps-cache.routing.tests.powerdns.com.'
472 query
= dns
.message
.make_query(name
, 'A', 'IN')
473 response
= dns
.message
.make_response(query
)
474 rrset
= dns
.rrset
.from_text(name
,
479 response
.answer
.append(rrset
)
481 # first queries to fill the cache
482 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
483 self
.assertTrue(receivedQuery
)
484 self
.assertTrue(receivedResponse
)
485 receivedQuery
.id = query
.id
486 self
.assertEqual(query
, receivedQuery
)
487 self
.assertEqual(receivedResponse
, response
)
488 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
489 self
.assertTrue(receivedQuery
)
490 self
.assertTrue(receivedResponse
)
491 receivedQuery
.id = query
.id
492 self
.assertEqual(query
, receivedQuery
)
493 self
.assertEqual(receivedResponse
, response
)
495 for _
in range(numberOfQueries
):
496 for method
in ("sendUDPQuery", "sendTCPQuery"):
497 sender
= getattr(self
, method
)
498 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
499 self
.assertEqual(receivedResponse
, response
)
502 name
= 'order-qps-cache-2.routing.tests.powerdns.com.'
503 query
= dns
.message
.make_query(name
, 'A', 'IN')
504 response
= dns
.message
.make_response(query
)
505 rrset
= dns
.rrset
.from_text(name
,
510 response
.answer
.append(rrset
)
512 # first queries to fill the cache
513 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
514 self
.assertTrue(receivedQuery
)
515 self
.assertTrue(receivedResponse
)
516 receivedQuery
.id = query
.id
517 self
.assertEqual(query
, receivedQuery
)
518 self
.assertEqual(receivedResponse
, response
)
519 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
520 self
.assertTrue(receivedQuery
)
521 self
.assertTrue(receivedResponse
)
522 receivedQuery
.id = query
.id
523 self
.assertEqual(query
, receivedQuery
)
524 self
.assertEqual(receivedResponse
, response
)
526 for _
in range(numberOfQueries
):
527 for method
in ("sendUDPQuery", "sendTCPQuery"):
528 sender
= getattr(self
, method
)
529 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
530 self
.assertEqual(receivedResponse
, response
)
532 # 4 queries should made it through, 2 UDP and 2 TCP
533 for k
,v
in self
._responsesCounter
.items():
537 if 'UDP Responder' in self
._responsesCounter
:
538 self
.assertEqual(self
._responsesCounter
['UDP Responder'], 0)
539 self
.assertEqual(self
._responsesCounter
['UDP Responder 2'], 2)
540 if 'TCP Responder' in self
._responsesCounter
:
541 self
.assertEqual(self
._responsesCounter
['TCP Responder'], 0)
542 self
.assertEqual(self
._responsesCounter
['TCP Responder 2'], 2)
544 class TestRoutingNoServer(DNSDistTest
):
546 _config_template
= """
547 newServer{address="127.0.0.1:%s", pool="real"}
548 setServFailWhenNoServer(true)
551 def testPolicyPoolNoServer(self
):
553 Routing: No server should return ServFail
556 name
= 'noserver.routing.tests.powerdns.com.'
557 query
= dns
.message
.make_query(name
, 'A', 'IN')
558 expectedResponse
= dns
.message
.make_response(query
)
559 expectedResponse
.set_rcode(dns
.rcode
.SERVFAIL
)
561 for method
in ("sendUDPQuery", "sendTCPQuery"):
562 sender
= getattr(self
, method
)
563 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
564 self
.checkMessageNoEDNS(expectedResponse
, receivedResponse
)
567 query
= dns
.message
.make_query(name
, 'A', 'IN', use_edns
=True, payload
=4096, want_dnssec
=False)
568 expectedResponse
= dns
.message
.make_response(query
, our_payload
=1232)
569 expectedResponse
.set_rcode(dns
.rcode
.SERVFAIL
)
571 for method
in ("sendUDPQuery", "sendTCPQuery"):
572 sender
= getattr(self
, method
)
573 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
574 self
.checkMessageEDNSWithoutOptions(expectedResponse
, receivedResponse
)
575 self
.assertFalse(receivedResponse
.ednsflags
& dns
.flags
.DO
)
576 self
.assertEqual(receivedResponse
.payload
, 1232)
578 class TestRoutingWRandom(DNSDistTest
):
580 _testServer2Port
= pickAvailablePort()
581 _config_params
= ['_testServerPort', '_testServer2Port']
582 _config_template
= """
583 setServerPolicy(wrandom)
584 s1 = newServer{address="127.0.0.1:%s", weight=1}
586 s2 = newServer{address="127.0.0.1:%s", weight=2}
591 def startResponders(cls
):
592 print("Launching responders..")
593 cls
._UDPResponder
= threading
.Thread(name
='UDP Responder', target
=cls
.UDPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
594 cls
._UDPResponder
.daemon
= True
595 cls
._UDPResponder
.start()
596 cls
._UDPResponder
2 = threading
.Thread(name
='UDP Responder 2', target
=cls
.UDPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
597 cls
._UDPResponder
2.daemon
= True
598 cls
._UDPResponder
2.start()
600 cls
._TCPResponder
= threading
.Thread(name
='TCP Responder', target
=cls
.TCPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
601 cls
._TCPResponder
.daemon
= True
602 cls
._TCPResponder
.start()
604 cls
._TCPResponder
2 = threading
.Thread(name
='TCP Responder 2', target
=cls
.TCPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
605 cls
._TCPResponder
2.daemon
= True
606 cls
._TCPResponder
2.start()
608 def testWRandom(self
):
612 Send 100 A queries to "wrandom.routing.tests.powerdns.com.",
613 check that dnsdist routes less than half to one, more to the other.
615 numberOfQueries
= 100
616 name
= 'wrandom.routing.tests.powerdns.com.'
617 query
= dns
.message
.make_query(name
, 'A', 'IN')
618 response
= dns
.message
.make_response(query
)
619 rrset
= dns
.rrset
.from_text(name
,
624 response
.answer
.append(rrset
)
626 # the counter is shared for UDP and TCP,
627 # so we need to do UDP then TCP to have a clean count
628 for _
in range(numberOfQueries
):
629 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
630 receivedQuery
.id = query
.id
631 self
.assertEqual(query
, receivedQuery
)
632 self
.assertEqual(response
, receivedResponse
)
634 for _
in range(numberOfQueries
):
635 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
636 receivedQuery
.id = query
.id
637 self
.assertEqual(query
, receivedQuery
)
638 self
.assertEqual(response
, receivedResponse
)
640 # The lower weight downstream should receive less than half the queries
641 self
.assertLess(self
._responsesCounter
['UDP Responder'], numberOfQueries
* 0.50)
642 self
.assertLess(self
._responsesCounter
['TCP Responder'], numberOfQueries
* 0.50)
644 # The higher weight downstream should receive more than half the queries
645 self
.assertGreater(self
._responsesCounter
['UDP Responder 2'], numberOfQueries
* 0.50)
646 self
.assertGreater(self
._responsesCounter
['TCP Responder 2'], numberOfQueries
* 0.50)
649 class TestRoutingHighValueWRandom(DNSDistTest
):
651 _testServer2Port
= pickAvailablePort()
652 _consoleKey
= DNSDistTest
.generateConsoleKey()
653 _consoleKeyB64
= base64
.b64encode(_consoleKey
).decode('ascii')
654 _config_params
= ['_consoleKeyB64', '_consolePort', '_testServerPort', '_testServer2Port']
655 _config_template
= """
657 controlSocket("127.0.0.1:%s")
658 setServerPolicy(wrandom)
659 s1 = newServer{address="127.0.0.1:%s", weight=2000000000}
661 s2 = newServer{address="127.0.0.1:%s", weight=2000000000}
666 def startResponders(cls
):
667 print("Launching responders..")
668 cls
._UDPResponder
= threading
.Thread(name
='UDP Responder', target
=cls
.UDPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
669 cls
._UDPResponder
.daemon
= True
670 cls
._UDPResponder
.start()
671 cls
._UDPResponder
2 = threading
.Thread(name
='UDP Responder 2', target
=cls
.UDPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
672 cls
._UDPResponder
2.daemon
= True
673 cls
._UDPResponder
2.start()
675 cls
._TCPResponder
= threading
.Thread(name
='TCP Responder', target
=cls
.TCPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
676 cls
._TCPResponder
.daemon
= True
677 cls
._TCPResponder
.start()
679 cls
._TCPResponder
2 = threading
.Thread(name
='TCP Responder 2', target
=cls
.TCPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
680 cls
._TCPResponder
2.daemon
= True
681 cls
._TCPResponder
2.start()
683 def testHighValueWRandom(self
):
685 Routing: WRandom (overflow)
687 Send 100 A queries to "wrandom-overflow.routing.tests.powerdns.com.",
688 check that dnsdist routes to each downstream, rather than failing with
691 numberOfQueries
= 100
692 name
= 'wrandom-overflow.routing.tests.powerdns.com.'
693 query
= dns
.message
.make_query(name
, 'A', 'IN')
694 response
= dns
.message
.make_response(query
)
695 rrset
= dns
.rrset
.from_text(name
,
700 response
.answer
.append(rrset
)
702 # the counter is shared for UDP and TCP,
703 # so we need to do UDP then TCP to have a clean count
704 for _
in range(numberOfQueries
):
705 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
706 receivedQuery
.id = query
.id
707 self
.assertEqual(query
, receivedQuery
)
708 self
.assertEqual(response
, receivedResponse
)
710 for _
in range(numberOfQueries
):
711 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
712 receivedQuery
.id = query
.id
713 self
.assertEqual(query
, receivedQuery
)
714 self
.assertEqual(response
, receivedResponse
)
716 stats
= self
.sendConsoleCommand("dumpStats()").split()
719 # Map to a dict with every other element being the value to the previous one
720 for i
, x
in enumerate(stats
):
722 stats_dict
[x
] = stats
[i
+1]
724 # There should be no queries getting "no-policy" responses
725 self
.assertEqual(stats_dict
['no-policy'], '0')
727 # Each downstream should receive some queries, but it will be unbalanced
728 # because the sum of the weights is higher than INT_MAX.
729 # The first downstream will receive more than half the queries
730 self
.assertGreater(self
._responsesCounter
['UDP Responder'], numberOfQueries
/ 2)
731 self
.assertGreater(self
._responsesCounter
['TCP Responder'], numberOfQueries
/ 2)
733 # The second downstream will receive the remainder of the queries, but it might very well be 0
734 if 'UDP Responder 2' in self
._responsesCounter
:
735 self
.assertEqual(self
._responsesCounter
['UDP Responder 2'], numberOfQueries
- self
._responsesCounter
['UDP Responder'])
736 if 'TCP Responder 2' in self
._responsesCounter
:
737 self
.assertEqual(self
._responsesCounter
['TCP Responder 2'], numberOfQueries
- self
._responsesCounter
['TCP Responder'])