diff options
author | Brian Wellington <bwelling@xbill.org> | 2020-07-01 10:35:12 -0700 |
---|---|---|
committer | Brian Wellington <bwelling@xbill.org> | 2020-07-01 10:35:12 -0700 |
commit | 8521b63293bf704412c67ef69cee0a1e2ad47298 (patch) | |
tree | 49d901b8f9b63e1184ecd433fb090b59c8189678 | |
parent | 7482b94a28dfcd9a98a3518effcec2a6085235d1 (diff) | |
parent | 5765181c220b96b1543395faaf5e43eb778a45ff (diff) | |
download | dnspython-8521b63293bf704412c67ef69cee0a1e2ad47298.tar.gz |
Merge remote-tracking branch 'upstream/master' into amtrelay
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | azure-pipelines.yml | 19 | ||||
-rw-r--r-- | codecov.yml | 5 | ||||
-rw-r--r-- | dns/dnssec.py | 2 | ||||
-rw-r--r-- | dns/message.pyi | 5 | ||||
-rw-r--r-- | dns/resolver.py | 100 | ||||
-rw-r--r-- | dns/version.py | 2 | ||||
-rw-r--r-- | doc/whatsnew.rst | 9 | ||||
-rw-r--r-- | pyproject.toml | 2 | ||||
-rwxr-xr-x | setup.py | 2 | ||||
-rw-r--r-- | tests/test_query.py | 60 | ||||
-rw-r--r-- | tests/test_resolver.py | 58 | ||||
-rw-r--r-- | tox.ini | 46 |
14 files changed, 192 insertions, 122 deletions
diff --git a/.travis.yml b/.travis.yml index 2d416a5..584f4a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,6 @@ install: - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - ~/.poetry/bin/poetry install -E dnssec -E doh -E idna -E trio -E curio script: - - ~/.poetry/bin/poetry run pytest --cov=dns --cov-report=xml:coverage.xml + - ~/.poetry/bin/poetry run pytest --cov=. --cov-report=xml:coverage.xml after_success: - bash <(curl -s https://codecov.io/bash) @@ -30,7 +30,7 @@ to facilitate the testing of DNS software. ## ABOUT THIS RELEASE -This is the dnspython 2.0.0 development branch. +This is dnspython 2.0.0rc2. Please read [What's New](https://dnspython.readthedocs.io/en/latest/whatsnew.html) for information about the changes in this release. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8af2647..5185c7c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -23,7 +23,11 @@ jobs: - script: | python -m pip install --upgrade pip pip install -e .[dnssec,idna,doh,trio,curio] - displayName: 'Install dependencies' + displayName: 'Install python dependencies' + + - script: | + dotnet tool install --global Codecov.Tool + displayName: 'Install Codecov.Tool' - script: | pip install pytest pytest-cov pytest-azurepipelines @@ -36,8 +40,11 @@ jobs: testResultsFiles: '**/test-*.xml' testRunTitle: 'Publish test results for Python $(python.version)' - - task: PublishCodeCoverageResults@1 - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml' - reportDirectory: '$(System.DefaultWorkingDirectory)/**/htmlcov' +# - task: PublishCodeCoverageResults@1 +# inputs: +# codeCoverageTool: Cobertura +# summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml' + + - script: | + codecov -f coverage.xml + displayName: 'Upload to codecov' diff --git a/codecov.yml b/codecov.yml index 1b44632..002b105 100644 --- a/codecov.yml +++ b/codecov.yml @@ -4,3 +4,8 @@ coverage: default: target: auto threshold: 2% +ignore: + - 'tests/*' + - 'examples/*' + - 'doc/*' + - 'setup.py' diff --git a/dns/dnssec.py b/dns/dnssec.py index 0be9f71..c50abf8 100644 --- a/dns/dnssec.py +++ b/dns/dnssec.py @@ -423,7 +423,7 @@ def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None): # since if the algorithm is really unknown we'd already have # raised an exception above raise ValidationFailure('unknown algorithm %u' % - rrsig.algorithm) # pragma: no cover + rrsig.algorithm) # pragma: no cover # If we got here, we successfully verified so we can return # without error return diff --git a/dns/message.pyi b/dns/message.pyi index 8829db3..c939b52 100644 --- a/dns/message.pyi +++ b/dns/message.pyi @@ -12,10 +12,7 @@ class Message: def __init__(self, id : Optional[int] =None) -> None: self.id : int self.flags = 0 - self.question : List[rrset.RRset] = [] - self.answer : List[rrset.RRset] = [] - self.authority : List[rrset.RRset] = [] - self.additional : List[rrset.RRset] = [] + self.sections : List[List[rrset.RRset]] = [[], [], [], []] self.opt : rrset.RRset = None self.request_payload = 0 self.keyring = None diff --git a/dns/resolver.py b/dns/resolver.py index 6c6f502..f4a07b4 100644 --- a/dns/resolver.py +++ b/dns/resolver.py @@ -780,22 +780,22 @@ class Resolver: if len(self.nameservers) == 0: raise NoResolverConfiguration - def _determine_split_char(self, entry): # pragma: no cover + def _determine_split_char(self, entry): # # The windows registry irritatingly changes the list element # delimiter in between ' ' and ',' (and vice-versa) in various # versions of windows. # - if entry.find(' ') >= 0: + if entry.find(' ') >= 0: # pragma: no cover split_char = ' ' - elif entry.find(',') >= 0: + elif entry.find(',') >= 0: # pragma: no cover split_char = ',' else: # probably a singleton; treat as a space-separated list. split_char = ' ' return split_char - def _config_win32_nameservers(self, nameservers): # pragma: no cover + def _config_win32_nameservers(self, nameservers): # we call str() on nameservers to convert it from unicode to ascii nameservers = str(nameservers) split_char = self._determine_split_char(nameservers) @@ -817,7 +817,7 @@ class Resolver: if s not in self.search: self.search.append(dns.name.from_text(s)) - def _config_win32_fromkey(self, key, always_try_domain): # pragma: no cover + def _config_win32_fromkey(self, key, always_try_domain): try: servers, rtype = winreg.QueryValueEx(key, 'NameServer') except WindowsError: # pylint: disable=undefined-variable @@ -829,76 +829,66 @@ class Resolver: dom, rtype = winreg.QueryValueEx(key, 'Domain') if dom: self._config_win32_domain(dom) - except WindowsError: # pylint: disable=undefined-variable + except WindowsError: # pragma: no cover pass else: try: servers, rtype = winreg.QueryValueEx(key, 'DhcpNameServer') - except WindowsError: # pylint: disable=undefined-variable + except WindowsError: # pragma: no cover servers = None - if servers: + if servers: # pragma: no cover self._config_win32_nameservers(servers) try: dom, rtype = winreg.QueryValueEx(key, 'DhcpDomain') - if dom: + if dom: # pragma: no cover self._config_win32_domain(dom) - except WindowsError: # pylint: disable=undefined-variable + except WindowsError: # pragma: no cover pass try: search, rtype = winreg.QueryValueEx(key, 'SearchList') except WindowsError: # pylint: disable=undefined-variable search = None - if search: + if search: # pragma: no cover self._config_win32_search(search) - def read_registry(self): # pragma: no cover + def read_registry(self): """Extract resolver configuration from the Windows registry.""" lm = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - want_scan = False try: - try: - # XP, 2000 - tcp_params = winreg.OpenKey(lm, - r'SYSTEM\CurrentControlSet' - r'\Services\Tcpip\Parameters') - want_scan = True - except EnvironmentError: - # ME - tcp_params = winreg.OpenKey(lm, - r'SYSTEM\CurrentControlSet' - r'\Services\VxD\MSTCP') + tcp_params = winreg.OpenKey(lm, + r'SYSTEM\CurrentControlSet' + r'\Services\Tcpip\Parameters') try: self._config_win32_fromkey(tcp_params, True) finally: tcp_params.Close() - if want_scan: - interfaces = winreg.OpenKey(lm, - r'SYSTEM\CurrentControlSet' - r'\Services\Tcpip\Parameters' - r'\Interfaces') - try: - i = 0 - while True: + interfaces = winreg.OpenKey(lm, + r'SYSTEM\CurrentControlSet' + r'\Services\Tcpip\Parameters' + r'\Interfaces') + try: + i = 0 + while True: + try: + guid = winreg.EnumKey(interfaces, i) + i += 1 + key = winreg.OpenKey(interfaces, guid) + if not self._win32_is_nic_enabled(lm, guid, key): + continue try: - guid = winreg.EnumKey(interfaces, i) - i += 1 - key = winreg.OpenKey(interfaces, guid) - if not self._win32_is_nic_enabled(lm, guid, key): - continue - try: - self._config_win32_fromkey(key, False) - finally: - key.Close() - except EnvironmentError: - break - finally: - interfaces.Close() + self._config_win32_fromkey(key, False) + finally: + key.Close() + except EnvironmentError: # pragma: no cover + break + finally: + interfaces.Close() finally: lm.Close() def _win32_is_nic_enabled(self, lm, guid, - interface_key): # pragma: no cover + interface_key): # Look in the Windows Registry to determine whether the network # interface corresponding to the given guid is enabled. # @@ -918,7 +908,7 @@ class Resolver: (pnp_id, ttype) = winreg.QueryValueEx( connection_key, 'PnpInstanceID') - if ttype != winreg.REG_SZ: + if ttype != winreg.REG_SZ: # pragma: no cover raise ValueError device_key = winreg.OpenKey( @@ -929,7 +919,7 @@ class Resolver: (flags, ttype) = winreg.QueryValueEx( device_key, 'ConfigFlags') - if ttype != winreg.REG_DWORD: + if ttype != winreg.REG_DWORD: # pragma: no cover raise ValueError # Based on experimentation, bit 0x1 indicates that the @@ -940,18 +930,8 @@ class Resolver: device_key.Close() finally: connection_key.Close() - except (EnvironmentError, ValueError): - # Pre-vista, enabled interfaces seem to have a non-empty - # NTEContextList; this was how dnspython detected enabled - # nics before the code above was contributed. We've retained - # the old method since we don't know if the code above works - # on Windows 95/98/ME. - try: - (nte, ttype) = winreg.QueryValueEx(interface_key, - 'NTEContextList') - return nte is not None - except WindowsError: # pylint: disable=undefined-variable - return False + except Exception: # pragma: no cover + return False def _compute_timeout(self, start, lifetime=None): lifetime = self.lifetime if lifetime is None else lifetime diff --git a/dns/version.py b/dns/version.py index d897395..dcdbbe0 100644 --- a/dns/version.py +++ b/dns/version.py @@ -24,7 +24,7 @@ MINOR = 0 #: MICRO MICRO = 0 #: RELEASELEVEL -RELEASELEVEL = 0x00 +RELEASELEVEL = 0x0c #: SERIAL SERIAL = 2 diff --git a/doc/whatsnew.rst b/doc/whatsnew.rst index 801e0f6..dd7e48d 100644 --- a/doc/whatsnew.rst +++ b/doc/whatsnew.rst @@ -64,3 +64,12 @@ What's New in dnspython 2.0.0 in the python 2 style on both python 2 and 3. * The resolver will now do negative caching if a cache has been configured. + +* TSIG and OPT now have rdata types. + +* The class for query messages is now QueryMessage. Class Message is now a + base class, and is also used for messages for which we don't have a better + class. Update messages are now class UpdateMessage, though class Update + is retained for compatibility. + +* Support for Windows 95, 98, and ME has been removed. diff --git a/pyproject.toml b/pyproject.toml index 21ca001..970d92f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "dnspython" -version = "2.0.0dev2" +version = "2.0.0rc2" description = "DNS toolkit" authors = ["Bob Halley <halley@dnspython.org>"] license = "ISC" @@ -20,7 +20,7 @@ import sys from setuptools import setup -version = '2.0.0dev2' +version = '2.0.0rc2' try: sys.argv.remove("--cython-compile") diff --git a/tests/test_query.py b/tests/test_query.py index 895dc0d..f1ec55c 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -16,6 +16,8 @@ # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import socket +import sys +import time import unittest try: @@ -236,6 +238,31 @@ class DestinationAndSourceTests(unittest.TestCase): (af, d, s) = _d_and_s('1::2', 53, None, 12345) self.assertEqual(s, ('::', 12345, 0, 0)) + +class AddressesEqualTestCase(unittest.TestCase): + + def test_v4(self): + self.assertTrue(dns.query._addresses_equal(socket.AF_INET, + ('10.0.0.1', 53), + ('10.0.0.1', 53))) + self.assertFalse(dns.query._addresses_equal(socket.AF_INET, + ('10.0.0.1', 53), + ('10.0.0.2', 53))) + + def test_v6(self): + self.assertTrue(dns.query._addresses_equal(socket.AF_INET6, + ('1::1', 53), + ('0001:0000::1', 53))) + self.assertFalse(dns.query._addresses_equal(socket.AF_INET6, + ('::1', 53), + ('::2', 53))) + + def test_mixed(self): + self.assertFalse(dns.query._addresses_equal(socket.AF_INET, + ('10.0.0.1', 53), + ('::2', 53))) + + axfr_zone = ''' $ORIGIN example. $TTL 300 @@ -482,3 +509,36 @@ class TsigTests(unittest.TestCase): self.assertTrue(rrs is not None) seen = set([rdata.address for rdata in rrs]) self.assertTrue('1.2.3.4' in seen) + +@unittest.skipIf(sys.platform == 'win32', + 'low level tests do not work on win32') +class LowLevelWaitTests(unittest.TestCase): + + def test_wait_for(self): + try: + (l, r) = socket.socketpair() + # already expired + with self.assertRaises(dns.exception.Timeout): + dns.query._wait_for(l, True, True, True, 0) + # simple timeout + with self.assertRaises(dns.exception.Timeout): + dns.query._wait_for(l, False, False, False, time.time() + 0.05) + # writable no timeout (not hanging is passing) + dns.query._wait_for(l, False, True, False, None) + finally: + l.close() + r.close() + + def test_select_for(self): + # we test this explicitly in case _wait_for didn't test it (i.e. + # if the default polling backing is _poll_for) + try: + (l, r) = socket.socketpair() + # simple timeout + self.assertFalse(dns.query._select_for(l, False, False, False, + 0.05)) + # writable no timeout + self.assertTrue(dns.query._select_for(l, False, True, False, None)) + finally: + l.close() + r.close() diff --git a/tests/test_resolver.py b/tests/test_resolver.py index 373ecb9..2a9c63d 100644 --- a/tests/test_resolver.py +++ b/tests/test_resolver.py @@ -64,6 +64,34 @@ search search1 search2 options rotate timeout:1 edns0 ndots:2 """ +bad_timeout_1 = """ +nameserver 10.0.0.1 +nameserver 10.0.0.2 +options rotate timeout +""" + +bad_timeout_2 = """ +nameserver 10.0.0.1 +nameserver 10.0.0.2 +options rotate timeout:bogus +""" + +bad_ndots_1 = """ +nameserver 10.0.0.1 +nameserver 10.0.0.2 +options rotate ndots +""" + +bad_ndots_2 = """ +nameserver 10.0.0.1 +nameserver 10.0.0.2 +options rotate ndots:bogus +""" + +no_nameservers = """ +options rotate +""" + message_text = """id 1234 opcode QUERY rcode NOERROR @@ -139,6 +167,36 @@ class BaseResolverTests(unittest.TestCase): self.assertEqual(r.ndots, 2) self.assertEqual(r.edns, 0) + def testReadOptionsBadTimeouts(self): + f = StringIO(bad_timeout_1) + r = dns.resolver.Resolver(configure=False) + r.read_resolv_conf(f) + # timeout should still be default + self.assertEqual(r.timeout, 2.0) + f = StringIO(bad_timeout_2) + r = dns.resolver.Resolver(configure=False) + r.read_resolv_conf(f) + # timeout should still be default + self.assertEqual(r.timeout, 2.0) + + def testReadOptionsBadNdots(self): + f = StringIO(bad_ndots_1) + r = dns.resolver.Resolver(configure=False) + r.read_resolv_conf(f) + # ndots should still be default + self.assertEqual(r.ndots, None) + f = StringIO(bad_ndots_2) + r = dns.resolver.Resolver(configure=False) + r.read_resolv_conf(f) + # ndots should still be default + self.assertEqual(r.ndots, None) + + def testReadNoNameservers(self): + f = StringIO(no_nameservers) + r = dns.resolver.Resolver(configure=False) + with self.assertRaises(dns.resolver.NoResolverConfiguration): + r.read_resolv_conf(f) + def testCacheExpiration(self): message = dns.message.from_text(message_text) name = dns.name.from_text('example.') diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 6417f2d..0000000 --- a/tox.ini +++ /dev/null @@ -1,46 +0,0 @@ -[tox] -envlist = - py36, - py37, - flake8, - pylint, - mypy, - coverage - -[testenv] - -commands= - python setup.py test - -deps= - -[testenv:flake8] -commands = - pip install flake8 - flake8 dns - -[testenv:pylint] -commands = - pip install pylint - pylint dns - -[testenv:mypy] -commands = - pip install mypy - mypy examples tests - -[testenv:coverage] -basepython = python2 - -deps = - coverage - -commands = - python setup.py install - coverage run --rcfile=.coverage.ini setup.py test - coverage report - -[pep8] -show-pep8 = True -show-source = True - |