Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,5 @@ jobs:
pip install .
- name: Run tests
run: make ci
env:
SKIP_IPV6: 1
- name: Report coverage to Codecov
uses: codecov/codecov-action@v1
39 changes: 32 additions & 7 deletions zeroconf/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
import time
import unittest
import unittest.mock
from functools import lru_cache
from threading import Event
from typing import Dict, Optional, cast # noqa # used in type hints

import ifaddr

import pytest

import zeroconf as r
Expand Down Expand Up @@ -57,6 +60,28 @@ def teardown_module():
log.setLevel(original_logging_level)


@lru_cache(maxsize=None)
def has_working_ipv6():
"""Return True if if the system can bind an IPv6 address."""
if not socket.has_ipv6:
return False

try:
sock = socket.socket(socket.AF_INET6)
sock.bind(('::1', 0))
except Exception:
return False
finally:
if sock:
sock.close()

for iface in ifaddr.get_adapters():
for addr in iface.ips:
if addr.is_IPv6 and iface.index is not None:
return True
return False


class TestDunder(unittest.TestCase):
def test_dns_text_repr(self):
# There was an issue on Python 3 that prevented DNSText's repr
Expand Down Expand Up @@ -550,15 +575,15 @@ def test_close_multiple_times(self):
rv.close()
rv.close()

@unittest.skipIf(not socket.has_ipv6, 'Requires IPv6')
@unittest.skipIf(not has_working_ipv6(), 'Requires IPv6')
@unittest.skipIf(os.environ.get('SKIP_IPV6'), 'IPv6 tests disabled')
def test_launch_and_close_v4_v6(self):
rv = r.Zeroconf(interfaces=r.InterfaceChoice.All, ip_version=r.IPVersion.All)
rv.close()
rv = r.Zeroconf(interfaces=r.InterfaceChoice.Default, ip_version=r.IPVersion.All)
rv.close()

@unittest.skipIf(not socket.has_ipv6, 'Requires IPv6')
@unittest.skipIf(not has_working_ipv6(), 'Requires IPv6')
@unittest.skipIf(os.environ.get('SKIP_IPV6'), 'IPv6 tests disabled')
def test_launch_and_close_v6_only(self):
rv = r.Zeroconf(interfaces=r.InterfaceChoice.All, ip_version=r.IPVersion.V6Only)
Expand Down Expand Up @@ -1092,7 +1117,7 @@ def test_integration_with_listener(self):
finally:
zeroconf_registrar.close()

@unittest.skipIf(not socket.has_ipv6, 'Requires IPv6')
@unittest.skipIf(not has_working_ipv6(), 'Requires IPv6')
@unittest.skipIf(os.environ.get('SKIP_IPV6'), 'IPv6 tests disabled')
def test_integration_with_listener_v6_records(self):

Expand Down Expand Up @@ -1124,7 +1149,7 @@ def test_integration_with_listener_v6_records(self):
finally:
zeroconf_registrar.close()

@unittest.skipIf(not socket.has_ipv6, 'Requires IPv6')
@unittest.skipIf(not has_working_ipv6(), 'Requires IPv6')
@unittest.skipIf(os.environ.get('SKIP_IPV6'), 'IPv6 tests disabled')
def test_integration_with_listener_ipv6(self):

Expand Down Expand Up @@ -1240,7 +1265,7 @@ def update_service(self, zeroconf, type, name):
desc = {'path': '/~paulsm/'} # type: Dict
desc.update(properties)
addresses = [socket.inet_aton("10.0.1.2")]
if socket.has_ipv6 and not os.environ.get('SKIP_IPV6'):
if has_working_ipv6() and not os.environ.get('SKIP_IPV6'):
addresses.append(socket.inet_pton(socket.AF_INET6, "2001:db8::1"))
info_service = ServiceInfo(
subtype, registration_name, port=80, properties=desc, server="ash-2.local.", addresses=addresses
Expand Down Expand Up @@ -1344,7 +1369,7 @@ def update_service(self, zeroconf, type, name):

class TestServiceBrowser(unittest.TestCase):
def test_update_record(self):
enable_ipv6 = socket.has_ipv6 and not os.environ.get('SKIP_IPV6')
enable_ipv6 = has_working_ipv6() and not os.environ.get('SKIP_IPV6')

service_name = 'name._type._tcp.local.'
service_type = '_type._tcp.local.'
Expand Down Expand Up @@ -2110,7 +2135,7 @@ def test_multiple_addresses():
)
assert info.addresses == [address, address]

if socket.has_ipv6 and not os.environ.get('SKIP_IPV6'):
if has_working_ipv6() and not os.environ.get('SKIP_IPV6'):
address_v6_parsed = "2001:db8::1"
address_v6 = socket.inet_pton(socket.AF_INET6, address_v6_parsed)
infos = [
Expand Down