我正在尝试创建一个使用DNS查询执行某些测试的测试。我试图创建一个最小的测试,它启动一个侦听DNS服务器,并使用扭曲的解析器来查询该服务器:
from twisted.trial import unittest
from twisted.internet import reactor, defer
from twisted.names import client, dns, error, server
class Tester(unittest.TestCase):
def setUp(self):
self.resolver = client.Resolver(resolv='/etc/resolv.conf')
self.resolver = client.Resolver(servers=[('127.0.0.1', 1025)])
self.factory = server.DNSServerFactory(clients=[self.resolver])
self.protocol = dns.DNSDatagramProtocol(controller=self.factory)
self.port = reactor.listenUDP(1025, self.protocol)
def tearDown(self):
self.port.stopListening()
def test_test(self):
def callback(ignore):
print("Received callback!")
res = client.createResolver(servers=[('127.0.0.1', 1025)], resolvconf='/dev/null', hosts='/dev/null')
d = res.lookupAddress('foobar.com')
d.addCallback(callback)
运行此测试会导致以下错误:
[ERROR]
Traceback (most recent call last):
Failure: twisted.trial.util.DirtyReactorAggregateError: Reactor was unclean.
DelayedCalls: (set twisted.internet.base.DelayedCall.debug = True to debug)
<DelayedCall 0x7f44c69042e8 [0.9992678165435791s] called=0 cancelled=0
DNSMixin._clearFailed(<Deferred at 0x7f44c6904358>, 28457)>
<DelayedCall 0x7f44c68f3e10 [59.99872899055481s] called=0 cancelled=0 Resolver.maybeParseConfig()>
test.Tester.test_test
==================================================================
[ERROR]
Traceback (most recent call last):
Failure: twisted.trial.util.DirtyReactorAggregateError: Reactor was
unclean.
Selectables:
<<class 'twisted.names.dns.DNSDatagramProtocol'> on 34529>
test.Tester.test_test
-------------------------------------------------------------------------------
Ran 1 tests in 0.003s
所以看起来反应堆没有从test_test中解析器发送的消息中清除。
我不明白为什么会这样。文件说试运行反应堆,我不应该碰它。我是否错误地使用了测试框架?
答案 0 :(得分:0)
您可能不应该在测试套件中进行真正的网络流量。真正的网络是片状的,依赖它的测试套件往往容易出错并且令人沮丧。你并不是真的希望你的测试运行失败只是因为systemd-resolved已经更新并开始对它注意到的一些DNS流量做一些古怪的事情。
避免实际网络流量的主要策略是将接口的替代实施方式设置在您正在测试的接口的一个级别之下 - 这种实现根本不使用真实网络。我的首选策略是使用简单的内存中对象模拟网络行为。如果需要,您可以针对实际和内存实现运行针对该较低级别的测试套件,并验证两个实现是否相同&#34;至少到某一点。
那就是说,tearDown
中存在一个简单的错误。它会调用stopListening
,返回Deferred
,但它不会返回Deferred
本身。因此,试验决定在tearDown
返回时进行清理,但可能尚未完成。退回stopListening
Deferred
,您可以避免一个的不洁错误。
test_test
中存在类似的错误。它不会返回d
,因此一旦方法返回,试验就会决定测试结束(成功)。返回d
,当d
触发时,它将决定测试结束(只有在成功结果触发时才通过测试)。
答案 1 :(得分:0)
使用扭曲解决DNS请求时,我遇到了类似的问题。
我的问题是,twisted每60秒保持一次循环调用,以检查resolv.conf文件。
这是通过this line中的maybeParseConfig
方法完成的
self._parseCall = self._reactor.callLater(self._resolvReadInterval, self.maybeParseConfig)
此self._parseCall
保留了导致您的反应堆不干净的延迟呼叫。
因此,即使我同意@Jean的回答,我也不想立即创建自己的假DNS解析器并想出一种解决方法
首先,您需要使用扭曲的旋转变压器:
import twisted.names.client
resolver_chain = twisted.names.client.getResolver()
这将返回一个twisted.names.resolve.ResolverChain
,在我的情况下,该列表在resolvers
属性中具有一个包含3个解析器的列表。需要清除的是twisted.names.client.Resolver
中的一个,在我的情况下是第3个。
resolver = resolver_chain.resolvers[2]
resolver._parseCall.cancel()
您只需要在测试完成后取消通话,反应堆就可以干净了。