试验测试DNS查询使反应堆处于不洁状态

时间:2017-12-30 12:24:47

标签: dns twisted

我正在尝试创建一个使用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中解析器发送的消息中清除。

我不明白为什么会这样。文件说试运行反应堆,我不应该碰它。我是否错误地使用了测试框架?

2 个答案:

答案 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()

您只需要在测试完成后取消通话,反应堆就可以干净了。