Source code for dhcpkit.tests.ipv6.extensions.test_ntp

"""
Test the NTP option implementation
"""
import unittest
from ipaddress import IPv6Address

from dhcpkit.ipv6.extensions.ntp import NTPMulticastAddressSubOption, NTPServerAddressSubOption, \
    NTPServerFQDNSubOption, NTPServersOption, NTPSubOption, UnknownNTPSubOption
from dhcpkit.tests.ipv6.options import test_option


[docs]class NTPServersOptionTestCase(test_option.OptionTestCase):
[docs] def setUp(self): self.option_bytes = bytes.fromhex('0038004b' '0001001020010db8000000000000000000000001' '00020010ff12000000000000000000000000abcd' '00030011') + b'\x03ntp\x08steffann\x02nl\x00' + \ bytes.fromhex('ffff000a') + b'RandomData' self.option_object = NTPServersOption(options=[ NTPServerAddressSubOption(IPv6Address('2001:db8::1')), NTPMulticastAddressSubOption(IPv6Address('ff12::abcd')), NTPServerFQDNSubOption('ntp.steffann.nl.'), UnknownNTPSubOption(65535, b'RandomData'), ]) self.parse_option()
[docs] def test_parse_wrong_type(self): with self.assertRaisesRegex(ValueError, 'does not contain NTPServerAddressSubOption data'): option = NTPServerAddressSubOption() option.load_from(b'00020010ff12000000000000000000000000abcd')
[docs] def test_bad_option_length(self): with self.assertRaisesRegex(ValueError, 'does not match the combined length'): NTPServersOption.parse(bytes.fromhex('003800130001001020010db8000000000000000000000001'))
[docs]class NTPSubOptionTestCase(test_option.OptionTestCase):
[docs] def setUp(self): self.option_bytes = bytes.fromhex('ffff000a') + b'RandomData' self.option_object = UnknownNTPSubOption(65535, b'RandomData') self.parse_option()
[docs] def parse_option(self): self.length, self.option = NTPSubOption.parse(self.option_bytes) self.assertIsInstance(self.option, NTPSubOption) self.option_class = type(self.option)
[docs] def test_load_from_wrong_buffer(self): if issubclass(self.option_class, UnknownNTPSubOption): # UnknownNTPSubOption accepts any parseable buffer, no point in testing that one return super().test_load_from_wrong_buffer()
[docs]class UnknownNTPSubOptionTestCase(NTPSubOptionTestCase):
[docs] def test_validate_suboption_type(self): self.check_unsigned_integer_property('suboption_type', size=16)
[docs] def test_validate_value(self): self.option.suboption_data = bytes.fromhex('00112233') self.assertEqual(self.option.value, '00112233')
[docs] def test_validate_suboption_data(self): self.option.suboption_data = b'AB' self.option.validate() self.option.suboption_data = 'ABC' with self.assertRaisesRegex(ValueError, 'sequence of bytes'): self.option.validate()
[docs]class NTPServerAddressSubOptionTestCase(NTPSubOptionTestCase):
[docs] def setUp(self): self.option_bytes = bytes.fromhex('0001001020010db8000000000000000000000001') self.option_object = NTPServerAddressSubOption(IPv6Address('2001:db8::1')) self.parse_option()
[docs] def test_config_datatype(self): value = NTPServerAddressSubOption.config_datatype('2001:db8::1') self.assertEqual(value, IPv6Address('2001:db8::1')) with self.assertRaisesRegex(ValueError, 'routable IPv6 address'): NTPServerAddressSubOption.config_datatype('::') with self.assertRaisesRegex(ValueError, 'routable IPv6 address'): NTPServerAddressSubOption.config_datatype('::1') with self.assertRaisesRegex(ValueError, 'routable IPv6 address'): NTPServerAddressSubOption.config_datatype('fe80::1') with self.assertRaisesRegex(ValueError, 'routable IPv6 address'): NTPServerAddressSubOption.config_datatype('ff02::1')
[docs] def test_validate_value(self): self.option.address = IPv6Address('2001:0db8::0001') self.assertEqual(self.option.value, '2001:db8::1')
[docs] def test_validate_address(self): self.option.address = bytes.fromhex('20010db8000000000000000000000001') with self.assertRaisesRegex(ValueError, 'routable IPv6 address'): self.option.validate() self.option.address = IPv6Address('2001:db8::1') self.option.validate() self.option.address = IPv6Address('::') with self.assertRaisesRegex(ValueError, 'routable IPv6 address'): self.option.validate() self.option.address = IPv6Address('::1') with self.assertRaisesRegex(ValueError, 'routable IPv6 address'): self.option.validate() self.option.address = IPv6Address('fe80::1') with self.assertRaisesRegex(ValueError, 'routable IPv6 address'): self.option.validate() self.option.address = IPv6Address('ff02::1') with self.assertRaisesRegex(ValueError, 'routable IPv6 address'): self.option.validate()
[docs] def test_bad_option_length(self): with self.assertRaisesRegex(ValueError, 'must have length 16'): NTPServerAddressSubOption.parse(bytes.fromhex('0001000f')) with self.assertRaisesRegex(ValueError, 'must have length 16'): NTPServerAddressSubOption.parse(bytes.fromhex('00010011'))
[docs]class NTPMulticastAddressSubOptionTestCase(NTPSubOptionTestCase):
[docs] def setUp(self): self.option_bytes = bytes.fromhex('00020010ff12000000000000000000000000abcd') self.option_object = NTPMulticastAddressSubOption(IPv6Address('ff12::abcd')) self.parse_option()
[docs] def test_config_datatype(self): value = NTPMulticastAddressSubOption.config_datatype('ff02::1') self.assertEqual(value, IPv6Address('ff02::1')) with self.assertRaisesRegex(ValueError, 'multicast IPv6 address'): NTPMulticastAddressSubOption.config_datatype('::') with self.assertRaisesRegex(ValueError, 'multicast IPv6 address'): NTPMulticastAddressSubOption.config_datatype('::1') with self.assertRaisesRegex(ValueError, 'multicast IPv6 address'): NTPMulticastAddressSubOption.config_datatype('fe80::1') with self.assertRaisesRegex(ValueError, 'multicast IPv6 address'): NTPMulticastAddressSubOption.config_datatype('2001:db8::1')
[docs] def test_validate_value(self): self.option.address = IPv6Address('ff02:0db8::0001') self.assertEqual(self.option.value, 'ff02:db8::1')
[docs] def test_validate_address(self): self.option.address = bytes.fromhex('20010db8000000000000000000000001') with self.assertRaisesRegex(ValueError, 'multicast IPv6 address'): self.option.validate() self.option.address = IPv6Address('ff02::1') self.option.validate() self.option.address = IPv6Address('::') with self.assertRaisesRegex(ValueError, 'multicast IPv6 address'): self.option.validate() self.option.address = IPv6Address('::1') with self.assertRaisesRegex(ValueError, 'multicast IPv6 address'): self.option.validate() self.option.address = IPv6Address('fe80::1') with self.assertRaisesRegex(ValueError, 'multicast IPv6 address'): self.option.validate() self.option.address = IPv6Address('2001:db8::1') with self.assertRaisesRegex(ValueError, 'multicast IPv6 address'): self.option.validate()
[docs] def test_bad_option_length(self): with self.assertRaisesRegex(ValueError, 'must have length 16'): NTPMulticastAddressSubOption.parse(bytes.fromhex('0002000f')) with self.assertRaisesRegex(ValueError, 'must have length 16'): NTPMulticastAddressSubOption.parse(bytes.fromhex('00020011'))
[docs]class NTPServerFQDNSubOptionTestCase(NTPSubOptionTestCase):
[docs] def setUp(self): self.option_bytes = bytes.fromhex('00030011') + b'\x03ntp\x08steffann\x02nl\x00' self.option_object = NTPServerFQDNSubOption('ntp.steffann.nl.') self.parse_option()
[docs] def test_config_datatype(self): value = NTPServerFQDNSubOption.config_datatype('ntp.steffann.nl') self.assertEqual(value, 'ntp.steffann.nl') with self.assertRaisesRegex(ValueError, 'Invalid label'): NTPServerFQDNSubOption.config_datatype('something that is not a domain name') with self.assertRaisesRegex(ValueError, 'Invalid label'): NTPServerFQDNSubOption.config_datatype('something..bad') with self.assertRaisesRegex(ValueError, 'Label too long'): NTPServerFQDNSubOption.config_datatype('steffann-steffann-steffann-steffann-' 'steffann-steffann-steffann-steffann.bad')
[docs] def test_validate_value(self): self.option.fqdn = 'example.com' self.assertEqual(self.option.value, 'example.com')
[docs] def test_validate_fqdn(self): self.option.fqdn = ['steffann.nl'] with self.assertRaisesRegex(ValueError, 'must be a string'): self.option.validate() self.option.fqdn = 'x' + '.x' * 126 self.option.validate() self.option.fqdn = 'xx' + '.x' * 126 with self.assertRaisesRegex(ValueError, 'Domain too long'): self.option.validate() self.option.fqdn = 'www.123456789012345678901234567890123456789012345678901234567890123.nl' self.option.validate() self.option.fqdn = 'www.1234567890123456789012345678901234567890123456789012345678901234.nl' with self.assertRaisesRegex(ValueError, 'Label too long'): self.option.validate()
[docs] def test_bad_option_length(self): with self.assertRaisesRegex(ValueError, 'must end with a 0-length label'): NTPServerFQDNSubOption.parse(bytes.fromhex('0003000c') + b'\x08steffann\x02nl\x00') with self.assertRaisesRegex(ValueError, 'length does not match'): NTPServerFQDNSubOption.parse(bytes.fromhex('0003000e') + b'\x08steffann\x02nl\x00\x01')
if __name__ == '__main__': # pragma: no cover unittest.main()