]>
git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.dnsdist/test_Routing.py
6 from dnsdisttests
import DNSDistTest
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"))
15 def testPolicyPoolAction(self
):
17 Routing: Set pool by qname via PoolAction
19 Send an A query to "poolaction.routing.tests.powerdns.com.",
20 check that dnsdist routes the query to the "real" pool.
22 name
= 'poolaction.routing.tests.powerdns.com.'
23 query
= dns
.message
.make_query(name
, 'A', 'IN')
24 response
= dns
.message
.make_response(query
)
25 rrset
= dns
.rrset
.from_text(name
,
30 response
.answer
.append(rrset
)
32 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
33 receivedQuery
.id = query
.id
34 self
.assertEquals(query
, receivedQuery
)
35 self
.assertEquals(response
, receivedResponse
)
37 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
38 receivedQuery
.id = query
.id
39 self
.assertEquals(query
, receivedQuery
)
40 self
.assertEquals(response
, receivedResponse
)
42 def testDefaultPool(self
):
44 Routing: Set pool by qname canary
46 Send an A query to "notpool.routing.tests.powerdns.com.",
47 check that dnsdist sends no response (no servers
50 name
= 'notpool.routing.tests.powerdns.com.'
51 query
= dns
.message
.make_query(name
, 'A', 'IN')
53 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
54 self
.assertEquals(receivedResponse
, None)
56 (_
, receivedResponse
) = self
.sendTCPQuery(query
, response
=None, useQueue
=False)
57 self
.assertEquals(receivedResponse
, None)
59 class TestRoutingQPSPoolRouting(DNSDistTest
):
60 _config_template
= """
61 newServer{address="127.0.0.1:%s", pool="regular"}
62 addAction(makeRule("qpspoolaction.routing.tests.powerdns.com"), QPSPoolAction(10, "regular"))
65 def testQPSPoolAction(self
):
67 Routing: Set pool by QPS via action
69 Send queries to "qpspoolaction.routing.tests.powerdns.com."
70 check that dnsdist does not route the query to the "regular" pool
71 when the max QPS has been reached.
74 name
= 'qpspoolaction.routing.tests.powerdns.com.'
75 query
= dns
.message
.make_query(name
, 'A', 'IN')
76 response
= dns
.message
.make_response(query
)
77 rrset
= dns
.rrset
.from_text(name
,
82 response
.answer
.append(rrset
)
84 for _
in range(maxQPS
):
85 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
86 receivedQuery
.id = query
.id
87 self
.assertEquals(query
, receivedQuery
)
88 self
.assertEquals(response
, receivedResponse
)
90 # we should now be sent to the "abuse" pool which is empty,
91 # so the queries should be dropped
92 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
93 self
.assertEquals(receivedResponse
, None)
97 # again, over TCP this time
98 for _
in range(maxQPS
):
99 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
100 receivedQuery
.id = query
.id
101 self
.assertEquals(query
, receivedQuery
)
102 self
.assertEquals(response
, receivedResponse
)
105 (_
, receivedResponse
) = self
.sendTCPQuery(query
, response
=None, useQueue
=False)
106 self
.assertEquals(receivedResponse
, None)
109 class TestRoutingRoundRobinLB(DNSDistTest
):
111 _testServer2Port
= 5351
112 _config_params
= ['_testServerPort', '_testServer2Port']
113 _config_template
= """
114 setServerPolicy(roundrobin)
115 s1 = newServer{address="127.0.0.1:%s"}
117 s2 = newServer{address="127.0.0.1:%s"}
122 def startResponders(cls
):
123 print("Launching responders..")
124 cls
._UDPResponder
= threading
.Thread(name
='UDP Responder', target
=cls
.UDPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
125 cls
._UDPResponder
.setDaemon(True)
126 cls
._UDPResponder
.start()
127 cls
._UDPResponder
2 = threading
.Thread(name
='UDP Responder 2', target
=cls
.UDPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
128 cls
._UDPResponder
2.setDaemon(True)
129 cls
._UDPResponder
2.start()
131 cls
._TCPResponder
= threading
.Thread(name
='TCP Responder', target
=cls
.TCPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
132 cls
._TCPResponder
.setDaemon(True)
133 cls
._TCPResponder
.start()
135 cls
._TCPResponder
2 = threading
.Thread(name
='TCP Responder 2', target
=cls
.TCPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
136 cls
._TCPResponder
2.setDaemon(True)
137 cls
._TCPResponder
2.start()
143 Send 10 A queries to "rr.routing.tests.powerdns.com.",
144 check that dnsdist routes half of it to each backend.
147 name
= 'rr.routing.tests.powerdns.com.'
148 query
= dns
.message
.make_query(name
, 'A', 'IN')
149 response
= dns
.message
.make_response(query
)
150 rrset
= dns
.rrset
.from_text(name
,
155 response
.answer
.append(rrset
)
157 # the round robin counter is shared for UDP and TCP,
158 # so we need to do UDP then TCP to have a clean count
159 for _
in range(numberOfQueries
):
160 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
161 receivedQuery
.id = query
.id
162 self
.assertEquals(query
, receivedQuery
)
163 self
.assertEquals(response
, receivedResponse
)
165 for _
in range(numberOfQueries
):
166 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
167 receivedQuery
.id = query
.id
168 self
.assertEquals(query
, receivedQuery
)
169 self
.assertEquals(response
, receivedResponse
)
171 for key
in self
._responsesCounter
:
172 value
= self
._responsesCounter
[key
]
173 self
.assertEquals(value
, numberOfQueries
/ 2)
175 class TestRoutingRoundRobinLBOneDown(DNSDistTest
):
177 _testServer2Port
= 5351
178 _config_params
= ['_testServerPort', '_testServer2Port']
179 _config_template
= """
180 setServerPolicy(roundrobin)
181 s1 = newServer{address="127.0.0.1:%s"}
183 s2 = newServer{address="127.0.0.1:%s"}
187 def testRRWithOneDown(self
):
189 Routing: Round Robin with one server down
191 Send 100 A queries to "rr.routing.tests.powerdns.com.",
192 check that dnsdist routes all of it to the only backend up.
195 name
= 'rr.routing.tests.powerdns.com.'
196 query
= dns
.message
.make_query(name
, 'A', 'IN')
197 response
= dns
.message
.make_response(query
)
198 rrset
= dns
.rrset
.from_text(name
,
203 response
.answer
.append(rrset
)
205 # the round robin counter is shared for UDP and TCP,
206 # so we need to do UDP then TCP to have a clean count
207 for _
in range(numberOfQueries
):
208 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
209 receivedQuery
.id = query
.id
210 self
.assertEquals(query
, receivedQuery
)
211 self
.assertEquals(response
, receivedResponse
)
213 for _
in range(numberOfQueries
):
214 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
215 receivedQuery
.id = query
.id
216 self
.assertEquals(query
, receivedQuery
)
217 self
.assertEquals(response
, receivedResponse
)
220 for key
in self
._responsesCounter
:
221 value
= self
._responsesCounter
[key
]
222 self
.assertTrue(value
== numberOfQueries
or value
== 0)
225 self
.assertEquals(total
, numberOfQueries
* 2)
227 class TestRoutingOrder(DNSDistTest
):
229 _testServer2Port
= 5351
230 _config_params
= ['_testServerPort', '_testServer2Port']
231 _config_template
= """
232 setServerPolicy(firstAvailable)
233 s1 = newServer{address="127.0.0.1:%s", order=2}
235 s2 = newServer{address="127.0.0.1:%s", order=1}
240 def startResponders(cls
):
241 print("Launching responders..")
242 cls
._UDPResponder
= threading
.Thread(name
='UDP Responder', target
=cls
.UDPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
243 cls
._UDPResponder
.setDaemon(True)
244 cls
._UDPResponder
.start()
245 cls
._UDPResponder
2 = threading
.Thread(name
='UDP Responder 2', target
=cls
.UDPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
246 cls
._UDPResponder
2.setDaemon(True)
247 cls
._UDPResponder
2.start()
249 cls
._TCPResponder
= threading
.Thread(name
='TCP Responder', target
=cls
.TCPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
250 cls
._TCPResponder
.setDaemon(True)
251 cls
._TCPResponder
.start()
253 cls
._TCPResponder
2 = threading
.Thread(name
='TCP Responder 2', target
=cls
.TCPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
254 cls
._TCPResponder
2.setDaemon(True)
255 cls
._TCPResponder
2.start()
259 Routing: firstAvailable policy based on 'order'
261 Send 50 A queries to "order.routing.tests.powerdns.com.",
262 check that dnsdist routes all of it to the second backend
263 because it has the lower order value.
266 name
= 'order.routing.tests.powerdns.com.'
267 query
= dns
.message
.make_query(name
, 'A', 'IN')
268 response
= dns
.message
.make_response(query
)
269 rrset
= dns
.rrset
.from_text(name
,
274 response
.answer
.append(rrset
)
276 for _
in range(numberOfQueries
):
277 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
278 receivedQuery
.id = query
.id
279 self
.assertEquals(query
, receivedQuery
)
280 self
.assertEquals(response
, receivedResponse
)
281 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
282 receivedQuery
.id = query
.id
283 self
.assertEquals(query
, receivedQuery
)
284 self
.assertEquals(response
, receivedResponse
)
287 if 'UDP Responder' in self
._responsesCounter
:
288 self
.assertEquals(self
._responsesCounter
['UDP Responder'], 0)
289 self
.assertEquals(self
._responsesCounter
['UDP Responder 2'], numberOfQueries
)
290 if 'TCP Responder' in self
._responsesCounter
:
291 self
.assertEquals(self
._responsesCounter
['TCP Responder'], 0)
292 self
.assertEquals(self
._responsesCounter
['TCP Responder 2'], numberOfQueries
)
294 class TestRoutingNoServer(DNSDistTest
):
296 _config_template
= """
297 newServer{address="127.0.0.1:%s", pool="real"}
298 setServFailWhenNoServer(true)
301 def testPolicyPoolNoServer(self
):
303 Routing: No server should return ServFail
305 name
= 'noserver.routing.tests.powerdns.com.'
306 query
= dns
.message
.make_query(name
, 'A', 'IN')
307 expectedResponse
= dns
.message
.make_response(query
)
308 expectedResponse
.set_rcode(dns
.rcode
.SERVFAIL
)
310 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
311 self
.assertEquals(receivedResponse
, expectedResponse
)
313 (_
, receivedResponse
) = self
.sendTCPQuery(query
, response
=None, useQueue
=False)
314 self
.assertEquals(receivedResponse
, expectedResponse
)
317 class TestRoutingWRandom(DNSDistTest
):
319 _testServer2Port
= 5351
320 _config_params
= ['_testServerPort', '_testServer2Port']
321 _config_template
= """
322 setServerPolicy(wrandom)
323 s1 = newServer{address="127.0.0.1:%s", weight=1}
325 s2 = newServer{address="127.0.0.1:%s", weight=2}
330 def startResponders(cls
):
331 print("Launching responders..")
332 cls
._UDPResponder
= threading
.Thread(name
='UDP Responder', target
=cls
.UDPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
333 cls
._UDPResponder
.setDaemon(True)
334 cls
._UDPResponder
.start()
335 cls
._UDPResponder
2 = threading
.Thread(name
='UDP Responder 2', target
=cls
.UDPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
336 cls
._UDPResponder
2.setDaemon(True)
337 cls
._UDPResponder
2.start()
339 cls
._TCPResponder
= threading
.Thread(name
='TCP Responder', target
=cls
.TCPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
340 cls
._TCPResponder
.setDaemon(True)
341 cls
._TCPResponder
.start()
343 cls
._TCPResponder
2 = threading
.Thread(name
='TCP Responder 2', target
=cls
.TCPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
344 cls
._TCPResponder
2.setDaemon(True)
345 cls
._TCPResponder
2.start()
347 def testWRandom(self
):
351 Send 100 A queries to "rr.routing.tests.powerdns.com.",
352 check that dnsdist routes less than half to one, more to the other.
354 numberOfQueries
= 100
355 name
= 'rr.routing.tests.powerdns.com.'
356 query
= dns
.message
.make_query(name
, 'A', 'IN')
357 response
= dns
.message
.make_response(query
)
358 rrset
= dns
.rrset
.from_text(name
,
363 response
.answer
.append(rrset
)
365 # the counter is shared for UDP and TCP,
366 # so we need to do UDP then TCP to have a clean count
367 for _
in range(numberOfQueries
):
368 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
369 receivedQuery
.id = query
.id
370 self
.assertEquals(query
, receivedQuery
)
371 self
.assertEquals(response
, receivedResponse
)
373 for _
in range(numberOfQueries
):
374 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
375 receivedQuery
.id = query
.id
376 self
.assertEquals(query
, receivedQuery
)
377 self
.assertEquals(response
, receivedResponse
)
379 # The lower weight downstream should receive less than half the queries
380 self
.assertTrue(self
._responsesCounter
['UDP Responder'] < numberOfQueries
* 0.50)
381 self
.assertTrue(self
._responsesCounter
['TCP Responder'] < numberOfQueries
* 0.50)
383 # The higher weight downstream should receive more than half the queries
384 self
.assertTrue(self
._responsesCounter
['UDP Responder 2'] > numberOfQueries
* 0.50)
385 self
.assertTrue(self
._responsesCounter
['TCP Responder 2'] > numberOfQueries
* 0.50)
388 class TestRoutingHighValueWRandom(DNSDistTest
):
390 _testServer2Port
= 5351
391 _consoleKey
= DNSDistTest
.generateConsoleKey()
392 _consoleKeyB64
= base64
.b64encode(_consoleKey
).decode('ascii')
393 _config_params
= ['_consoleKeyB64', '_consolePort', '_testServerPort', '_testServer2Port']
394 _config_template
= """
396 controlSocket("127.0.0.1:%s")
397 setServerPolicy(wrandom)
398 s1 = newServer{address="127.0.0.1:%s", weight=2000000000}
400 s2 = newServer{address="127.0.0.1:%s", weight=2000000000}
405 def startResponders(cls
):
406 print("Launching responders..")
407 cls
._UDPResponder
= threading
.Thread(name
='UDP Responder', target
=cls
.UDPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
408 cls
._UDPResponder
.setDaemon(True)
409 cls
._UDPResponder
.start()
410 cls
._UDPResponder
2 = threading
.Thread(name
='UDP Responder 2', target
=cls
.UDPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
411 cls
._UDPResponder
2.setDaemon(True)
412 cls
._UDPResponder
2.start()
414 cls
._TCPResponder
= threading
.Thread(name
='TCP Responder', target
=cls
.TCPResponder
, args
=[cls
._testServerPort
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
415 cls
._TCPResponder
.setDaemon(True)
416 cls
._TCPResponder
.start()
418 cls
._TCPResponder
2 = threading
.Thread(name
='TCP Responder 2', target
=cls
.TCPResponder
, args
=[cls
._testServer
2Port
, cls
._toResponderQueue
, cls
._fromResponderQueue
])
419 cls
._TCPResponder
2.setDaemon(True)
420 cls
._TCPResponder
2.start()
422 def testHighValueWRandom(self
):
426 Send 100 A queries to "rr.routing.tests.powerdns.com.",
427 check that dnsdist routes to each downstream, rather than failing with
430 numberOfQueries
= 100
431 name
= 'rr.routing.tests.powerdns.com.'
432 query
= dns
.message
.make_query(name
, 'A', 'IN')
433 response
= dns
.message
.make_response(query
)
434 rrset
= dns
.rrset
.from_text(name
,
439 response
.answer
.append(rrset
)
441 # the counter is shared for UDP and TCP,
442 # so we need to do UDP then TCP to have a clean count
443 for _
in range(numberOfQueries
):
444 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
445 receivedQuery
.id = query
.id
446 self
.assertEquals(query
, receivedQuery
)
447 self
.assertEquals(response
, receivedResponse
)
449 for _
in range(numberOfQueries
):
450 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
451 receivedQuery
.id = query
.id
452 self
.assertEquals(query
, receivedQuery
)
453 self
.assertEquals(response
, receivedResponse
)
455 stats
= self
.sendConsoleCommand("dumpStats()").split()
458 # Map to a dict with every other element being the value to the previous one
459 for i
, x
in enumerate(stats
):
461 stats_dict
[x
] = stats
[i
+1]
463 # There should be no queries getting "no-policy" responses
464 self
.assertEquals(stats_dict
['no-policy'], '0')
466 # Each downstream should receive some queries, but it will be unbalanced
467 # The first downstream will receive more than half the queries
468 self
.assertTrue(self
._responsesCounter
['UDP Responder'] > numberOfQueries
/ 2)
469 self
.assertTrue(self
._responsesCounter
['TCP Responder'] > numberOfQueries
/ 2)
471 # The second downstream will receive the remainder of the queries, more than 0
472 self
.assertTrue(self
._responsesCounter
['UDP Responder 2'] > 0)
473 self
.assertTrue(self
._responsesCounter
['TCP Responder 2'] > 0)
474 self
.assertEquals(self
._responsesCounter
['UDP Responder 2'], numberOfQueries
- self
._responsesCounter
['UDP Responder'])
475 self
.assertEquals(self
._responsesCounter
['TCP Responder 2'], numberOfQueries
- self
._responsesCounter
['TCP Responder'])
478 class TestRoutingBadWeightWRandom(DNSDistTest
):
480 _testServer2Port
= 5351
481 _consoleKey
= DNSDistTest
.generateConsoleKey()
482 _consoleKeyB64
= base64
.b64encode(_consoleKey
).decode('ascii')
483 _config_params
= ['_consoleKeyB64', '_consolePort', '_testServerPort', '_testServer2Port']
484 _config_template
= """
486 controlSocket("127.0.0.1:%s")
487 setServerPolicy(wrandom)
488 s1 = newServer{address="127.0.0.1:%s", weight=-1}
489 s2 = newServer{address="127.0.0.1:%s", weight=2147483648}
492 def testBadWeightWRandom(self
):
496 Test that downstreams cannot be added with invalid weights.
498 # There should be no downstreams
499 self
.assertTrue(self
.sendConsoleCommand("getServer(0)").startswith("Error"))