diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..8dc0e50 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Commit that added in black formatting support +e116d26eeca0891c31b689e43db5bb60b62f73f6 diff --git a/.git_hooks_pre-commit b/.git_hooks_pre-commit index 1fb621f..7938eee 100755 --- a/.git_hooks_pre-commit +++ b/.git_hooks_pre-commit @@ -8,4 +8,5 @@ ROOT=$(dirname "$GIT") . "$ROOT/env/bin/activate" "$ROOT/script/lint" +"$ROOT/script/format" --check --quiet || (echo "Formatting check failed, run ./script/format" && exit 1) "$ROOT/script/coverage" diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 047c9ed..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,3 +0,0 @@ -# These are supported funding model platforms - -github: ross diff --git a/octodns/__init__.py b/octodns/__init__.py index 1870f70..9d59853 100644 --- a/octodns/__init__.py +++ b/octodns/__init__.py @@ -1,6 +1,10 @@ 'OctoDNS: DNS as code - Tools for managing DNS across multiple providers' -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) __VERSION__ = '0.9.17' diff --git a/octodns/cmds/__init__.py b/octodns/cmds/__init__.py index 14ccf18..16a8eb0 100644 --- a/octodns/cmds/__init__.py +++ b/octodns/cmds/__init__.py @@ -2,5 +2,9 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) diff --git a/octodns/cmds/args.py b/octodns/cmds/args.py index 41906ba..7f04f43 100644 --- a/octodns/cmds/args.py +++ b/octodns/cmds/args.py @@ -2,12 +2,15 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from argparse import ArgumentParser as _Base -from logging import DEBUG, INFO, WARN, Formatter, StreamHandler, \ - getLogger +from logging import DEBUG, INFO, WARN, Formatter, StreamHandler, getLogger from logging.handlers import SysLogHandler from sys import stderr, stdout @@ -26,22 +29,33 @@ class ArgumentParser(_Base): def parse_args(self, default_log_level=INFO): version = f'octoDNS {__VERSION__}' - self.add_argument('--version', action='version', version=version, - help='Print octoDNS version and exit') - self.add_argument('--log-stream-stdout', action='store_true', - default=False, - help='Log to stdout instead of stderr') + self.add_argument( + '--version', + action='version', + version=version, + help='Print octoDNS version and exit', + ) + self.add_argument( + '--log-stream-stdout', + action='store_true', + default=False, + help='Log to stdout instead of stderr', + ) _help = 'Send logging data to syslog in addition to stderr' - self.add_argument('--log-syslog', action='store_true', default=False, - help=_help) - self.add_argument('--syslog-device', default='/dev/log', - help='Syslog device') - self.add_argument('--syslog-facility', default='local0', - help='Syslog facility') + self.add_argument( + '--log-syslog', action='store_true', default=False, help=_help + ) + self.add_argument( + '--syslog-device', default='/dev/log', help='Syslog device' + ) + self.add_argument( + '--syslog-facility', default='local0', help='Syslog facility' + ) _help = 'Increase verbosity to get details and help track down issues' - self.add_argument('--debug', action='store_true', default=False, - help=_help) + self.add_argument( + '--debug', action='store_true', default=False, help=_help + ) args = super(ArgumentParser, self).parse_args() self._setup_logging(args, default_log_level) @@ -57,10 +71,13 @@ class ArgumentParser(_Base): logger.addHandler(handler) if args.log_syslog: - fmt = 'octodns[%(process)-5s:%(thread)d]: %(name)s ' \ + fmt = ( + 'octodns[%(process)-5s:%(thread)d]: %(name)s ' '%(levelname)-5s %(message)s' - handler = SysLogHandler(address=args.syslog_device, - facility=args.syslog_facility) + ) + handler = SysLogHandler( + address=args.syslog_device, facility=args.syslog_facility + ) handler.setFormatter(Formatter(fmt=fmt)) logger.addHandler(handler) diff --git a/octodns/cmds/compare.py b/octodns/cmds/compare.py index 9bf9f1c..818a436 100755 --- a/octodns/cmds/compare.py +++ b/octodns/cmds/compare.py @@ -3,8 +3,12 @@ Octo-DNS Comparator ''' -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from pprint import pprint import sys @@ -16,16 +20,32 @@ from octodns.manager import Manager def main(): parser = ArgumentParser(description=__doc__.split('\n')[1]) - parser.add_argument('--config-file', required=True, - help='The Manager configuration file to use') - parser.add_argument('--a', nargs='+', required=True, - help='First source(s) to pull data from') - parser.add_argument('--b', nargs='+', required=True, - help='Second source(s) to pull data from') - parser.add_argument('--zone', default=None, required=True, - help='Zone to compare') - parser.add_argument('--ignore-prefix', default=None, required=False, - help='Record prefix to ignore from list of changes') + parser.add_argument( + '--config-file', + required=True, + help='The Manager configuration file to use', + ) + parser.add_argument( + '--a', + nargs='+', + required=True, + help='First source(s) to pull data from', + ) + parser.add_argument( + '--b', + nargs='+', + required=True, + help='Second source(s) to pull data from', + ) + parser.add_argument( + '--zone', default=None, required=True, help='Zone to compare' + ) + parser.add_argument( + '--ignore-prefix', + default=None, + required=False, + help='Record prefix to ignore from list of changes', + ) args = parser.parse_args() manager = Manager(args.config_file) @@ -34,8 +54,7 @@ def main(): # Filter changes list based on ignore-prefix argument if present if args.ignore_prefix: pattern = args.ignore_prefix - changes = [c for c in changes - if not c.record.fqdn.startswith(pattern)] + changes = [c for c in changes if not c.record.fqdn.startswith(pattern)] pprint(changes) diff --git a/octodns/cmds/dump.py b/octodns/cmds/dump.py index 9927468..8d30913 100755 --- a/octodns/cmds/dump.py +++ b/octodns/cmds/dump.py @@ -3,8 +3,12 @@ Octo-DNS Dumper ''' -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from octodns.cmds.args import ArgumentParser from octodns.manager import Manager @@ -13,26 +17,49 @@ from octodns.manager import Manager def main(): parser = ArgumentParser(description=__doc__.split('\n')[1]) - parser.add_argument('--config-file', required=True, - help='The Manager configuration file to use') - parser.add_argument('--output-dir', required=True, - help='The directory into which the results will be ' - 'written (Note: will overwrite existing files)') - parser.add_argument('--lenient', action='store_true', default=False, - help='Ignore record validations and do a best effort ' - 'dump') - parser.add_argument('--split', action='store_true', default=False, - help='Split the dumped zone into a YAML file per ' - 'record') + parser.add_argument( + '--config-file', + required=True, + help='The Manager configuration file to use', + ) + parser.add_argument( + '--output-dir', + required=True, + help='The directory into which the results will be ' + 'written (Note: will overwrite existing files)', + ) + parser.add_argument( + '--output-provider', + required=False, + help='The configured provider to use when dumping ' + 'records. Must support copy() and directory', + ) + parser.add_argument( + '--lenient', + action='store_true', + default=False, + help='Ignore record validations and do a best effort ' 'dump', + ) + parser.add_argument( + '--split', + action='store_true', + default=False, + help='Split the dumped zone into a YAML file per ' 'record', + ) parser.add_argument('zone', help='Zone to dump') - parser.add_argument('source', nargs='+', - help='Source(s) to pull data from') + parser.add_argument('source', nargs='+', help='Source(s) to pull data from') args = parser.parse_args() manager = Manager(args.config_file) - manager.dump(args.zone, args.output_dir, args.lenient, args.split, - *args.source) + manager.dump( + zone=args.zone, + output_dir=args.output_dir, + output_provider=args.output_provider, + lenient=args.lenient, + split=args.split, + sources=args.source, + ) if __name__ == '__main__': diff --git a/octodns/cmds/report.py b/octodns/cmds/report.py index c733492..d13e85c 100755 --- a/octodns/cmds/report.py +++ b/octodns/cmds/report.py @@ -3,8 +3,12 @@ Octo-DNS Reporter ''' -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from concurrent.futures import ThreadPoolExecutor from dns.exception import Timeout @@ -18,28 +22,38 @@ from octodns.manager import Manager class AsyncResolver(Resolver): - def __init__(self, num_workers, *args, **kwargs): super(AsyncResolver, self).__init__(*args, **kwargs) self.executor = ThreadPoolExecutor(max_workers=num_workers) def query(self, *args, **kwargs): - return self.executor.submit(super(AsyncResolver, self).query, *args, - **kwargs) + return self.executor.submit( + super(AsyncResolver, self).query, *args, **kwargs + ) def main(): parser = ArgumentParser(description=__doc__.split('\n')[1]) - parser.add_argument('--config-file', required=True, - help='The Manager configuration file to use') + parser.add_argument( + '--config-file', + required=True, + help='The Manager configuration file to use', + ) parser.add_argument('--zone', required=True, help='Zone to dump') - parser.add_argument('--source', required=True, default=[], action='append', - help='Source(s) to pull data from') - parser.add_argument('--num-workers', default=4, - help='Number of background workers') - parser.add_argument('--timeout', default=1, - help='Number seconds to wait for an answer') + parser.add_argument( + '--source', + required=True, + default=[], + action='append', + help='Source(s) to pull data from', + ) + parser.add_argument( + '--num-workers', default=4, help='Number of background workers' + ) + parser.add_argument( + '--timeout', default=1, help='Number seconds to wait for an answer' + ) parser.add_argument('server', nargs='+', help='Servers to query') args = parser.parse_args() @@ -62,8 +76,9 @@ def main(): resolvers = [] ip_addr_re = re.compile(r'^[\d\.]+$') for server in args.server: - resolver = AsyncResolver(configure=False, - num_workers=int(args.num_workers)) + resolver = AsyncResolver( + configure=False, num_workers=int(args.num_workers) + ) if not ip_addr_re.match(server): server = str(query(server, 'A')[0]) log.info('server=%s', server) @@ -73,8 +88,9 @@ def main(): queries = {} for record in sorted(zone.records): - queries[record] = [r.query(record.fqdn, record._type) - for r in resolvers] + queries[record] = [ + r.query(record.fqdn, record._type) for r in resolvers + ] for record, futures in sorted(queries.items(), key=lambda d: d[0]): stdout.write(record.fqdn) diff --git a/octodns/cmds/sync.py b/octodns/cmds/sync.py index dbf4103..fcaa5ea 100755 --- a/octodns/cmds/sync.py +++ b/octodns/cmds/sync.py @@ -3,8 +3,12 @@ Octo-DNS Multiplexer ''' -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from octodns.cmds.args import ArgumentParser from octodns.manager import Manager @@ -13,31 +17,57 @@ from octodns.manager import Manager def main(): parser = ArgumentParser(description=__doc__.split('\n')[1]) - parser.add_argument('--config-file', required=True, - help='The Manager configuration file to use') - parser.add_argument('--doit', action='store_true', default=False, - help='Whether to take action or just show what would ' - 'change') - parser.add_argument('--force', action='store_true', default=False, - help='Acknowledge that significant changes are being ' - 'made and do them') + parser.add_argument( + '--config-file', + required=True, + help='The Manager configuration file to use', + ) + parser.add_argument( + '--doit', + action='store_true', + default=False, + help='Whether to take action or just show what would ' 'change', + ) + parser.add_argument( + '--force', + action='store_true', + default=False, + help='Acknowledge that significant changes are being ' + 'made and do them', + ) - parser.add_argument('zone', nargs='*', default=[], - help='Limit sync to the specified zone(s)') + parser.add_argument( + 'zone', + nargs='*', + default=[], + help='Limit sync to the specified zone(s)', + ) - parser.add_argument('--source', default=[], action='append', - help='Limit sync to zones with the specified ' - 'source(s) (all sources will be synchronized for the ' - 'selected zones)') - parser.add_argument('--target', default=[], action='append', - help='Limit sync to the specified target(s)') + parser.add_argument( + '--source', + default=[], + action='append', + help='Limit sync to zones with the specified ' + 'source(s) (all sources will be synchronized for the ' + 'selected zones)', + ) + parser.add_argument( + '--target', + default=[], + action='append', + help='Limit sync to the specified target(s)', + ) args = parser.parse_args() manager = Manager(args.config_file) - manager.sync(eligible_zones=args.zone, eligible_sources=args.source, - eligible_targets=args.target, dry_run=not args.doit, - force=args.force) + manager.sync( + eligible_zones=args.zone, + eligible_sources=args.source, + eligible_targets=args.target, + dry_run=not args.doit, + force=args.force, + ) if __name__ == '__main__': diff --git a/octodns/cmds/validate.py b/octodns/cmds/validate.py index 6711ec9..f69c02b 100755 --- a/octodns/cmds/validate.py +++ b/octodns/cmds/validate.py @@ -3,8 +3,12 @@ Octo-DNS Validator ''' -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import WARN @@ -15,8 +19,11 @@ from octodns.manager import Manager def main(): parser = ArgumentParser(description=__doc__.split('\n')[1]) - parser.add_argument('--config-file', required=True, - help='The Manager configuration file to use') + parser.add_argument( + '--config-file', + required=True, + help='The Manager configuration file to use', + ) args = parser.parse_args(WARN) diff --git a/octodns/cmds/versions.py b/octodns/cmds/versions.py index 7cb3a45..2794ee4 100755 --- a/octodns/cmds/versions.py +++ b/octodns/cmds/versions.py @@ -3,8 +3,12 @@ octoDNS Versions ''' -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from octodns.cmds.args import ArgumentParser from octodns.manager import Manager @@ -13,8 +17,11 @@ from octodns.manager import Manager def main(): parser = ArgumentParser(description=__doc__.split('\n')[1]) - parser.add_argument('--config-file', required=True, - help='The Manager configuration file to use') + parser.add_argument( + '--config-file', + required=True, + help='The Manager configuration file to use', + ) args = parser.parse_args() diff --git a/octodns/equality.py b/octodns/equality.py index bd22c7d..db08a2a 100644 --- a/octodns/equality.py +++ b/octodns/equality.py @@ -2,12 +2,15 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) class EqualityTupleMixin(object): - def _equality_tuple(self): raise NotImplementedError('_equality_tuple method not implemented') diff --git a/octodns/manager.py b/octodns/manager.py index e640a8d..0faa0bf 100644 --- a/octodns/manager.py +++ b/octodns/manager.py @@ -2,8 +2,12 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from concurrent.futures import ThreadPoolExecutor from importlib import import_module @@ -22,9 +26,12 @@ from .zone import Zone # TODO: this can go away once we no longer support python 3.7 try: - from importlib.metadata import PackageNotFoundError, \ - version as module_version + from importlib.metadata import ( + PackageNotFoundError, + version as module_version, + ) except ModuleNotFoundError: # pragma: no cover + class PackageNotFoundError(Exception): pass @@ -61,7 +68,6 @@ class _AggregateTarget(object): class MakeThreadFuture(object): - def __init__(self, func, args, kwargs): self.func = func self.args = args @@ -98,24 +104,29 @@ class Manager(object): def __init__(self, config_file, max_workers=None, include_meta=False): version = self._try_version('octodns', version=__VERSION__) - self.log.info('__init__: config_file=%s (octoDNS %s)', config_file, - version) + self.log.info( + '__init__: config_file=%s (octoDNS %s)', config_file, version + ) # Read our config file with open(config_file, 'r') as fh: self.config = safe_load(fh, enforce_order=False) manager_config = self.config.get('manager', {}) - max_workers = manager_config.get('max_workers', 1) \ - if max_workers is None else max_workers + max_workers = ( + manager_config.get('max_workers', 1) + if max_workers is None + else max_workers + ) self.log.info('__init__: max_workers=%d', max_workers) if max_workers > 1: self._executor = ThreadPoolExecutor(max_workers=max_workers) else: self._executor = MainThreadExecutor() - self.include_meta = include_meta or manager_config.get('include_meta', - False) + self.include_meta = include_meta or manager_config.get( + 'include_meta', False + ) self.log.info('__init__: include_meta=%s', self.include_meta) self.log.debug('__init__: configuring providers') @@ -126,89 +137,112 @@ class Manager(object): _class = provider_config.pop('class') except KeyError: self.log.exception('Invalid provider class') - raise ManagerException(f'Provider {provider_name} is missing ' - 'class') + raise ManagerException( + f'Provider {provider_name} is missing ' 'class' + ) _class, module, version = self._get_named_class('provider', _class) kwargs = self._build_kwargs(provider_config) try: self.providers[provider_name] = _class(provider_name, **kwargs) - self.log.info('__init__: provider=%s (%s %s)', provider_name, - module, version) + self.log.info( + '__init__: provider=%s (%s %s)', + provider_name, + module, + version, + ) except TypeError: self.log.exception('Invalid provider config') - raise ManagerException('Incorrect provider config for ' + - provider_name) + raise ManagerException( + 'Incorrect provider config for ' + provider_name + ) self.processors = {} - for processor_name, processor_config in \ - self.config.get('processors', {}).items(): + for processor_name, processor_config in self.config.get( + 'processors', {} + ).items(): try: _class = processor_config.pop('class') except KeyError: self.log.exception('Invalid processor class') - raise ManagerException(f'Processor {processor_name} is ' - 'missing class') - _class, module, version = self._get_named_class('processor', - _class) + raise ManagerException( + f'Processor {processor_name} is ' 'missing class' + ) + _class, module, version = self._get_named_class('processor', _class) kwargs = self._build_kwargs(processor_config) try: - self.processors[processor_name] = _class(processor_name, - **kwargs) - self.log.info('__init__: processor=%s (%s %s)', processor_name, - module, version) + self.processors[processor_name] = _class( + processor_name, **kwargs + ) + self.log.info( + '__init__: processor=%s (%s %s)', + processor_name, + module, + version, + ) except TypeError: self.log.exception('Invalid processor config') - raise ManagerException('Incorrect processor config for ' + - processor_name) + raise ManagerException( + 'Incorrect processor config for ' + processor_name + ) zone_tree = {} - # sort by reversed strings so that parent zones always come first - for name in sorted(self.config['zones'].keys(), key=lambda s: s[::-1]): - # ignore trailing dots, and reverse - pieces = name[:-1].split('.')[::-1] - # where starts out at the top - where = zone_tree - # for all the pieces - for piece in pieces: - try: - where = where[piece] - # our current piece already exists, just point where at - # it's value - except KeyError: - # our current piece doesn't exist, create it - where[piece] = {} - # and then point where at it's newly created value - where = where[piece] + # Sort so we iterate on the deepest nodes first, ensuring if a parent + # zone exists it will be seen after the subzone, thus we can easily + # reparent children to their parent zone from the tree root. + for name in sorted( + self.config['zones'].keys(), key=lambda s: 0 - s.count('.') + ): + # Trim the trailing dot from FQDN + name = name[:-1] + this = {} + for sz in [k for k in zone_tree.keys() if k.endswith(name)]: + # Found a zone in tree root that is our child, slice the + # name and move its tree under ours. + this[sz[: -(len(name) + 1)]] = zone_tree.pop(sz) + # Add to tree root where it will be reparented as we iterate up + # the tree. + zone_tree[name] = this self.zone_tree = zone_tree self.plan_outputs = {} - plan_outputs = manager_config.get('plan_outputs', { - '_logger': { - 'class': 'octodns.provider.plan.PlanLogger', - 'level': 'info' - } - }) + plan_outputs = manager_config.get( + 'plan_outputs', + { + '_logger': { + 'class': 'octodns.provider.plan.PlanLogger', + 'level': 'info', + } + }, + ) for plan_output_name, plan_output_config in plan_outputs.items(): try: _class = plan_output_config.pop('class') except KeyError: self.log.exception('Invalid plan_output class') - raise ManagerException(f'plan_output {plan_output_name} is ' - 'missing class') - _class, module, version = self._get_named_class('plan_output', - _class) + raise ManagerException( + f'plan_output {plan_output_name} is ' 'missing class' + ) + _class, module, version = self._get_named_class( + 'plan_output', _class + ) kwargs = self._build_kwargs(plan_output_config) try: - self.plan_outputs[plan_output_name] = \ - _class(plan_output_name, **kwargs) + self.plan_outputs[plan_output_name] = _class( + plan_output_name, **kwargs + ) # Don't print out version info for the default output if plan_output_name != '_logger': - self.log.info('__init__: plan_output=%s (%s %s)', - plan_output_name, module, version) + self.log.info( + '__init__: plan_output=%s (%s %s)', + plan_output_name, + module, + version, + ) except TypeError: self.log.exception('Invalid plan_output config') - raise ManagerException('Incorrect plan_output config for ' + - plan_output_name) + raise ManagerException( + 'Incorrect plan_output config for ' + plan_output_name + ) def _try_version(self, module_name, module=None, version=None): try: @@ -243,15 +277,19 @@ class Manager(object): module_name, class_name = _class.rsplit('.', 1) module, version = self._import_module(module_name) except (ImportError, ValueError): - self.log.exception('_get_{}_class: Unable to import ' - 'module %s', _class) + self.log.exception( + '_get_{}_class: Unable to import ' 'module %s', _class + ) raise ManagerException(f'Unknown {_type} class: {_class}') try: return getattr(module, class_name), module_name, version except AttributeError: - self.log.exception('_get_{}_class: Unable to get class %s ' - 'from module %s', class_name, module) + self.log.exception( + '_get_{}_class: Unable to get class %s ' 'from module %s', + class_name, + module, + ) raise ManagerException(f'Unknown {_type} class: {_class}') def _build_kwargs(self, source): @@ -265,8 +303,10 @@ class Manager(object): v = environ[env_var] except KeyError: self.log.exception('Invalid provider config') - raise ManagerException('Incorrect provider config, ' - 'missing env var ' + env_var) + raise ManagerException( + 'Incorrect provider config, ' + 'missing env var ' + env_var + ) except AttributeError: pass kwargs[k] = v @@ -274,32 +314,38 @@ class Manager(object): return kwargs def configured_sub_zones(self, zone_name): - # Reversed pieces of the zone name - pieces = zone_name[:-1].split('.')[::-1] - # Point where at the root of the tree + name = zone_name[:-1] where = self.zone_tree - # Until we've hit the bottom of this zone - try: - while pieces: - # Point where at the value of our current piece - where = where[pieces.pop(0)] - except KeyError: - self.log.debug('configured_sub_zones: unknown zone, %s, no subs', - zone_name) - return set() - # We're not pointed at the dict for our name, the keys of which will be - # any subzones + while True: + # Find parent if it exists + parent = next((k for k in where if name.endswith(k)), None) + if not parent: + # The zone_name in the tree has been reached, stop searching. + break + # Move down the tree and slice name to get the remainder for the + # next round of the search. + where = where[parent] + name = name[: -(len(parent) + 1)] + # `where` is now pointing at the dictionary of children for zone_name + # in the tree sub_zone_names = where.keys() self.log.debug('configured_sub_zones: subs=%s', sub_zone_names) return set(sub_zone_names) - def _populate_and_plan(self, zone_name, processors, sources, targets, - desired=None, lenient=False): + def _populate_and_plan( + self, + zone_name, + processors, + sources, + targets, + desired=None, + lenient=False, + ): - self.log.debug('sync: populating, zone=%s, lenient=%s', - zone_name, lenient) - zone = Zone(zone_name, - sub_zones=self.configured_sub_zones(zone_name)) + self.log.debug( + 'sync: populating, zone=%s, lenient=%s', zone_name, lenient + ) + zone = Zone(zone_name, sub_zones=self.configured_sub_zones(zone_name)) if desired: # This is an alias zone, rather than populate it we'll copy the @@ -312,11 +358,12 @@ class Manager(object): try: source.populate(zone, lenient=lenient) except TypeError as e: - if ("unexpected keyword argument 'lenient'" - not in str(e)): + if "unexpected keyword argument 'lenient'" not in str(e): raise - self.log.warning('provider %s does not accept lenient ' - 'param', source.__class__.__name__) + self.log.warning( + 'provider %s does not accept lenient ' 'param', + source.__class__.__name__, + ) source.populate(zone) for processor in processors: @@ -327,38 +374,56 @@ class Manager(object): for target in targets: if self.include_meta: - meta = Record.new(zone, 'octodns-meta', { - 'type': 'TXT', - 'ttl': 60, - 'value': f'provider={target.id}', - }) + meta = Record.new( + zone, + 'octodns-meta', + { + 'type': 'TXT', + 'ttl': 60, + 'value': f'provider={target.id}', + }, + ) zone.add_record(meta, replace=True) try: plan = target.plan(zone, processors=processors) except TypeError as e: if "keyword argument 'processors'" not in str(e): raise - self.log.warning('provider.plan %s does not accept processors ' - 'param', target.__class__.__name__) + self.log.warning( + 'provider.plan %s does not accept processors ' 'param', + target.__class__.__name__, + ) plan = target.plan(zone) for processor in processors: - plan = processor.process_plan(plan, sources=sources, - target=target) + plan = processor.process_plan( + plan, sources=sources, target=target + ) if plan: plans.append((target, plan)) # Return the zone as it's the desired state return plans, zone - def sync(self, eligible_zones=[], eligible_sources=[], eligible_targets=[], - dry_run=True, force=False, plan_output_fh=stdout): + def sync( + self, + eligible_zones=[], + eligible_sources=[], + eligible_targets=[], + dry_run=True, + force=False, + plan_output_fh=stdout, + ): self.log.info( 'sync: eligible_zones=%s, eligible_targets=%s, dry_run=%s, ' 'force=%s, plan_output_fh=%s', - eligible_zones, eligible_targets, dry_run, force, - getattr(plan_output_fh, 'name', plan_output_fh.__class__.__name__)) + eligible_zones, + eligible_targets, + dry_run, + force, + getattr(plan_output_fh, 'name', plan_output_fh.__class__.__name__), + ) zones = self.config['zones'].items() if eligible_zones: @@ -373,19 +438,27 @@ class Manager(object): # Check that the source zone is defined. if source_zone not in self.config['zones']: - self.log.error(f'Invalid alias zone {zone_name}, ' - f'target {source_zone} does not exist') - raise ManagerException(f'Invalid alias zone {zone_name}: ' - f'source zone {source_zone} does ' - 'not exist') + self.log.error( + f'Invalid alias zone {zone_name}, ' + f'target {source_zone} does not exist' + ) + raise ManagerException( + f'Invalid alias zone {zone_name}: ' + f'source zone {source_zone} does ' + 'not exist' + ) # Check that the source zone is not an alias zone itself. if 'alias' in self.config['zones'][source_zone]: - self.log.error(f'Invalid alias zone {zone_name}, ' - f'target {source_zone} is an alias zone') - raise ManagerException(f'Invalid alias zone {zone_name}: ' - f'source zone {source_zone} is an ' - 'alias zone') + self.log.error( + f'Invalid alias zone {zone_name}, ' + f'target {source_zone} is an alias zone' + ) + raise ManagerException( + f'Invalid alias zone {zone_name}: ' + f'source zone {source_zone} is an ' + 'alias zone' + ) aliased_zones[zone_name] = source_zone continue @@ -403,8 +476,9 @@ class Manager(object): processors = config.get('processors', []) - if (eligible_sources and not - [s for s in sources if s in eligible_sources]): + if eligible_sources and not [ + s for s in sources if s in eligible_sources + ]: self.log.info('sync: no eligible sources, skipping') continue @@ -426,8 +500,9 @@ class Manager(object): collected.append(self.processors[processor]) processors = collected except KeyError: - raise ManagerException(f'Zone {zone_name}, unknown ' - f'processor: {processor}') + raise ManagerException( + f'Zone {zone_name}, unknown ' f'processor: {processor}' + ) try: # rather than using a list comprehension, we break this loop @@ -438,26 +513,35 @@ class Manager(object): collected.append(self.providers[source]) sources = collected except KeyError: - raise ManagerException(f'Zone {zone_name}, unknown ' - f'source: {source}') + raise ManagerException( + f'Zone {zone_name}, unknown ' f'source: {source}' + ) try: trgs = [] for target in targets: trg = self.providers[target] if not isinstance(trg, BaseProvider): - raise ManagerException(f'{trg} - "{target}" does not ' - 'support targeting') + raise ManagerException( + f'{trg} - "{target}" does not ' 'support targeting' + ) trgs.append(trg) targets = trgs except KeyError: - raise ManagerException(f'Zone {zone_name}, unknown ' - f'target: {target}') + raise ManagerException( + f'Zone {zone_name}, unknown ' f'target: {target}' + ) - futures.append(self._executor.submit(self._populate_and_plan, - zone_name, processors, - sources, targets, - lenient=lenient)) + futures.append( + self._executor.submit( + self._populate_and_plan, + zone_name, + processors, + sources, + targets, + lenient=lenient, + ) + ) # Wait on all results and unpack/flatten the plans and store the # desired states in case we need them below @@ -476,18 +560,22 @@ class Manager(object): try: desired_config = desired[zone_source] except KeyError: - raise ManagerException(f'Zone {zone_name} cannot be sync ' - f'without zone {zone_source} sinced ' - 'it is aliased') - futures.append(self._executor.submit( - self._populate_and_plan, - zone_name, - processors, - [], - [self.providers[t] for t in source_config['targets']], - desired=desired_config, - lenient=lenient - )) + raise ManagerException( + f'Zone {zone_name} cannot be sync ' + f'without zone {zone_source} sinced ' + 'it is aliased' + ) + futures.append( + self._executor.submit( + self._populate_and_plan, + zone_name, + processors, + [], + [self.providers[t] for t in source_config['targets']], + desired=desired_config, + lenient=lenient, + ) + ) # Wait on results and unpack/flatten the plans, ignore the desired here # as these are aliased zones @@ -517,8 +605,9 @@ class Manager(object): for target, plan in plans: zone_name = plan.existing.name if zones[zone_name].get('always-dry-run', False): - self.log.info('sync: zone=%s skipping always-dry-run', - zone_name) + self.log.info( + 'sync: zone=%s skipping always-dry-run', zone_name + ) continue total_changes += target.apply(plan) @@ -549,25 +638,75 @@ class Manager(object): return zb.changes(za, _AggregateTarget(a + b)) - def dump(self, zone, output_dir, lenient, split, source, *sources): + def dump( + self, + zone, + output_dir, + sources, + lenient=False, + split=False, + output_provider=None, + ): ''' Dump zone data from the specified source ''' - self.log.info('dump: zone=%s, sources=%s', zone, sources) - - # We broke out source to force at least one to be passed, add it to any - # others we got. - sources = [source] + list(sources) + self.log.info( + 'dump: zone=%s, output_dir=%s, output_provider=%s, ' + 'lenient=%s, split=%s, sources=%s', + zone, + output_dir, + output_provider, + lenient, + split, + sources, + ) try: sources = [self.providers[s] for s in sources] except KeyError as e: raise ManagerException(f'Unknown source: {e.args[0]}') - clz = YamlProvider - if split: - clz = SplitYamlProvider - target = clz('dump', output_dir) + if output_provider: + self.log.info( + 'dump: using specified output_provider=%s', output_provider + ) + try: + target = self.providers[output_provider] + except KeyError as e: + raise ManagerException(f'Unknown output_provider: {e.args[0]}') + # The chosen output provider has to support a directory property so + # that we can tell it where the user has requested the dumped files + # to reside. + if not hasattr(target, 'directory'): + msg = ( + f'output_provider={output_provider}, does not support ' + 'directory property' + ) + raise ManagerException(msg) + if target.directory != output_dir: + # If the requested target doesn't match what's configured in + # the chosen provider then we'll need to set it. Before doing + # that we make a copy of the provider so that it can remain + # unchanged and potentially be used as a source, e.g. copying + # from one yaml to another + if not hasattr(target, 'copy'): + msg = ( + f'output_provider={output_provider}, does not ' + 'support copy method' + ) + raise ManagerException(msg) + target = target.copy() + self.log.info( + 'dump: setting directory of output_provider ' 'copy to %s', + output_dir, + ) + target.directory = output_dir + else: + self.log.info('dump: using custom YamlProvider') + clz = YamlProvider + if split: + clz = SplitYamlProvider + target = clz('dump', output_dir) zone = Zone(zone, self.configured_sub_zones(zone)) for source in sources: @@ -586,15 +725,19 @@ class Manager(object): if source_zone: if source_zone not in self.config['zones']: self.log.exception('Invalid alias zone') - raise ManagerException(f'Invalid alias zone {zone_name}: ' - f'source zone {source_zone} does ' - 'not exist') + raise ManagerException( + f'Invalid alias zone {zone_name}: ' + f'source zone {source_zone} does ' + 'not exist' + ) if 'alias' in self.config['zones'][source_zone]: self.log.exception('Invalid alias zone') - raise ManagerException(f'Invalid alias zone {zone_name}: ' - 'source zone {source_zone} is an ' - 'alias zone') + raise ManagerException( + f'Invalid alias zone {zone_name}: ' + 'source zone {source_zone} is an ' + 'alias zone' + ) # this is just here to satisfy coverage, see # https://github.com/nedbat/coveragepy/issues/198 @@ -616,8 +759,9 @@ class Manager(object): collected.append(self.providers[source]) sources = collected except KeyError: - raise ManagerException(f'Zone {zone_name}, unknown source: ' + - source) + raise ManagerException( + f'Zone {zone_name}, unknown source: ' + source + ) for source in sources: if isinstance(source, YamlProvider): @@ -630,13 +774,15 @@ class Manager(object): for processor in processors: collected.append(self.processors[processor]) except KeyError: - raise ManagerException(f'Zone {zone_name}, unknown ' - f'processor: {processor}') + raise ManagerException( + f'Zone {zone_name}, unknown ' f'processor: {processor}' + ) def get_zone(self, zone_name): if not zone_name[-1] == '.': - raise ManagerException(f'Invalid zone name {zone_name}, missing ' - 'ending dot') + raise ManagerException( + f'Invalid zone name {zone_name}, missing ' 'ending dot' + ) for name, config in self.config['zones'].items(): if name == zone_name: diff --git a/octodns/processor/__init__.py b/octodns/processor/__init__.py index 14ccf18..16a8eb0 100644 --- a/octodns/processor/__init__.py +++ b/octodns/processor/__init__.py @@ -2,5 +2,9 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) diff --git a/octodns/processor/acme.py b/octodns/processor/acme.py index 2d7c101..2797dba 100644 --- a/octodns/processor/acme.py +++ b/octodns/processor/acme.py @@ -2,8 +2,12 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger @@ -34,8 +38,9 @@ class AcmeMangingProcessor(BaseProcessor): def process_source_zone(self, desired, *args, **kwargs): for record in desired.records: - if record._type == 'TXT' and \ - record.name.startswith('_acme-challenge'): + if record._type == 'TXT' and record.name.startswith( + '_acme-challenge' + ): # We have a managed acme challenge record (owned by octoDNS) so # we should mark it as such record = record.copy() @@ -51,10 +56,12 @@ class AcmeMangingProcessor(BaseProcessor): for record in existing.records: # Uses a startswith rather than == to ignore subdomain challenges, # e.g. _acme-challenge.foo.domain.com when managing domain.com - if record._type == 'TXT' and \ - record.name.startswith('_acme-challenge') and \ - '*octoDNS*' not in record.values and \ - record not in self._owned: + if ( + record._type == 'TXT' + and record.name.startswith('_acme-challenge') + and '*octoDNS*' not in record.values + and record not in self._owned + ): self.log.info('_process: ignoring %s', record.fqdn) existing.remove_record(record) diff --git a/octodns/processor/awsacm.py b/octodns/processor/awsacm.py index f147c00..dcd53f9 100644 --- a/octodns/processor/awsacm.py +++ b/octodns/processor/awsacm.py @@ -2,21 +2,30 @@ # Ignores AWS ACM validation CNAME records. # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Route53') try: - logger.warning('octodns_route53 shimmed. Update your processor class to ' - 'octodns_route53.processor.AwsAcmMangingProcessor. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_route53 shimmed. Update your processor class to ' + 'octodns_route53.processor.AwsAcmMangingProcessor. ' + 'Shim will be removed in 1.0' + ) from octodns_route53.processor import AwsAcmMangingProcessor + AwsAcmMangingProcessor # pragma: no cover except ModuleNotFoundError: - logger.exception('AwsAcmMangingProcessor has been moved into a separate ' - 'module, octodns_route53 is now required. Processor ' - 'class should be updated to ' - 'octodns_route53.processor.AwsAcmMangingProcessor') + logger.exception( + 'AwsAcmMangingProcessor has been moved into a separate ' + 'module, octodns_route53 is now required. Processor ' + 'class should be updated to ' + 'octodns_route53.processor.AwsAcmMangingProcessor' + ) raise diff --git a/octodns/processor/base.py b/octodns/processor/base.py index 82ee66a..ac5c155 100644 --- a/octodns/processor/base.py +++ b/octodns/processor/base.py @@ -2,12 +2,15 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) class BaseProcessor(object): - def __init__(self, name): self.name = name diff --git a/octodns/processor/filter.py b/octodns/processor/filter.py index d9b8ee3..b343332 100644 --- a/octodns/processor/filter.py +++ b/octodns/processor/filter.py @@ -2,14 +2,17 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from .base import BaseProcessor class TypeAllowlistFilter(BaseProcessor): - def __init__(self, name, allowlist): super(TypeAllowlistFilter, self).__init__(name) self.allowlist = set(allowlist) @@ -26,7 +29,6 @@ class TypeAllowlistFilter(BaseProcessor): class TypeRejectlistFilter(BaseProcessor): - def __init__(self, name, rejectlist): super(TypeRejectlistFilter, self).__init__(name) self.rejectlist = set(rejectlist) diff --git a/octodns/processor/ownership.py b/octodns/processor/ownership.py index a70c8dd..68b7430 100644 --- a/octodns/processor/ownership.py +++ b/octodns/processor/ownership.py @@ -2,8 +2,12 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from collections import defaultdict @@ -17,7 +21,6 @@ from .base import BaseProcessor # delete. We'll take ownership of existing records that we're told to manage # and thus "own" them going forward. class OwnershipProcessor(BaseProcessor): - def __init__(self, name, txt_name='_owner', txt_value='*octodns*'): super(OwnershipProcessor, self).__init__(name) self.txt_name = txt_name @@ -32,19 +35,21 @@ class OwnershipProcessor(BaseProcessor): name = f'{self.txt_name}.{record._type}.{record_name}' else: name = f'{self.txt_name}.{record._type}' - txt = Record.new(desired, name, { - 'type': 'TXT', - 'ttl': 60, - 'value': self.txt_value, - }) + txt = Record.new( + desired, + name, + {'type': 'TXT', 'ttl': 60, 'value': self.txt_value}, + ) desired.add_record(txt) return desired def _is_ownership(self, record): - return record._type == 'TXT' and \ - record.name.startswith(self.txt_name) \ + return ( + record._type == 'TXT' + and record.name.startswith(self.txt_name) and record.values == self._txt_values + ) def process_plan(self, plan, *args, **kwargs): if not plan: @@ -80,9 +85,11 @@ class OwnershipProcessor(BaseProcessor): for change in plan.changes: record = change.record - if not self._is_ownership(record) and \ - record._type not in owned[record.name] and \ - record.name != 'octodns-meta': + if ( + not self._is_ownership(record) + and record._type not in owned[record.name] + and record.name != 'octodns-meta' + ): # It's not an ownership TXT, it's not owned, and it's not # special we're going to ignore it continue @@ -92,8 +99,13 @@ class OwnershipProcessor(BaseProcessor): filtered_changes.append(change) if plan.changes != filtered_changes: - return Plan(plan.existing, plan.desired, filtered_changes, - plan.exists, plan.update_pcent_threshold, - plan.delete_pcent_threshold) + return Plan( + plan.existing, + plan.desired, + filtered_changes, + plan.exists, + plan.update_pcent_threshold, + plan.delete_pcent_threshold, + ) return plan diff --git a/octodns/provider/__init__.py b/octodns/provider/__init__.py index 7e18783..4acfe88 100644 --- a/octodns/provider/__init__.py +++ b/octodns/provider/__init__.py @@ -2,8 +2,12 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) class ProviderException(Exception): diff --git a/octodns/provider/azuredns.py b/octodns/provider/azuredns.py index 3210685..269df2f 100644 --- a/octodns/provider/azuredns.py +++ b/octodns/provider/azuredns.py @@ -2,22 +2,31 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Azure') try: - logger.warning('octodns_azure shimmed. Update your provider class to ' - 'octodns_azure.AzureProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_azure shimmed. Update your provider class to ' + 'octodns_azure.AzureProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_azure import AzureProvider + AzureProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('AzureProvider has been moved into a separate module, ' - 'octodns_azure is now required. Provider class should ' - 'be updated to octodns_azure.AzureProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'AzureProvider has been moved into a separate module, ' + 'octodns_azure is now required. Provider class should ' + 'be updated to octodns_azure.AzureProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/base.py b/octodns/provider/base.py index b524017..78001fa 100644 --- a/octodns/provider/base.py +++ b/octodns/provider/base.py @@ -2,8 +2,12 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from ..source.base import BaseSource from ..zone import Zone @@ -12,19 +16,24 @@ from . import SupportsException class BaseProvider(BaseSource): - - def __init__(self, id, apply_disabled=False, - update_pcent_threshold=Plan.MAX_SAFE_UPDATE_PCENT, - delete_pcent_threshold=Plan.MAX_SAFE_DELETE_PCENT, - strict_supports=False): + def __init__( + self, + id, + apply_disabled=False, + update_pcent_threshold=Plan.MAX_SAFE_UPDATE_PCENT, + delete_pcent_threshold=Plan.MAX_SAFE_DELETE_PCENT, + strict_supports=False, + ): super(BaseProvider, self).__init__(id) - self.log.debug('__init__: id=%s, apply_disabled=%s, ' - 'update_pcent_threshold=%.2f, ' - 'delete_pcent_threshold=%.2f', - id, - apply_disabled, - update_pcent_threshold, - delete_pcent_threshold) + self.log.debug( + '__init__: id=%s, apply_disabled=%s, ' + 'update_pcent_threshold=%.2f, ' + 'delete_pcent_threshold=%.2f', + id, + apply_disabled, + update_pcent_threshold, + delete_pcent_threshold, + ) self.apply_disabled = apply_disabled self.update_pcent_threshold = update_pcent_threshold self.delete_pcent_threshold = delete_pcent_threshold @@ -68,8 +77,10 @@ class BaseProvider(BaseSource): if not unsupported_pools: continue unsupported_pools = ','.join(unsupported_pools) - msg = f'"status" flag used in pools {unsupported_pools}' \ + msg = ( + f'"status" flag used in pools {unsupported_pools}' f' in {record.fqdn} is not supported' + ) fallback = 'will ignore it and respect the healthcheck' self.supports_warn_or_except(msg, fallback) record = record.copy() @@ -84,11 +95,13 @@ class BaseProvider(BaseSource): record = record.copy() record.dynamic = None desired.add_record(record, replace=True) - elif record._type == 'PTR' and len(record.values) > 1 and \ - not self.SUPPORTS_MULTIVALUE_PTR: + elif ( + record._type == 'PTR' + and len(record.values) > 1 + and not self.SUPPORTS_MULTIVALUE_PTR + ): # replace with a single-value copy - msg = \ - f'multi-value PTR records not supported for {record.fqdn}' + msg = f'multi-value PTR records not supported for {record.fqdn}' fallback = f'falling back to single value, {record.value}' self.supports_warn_or_except(msg, fallback) record = record.copy() @@ -98,13 +111,15 @@ class BaseProvider(BaseSource): record = desired.root_ns if self.SUPPORTS_ROOT_NS: if not record: - self.log.warning('root NS record supported, but no record ' - 'is configured for %s', desired.name) + self.log.warning( + 'root NS record supported, but no record ' + 'is configured for %s', + desired.name, + ) else: if record: # we can't manage root NS records, get rid of it - msg = \ - f'root NS record not supported for {record.fqdn}' + msg = f'root NS record not supported for {record.fqdn}' fallback = 'ignoring it' self.supports_warn_or_except(msg, fallback) desired.remove_record(record) @@ -132,10 +147,13 @@ class BaseProvider(BaseSource): ''' existing_root_ns = existing.root_ns - if existing_root_ns and (not self.SUPPORTS_ROOT_NS or - not desired.root_ns): - self.log.info('root NS record in existing, but not supported or ' - 'not configured; ignoring it') + if existing_root_ns and ( + not self.SUPPORTS_ROOT_NS or not desired.root_ns + ): + self.log.info( + 'root NS record in existing, but not supported or ' + 'not configured; ignoring it' + ) existing.remove_record(existing_root_ns) return existing @@ -168,8 +186,10 @@ class BaseProvider(BaseSource): if exists is None: # If your code gets this warning see Source.populate for more # information - self.log.warning('Provider %s used in target mode did not return ' - 'exists', self.id) + self.log.warning( + 'Provider %s used in target mode did not return ' 'exists', + self.id, + ) # Make a (shallow) copy of the desired state so that everything from # now on (in this target) can modify it as they see fit without @@ -194,17 +214,25 @@ class BaseProvider(BaseSource): self.log.info('plan: filtered out %s changes', before - after) # allow the provider to add extra changes it needs - extra = self._extra_changes(existing=existing, desired=desired, - changes=changes) + extra = self._extra_changes( + existing=existing, desired=desired, changes=changes + ) if extra: - self.log.info('plan: extra changes\n %s', '\n ' - .join([str(c) for c in extra])) + self.log.info( + 'plan: extra changes\n %s', + '\n '.join([str(c) for c in extra]), + ) changes += extra if changes: - plan = Plan(existing, desired, changes, exists, - self.update_pcent_threshold, - self.delete_pcent_threshold) + plan = Plan( + existing, + desired, + changes, + exists, + self.update_pcent_threshold, + self.delete_pcent_threshold, + ) self.log.info('plan: %s', plan) return plan self.log.info('plan: No changes') @@ -221,11 +249,11 @@ class BaseProvider(BaseSource): zone_name = plan.desired.name num_changes = len(plan.changes) - self.log.info('apply: making %d changes to %s', num_changes, - zone_name) + self.log.info('apply: making %d changes to %s', num_changes, zone_name) self._apply(plan) return len(plan.changes) def _apply(self, plan): - raise NotImplementedError('Abstract base class, _apply method ' - 'missing') + raise NotImplementedError( + 'Abstract base class, _apply method ' 'missing' + ) diff --git a/octodns/provider/cloudflare.py b/octodns/provider/cloudflare.py index c1a8f56..0014620 100644 --- a/octodns/provider/cloudflare.py +++ b/octodns/provider/cloudflare.py @@ -2,23 +2,32 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Cloudflare') try: - logger.warning('octodns_cloudflare shimmed. Update your provider class to ' - 'octodns_cloudflare.CloudflareProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_cloudflare shimmed. Update your provider class to ' + 'octodns_cloudflare.CloudflareProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_cloudflare import CloudflareProvider + CloudflareProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('CloudflareProvider has been moved into a separate ' - 'module, octodns_cloudflare is now required. Provider ' - 'class should be updated to ' - 'octodns_cloudflare.CloudflareProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'CloudflareProvider has been moved into a separate ' + 'module, octodns_cloudflare is now required. Provider ' + 'class should be updated to ' + 'octodns_cloudflare.CloudflareProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/constellix.py b/octodns/provider/constellix.py index 5159951..5747e9a 100644 --- a/octodns/provider/constellix.py +++ b/octodns/provider/constellix.py @@ -2,23 +2,32 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Constellix') try: - logger.warning('octodns_constellix shimmed. Update your provider class to ' - 'octodns_constellix.ConstellixProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_constellix shimmed. Update your provider class to ' + 'octodns_constellix.ConstellixProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_constellix import ConstellixProvider + ConstellixProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('ConstellixProvider has been moved into a separate ' - 'module, octodns_constellix is now required. Provider ' - 'class should be updated to ' - 'octodns_constellix.ConstellixProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'ConstellixProvider has been moved into a separate ' + 'module, octodns_constellix is now required. Provider ' + 'class should be updated to ' + 'octodns_constellix.ConstellixProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/digitalocean.py b/octodns/provider/digitalocean.py index 9ea59b1..3e1f75e 100644 --- a/octodns/provider/digitalocean.py +++ b/octodns/provider/digitalocean.py @@ -2,23 +2,32 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('DigitalOcean') try: - logger.warning('octodns_digitalocean shimmed. Update your provider class ' - 'to octodns_digitalocean.DigitalOceanProvider. Shim will ' - 'be removed in 1.0') + logger.warning( + 'octodns_digitalocean shimmed. Update your provider class ' + 'to octodns_digitalocean.DigitalOceanProvider. Shim will ' + 'be removed in 1.0' + ) from octodns_digitalocean import DigitalOceanProvider + DigitalOceanProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('DigitalOceanProvider has been moved into a separate ' - 'module, octodns_digitalocean is now required. Provider ' - 'class should be updated to ' - 'octodns_digitalocean.DigitalOceanProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'DigitalOceanProvider has been moved into a separate ' + 'module, octodns_digitalocean is now required. Provider ' + 'class should be updated to ' + 'octodns_digitalocean.DigitalOceanProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/dnsimple.py b/octodns/provider/dnsimple.py index cd379a1..e34a87f 100644 --- a/octodns/provider/dnsimple.py +++ b/octodns/provider/dnsimple.py @@ -2,22 +2,31 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Dnsimple') try: - logger.warning('octodns_dnsimple shimmed. Update your provider class to ' - 'octodns_dnsimple.DnsimpleProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_dnsimple shimmed. Update your provider class to ' + 'octodns_dnsimple.DnsimpleProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_dnsimple import DnsimpleProvider + DnsimpleProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('DnsimpleProvider has been moved into a separate module, ' - 'octodns_dnsimple is now required. Provider class should ' - 'be updated to octodns_dnsimple.DnsimpleProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'DnsimpleProvider has been moved into a separate module, ' + 'octodns_dnsimple is now required. Provider class should ' + 'be updated to octodns_dnsimple.DnsimpleProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/dnsmadeeasy.py b/octodns/provider/dnsmadeeasy.py index fc54c38..cbb28f0 100644 --- a/octodns/provider/dnsmadeeasy.py +++ b/octodns/provider/dnsmadeeasy.py @@ -2,23 +2,32 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('DnsMadeEasy') try: - logger.warning('octodns_dnsmadeeasy shimmed. Update your provider class ' - 'to octodns_dnsmadeeasy.DnsMadeEasyProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_dnsmadeeasy shimmed. Update your provider class ' + 'to octodns_dnsmadeeasy.DnsMadeEasyProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_dnsmadeeasy import DnsMadeEasyProvider + DnsMadeEasyProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('DnsMadeEasyProvider has been moved into a separate ' - 'module, octodns_dnsmadeeasy is now required. Provider ' - 'class should be updated to ' - 'octodns_dnsmadeeasy.DnsMadeEasyProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'DnsMadeEasyProvider has been moved into a separate ' + 'module, octodns_dnsmadeeasy is now required. Provider ' + 'class should be updated to ' + 'octodns_dnsmadeeasy.DnsMadeEasyProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/dyn.py b/octodns/provider/dyn.py index eef3a7a..e7c1120 100644 --- a/octodns/provider/dyn.py +++ b/octodns/provider/dyn.py @@ -2,22 +2,31 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Dyn') try: - logger.warning('octodns_dyn shimmed. Update your provider class to ' - 'octodns_dyn.DynProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_dyn shimmed. Update your provider class to ' + 'octodns_dyn.DynProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_dyn import DynProvider + DynProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('DynProvider has been moved into a separate module, ' - 'octodns_dyn is now required. Provider class should ' - 'be updated to octodns_dyn.DynProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'DynProvider has been moved into a separate module, ' + 'octodns_dyn is now required. Provider class should ' + 'be updated to octodns_dyn.DynProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/easydns.py b/octodns/provider/easydns.py index 7be551b..6dc5c8b 100644 --- a/octodns/provider/easydns.py +++ b/octodns/provider/easydns.py @@ -2,23 +2,32 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('EasyDns') try: - logger.warning('octodns_easydns shimmed. Update your provider class to ' - 'octodns_easydns.EasyDnsProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_easydns shimmed. Update your provider class to ' + 'octodns_easydns.EasyDnsProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_easydns import EasyDnsProvider, EasyDNSProvider + EasyDnsProvider # pragma: no cover EasyDNSProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('EasyDNSProvider has been moved into a separate module, ' - 'octodns_easydns is now required. Provider class should ' - 'be updated to octodns_easydns.EasyDnsProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'EasyDNSProvider has been moved into a separate module, ' + 'octodns_easydns is now required. Provider class should ' + 'be updated to octodns_easydns.EasyDnsProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/edgedns.py b/octodns/provider/edgedns.py index 8e1e58c..ca439ee 100644 --- a/octodns/provider/edgedns.py +++ b/octodns/provider/edgedns.py @@ -2,22 +2,31 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Akamai') try: - logger.warning('octodns_edgedns shimmed. Update your provider class to ' - 'octodns_edgedns.AkamaiProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_edgedns shimmed. Update your provider class to ' + 'octodns_edgedns.AkamaiProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_edgedns import AkamaiProvider + AkamaiProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('AkamaiProvider has been moved into a separate module, ' - 'octodns_edgedns is now required. Provider class should ' - 'be updated to octodns_edgedns.AkamaiProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'AkamaiProvider has been moved into a separate module, ' + 'octodns_edgedns is now required. Provider class should ' + 'be updated to octodns_edgedns.AkamaiProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/etc_hosts.py b/octodns/provider/etc_hosts.py index 4ae9ee9..e903dd2 100644 --- a/octodns/provider/etc_hosts.py +++ b/octodns/provider/etc_hosts.py @@ -2,22 +2,31 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('EtcHosts') try: - logger.warning('octodns_etchosts shimmed. Update your provider class to ' - 'octodns_etchosts.EtcHostsProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_etchosts shimmed. Update your provider class to ' + 'octodns_etchosts.EtcHostsProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_etchosts import EtcHostsProvider + EtcHostsProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('EtcHostsProvider has been moved into a separate module, ' - 'octodns_etchosts is now required. Provider class should ' - 'be updated to octodns_etchosts.EtcHostsProvider. See ' - 'See https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'EtcHostsProvider has been moved into a separate module, ' + 'octodns_etchosts is now required. Provider class should ' + 'be updated to octodns_etchosts.EtcHostsProvider. See ' + 'See https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/fastdns.py b/octodns/provider/fastdns.py index 9dd1490..0164be5 100644 --- a/octodns/provider/fastdns.py +++ b/octodns/provider/fastdns.py @@ -2,14 +2,20 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Akamai') -logger.warning('AkamaiProvider has been moved into a separate module, ' - 'octodns_edgedns is now required. Provider class should ' - 'be updated to octodns_edgedns.AkamaiProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') +logger.warning( + 'AkamaiProvider has been moved into a separate module, ' + 'octodns_edgedns is now required. Provider class should ' + 'be updated to octodns_edgedns.AkamaiProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' +) diff --git a/octodns/provider/gandi.py b/octodns/provider/gandi.py index 2429bfa..4e08be0 100644 --- a/octodns/provider/gandi.py +++ b/octodns/provider/gandi.py @@ -2,22 +2,31 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Gandi') try: - logger.warning('octodns_gandi shimmed. Update your provider class to ' - 'octodns_gandi.GandiProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_gandi shimmed. Update your provider class to ' + 'octodns_gandi.GandiProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_gandi import GandiProvider + GandiProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('GandiProvider has been moved into a separate module, ' - 'octodns_gandi is now required. Provider class should ' - 'be updated to octodns_gandi.GandiProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'GandiProvider has been moved into a separate module, ' + 'octodns_gandi is now required. Provider class should ' + 'be updated to octodns_gandi.GandiProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/gcore.py b/octodns/provider/gcore.py index 141ed10..983ff1d 100644 --- a/octodns/provider/gcore.py +++ b/octodns/provider/gcore.py @@ -2,22 +2,31 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('GCore') try: - logger.warning('octodns_gcore shimmed. Update your provider class to ' - 'octodns_gcore.GCoreProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_gcore shimmed. Update your provider class to ' + 'octodns_gcore.GCoreProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_gcore import GCoreProvider + GCoreProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('GCoreProvider has been moved into a separate module, ' - 'octodns_gcore is now required. Provider class should ' - 'be updated to octodns_gcore.GCoreProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'GCoreProvider has been moved into a separate module, ' + 'octodns_gcore is now required. Provider class should ' + 'be updated to octodns_gcore.GCoreProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/googlecloud.py b/octodns/provider/googlecloud.py index 22cb07a..b772f36 100644 --- a/octodns/provider/googlecloud.py +++ b/octodns/provider/googlecloud.py @@ -2,23 +2,32 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('GoogleCloud') try: - logger.warning('octodns_googlecloud shimmed. Update your provider class ' - 'to octodns_googlecloud.GoogleCloudProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_googlecloud shimmed. Update your provider class ' + 'to octodns_googlecloud.GoogleCloudProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_googlecloud import GoogleCloudProvider + GoogleCloudProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('GoogleCloudProvider has been moved into a separate ' - 'module, octodns_googlecloud is now required. Provider ' - 'class should be updated to ' - 'octodns_googlecloud.GoogleCloudProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'GoogleCloudProvider has been moved into a separate ' + 'module, octodns_googlecloud is now required. Provider ' + 'class should be updated to ' + 'octodns_googlecloud.GoogleCloudProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/hetzner.py b/octodns/provider/hetzner.py index 38577e4..b0f362e 100644 --- a/octodns/provider/hetzner.py +++ b/octodns/provider/hetzner.py @@ -2,22 +2,31 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Hetzner') try: - logger.warning('octodns_hetzner shimmed. Update your provider class to ' - 'octodns_hetzner.HetznerProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_hetzner shimmed. Update your provider class to ' + 'octodns_hetzner.HetznerProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_hetzner import HetznerProvider + HetznerProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('HetznerProvider has been moved into a separate module, ' - 'octodns_hetzner is now required. Provider class should ' - 'be updated to octodns_hetzner.HetznerProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'HetznerProvider has been moved into a separate module, ' + 'octodns_hetzner is now required. Provider class should ' + 'be updated to octodns_hetzner.HetznerProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/mythicbeasts.py b/octodns/provider/mythicbeasts.py index 0d1378e..708124a 100644 --- a/octodns/provider/mythicbeasts.py +++ b/octodns/provider/mythicbeasts.py @@ -2,23 +2,32 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('MythicBeasts') try: - logger.warning('octodns_mythicbeasts shimmed. Update your provider class ' - 'to octodns_mythicbeasts.MythicBeastsProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_mythicbeasts shimmed. Update your provider class ' + 'to octodns_mythicbeasts.MythicBeastsProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_mythicbeasts import MythicBeastsProvider + MythicBeastsProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('MythicBeastsProvider has been moved into a separate ' - 'module, octodns_mythicbeasts is now required. Provider ' - 'class should be updated to ' - 'octodns_mythicbeasts.MythicBeastsProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'MythicBeastsProvider has been moved into a separate ' + 'module, octodns_mythicbeasts is now required. Provider ' + 'class should be updated to ' + 'octodns_mythicbeasts.MythicBeastsProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/ns1.py b/octodns/provider/ns1.py index 76398a8..9d60570 100644 --- a/octodns/provider/ns1.py +++ b/octodns/provider/ns1.py @@ -2,22 +2,31 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Ns1') try: - logger.warning('octodns_ns1 shimmed. Update your provider class to ' - 'octodns_ns1.Ns1Provider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_ns1 shimmed. Update your provider class to ' + 'octodns_ns1.Ns1Provider. ' + 'Shim will be removed in 1.0' + ) from octodns_ns1 import Ns1Provider + Ns1Provider # pragma: no cover except ModuleNotFoundError: - logger.exception('Ns1Provider has been moved into a separate module, ' - 'octodns_ns1 is now required. Provider class should ' - 'be updated to octodns_ns1.Ns1Provider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'Ns1Provider has been moved into a separate module, ' + 'octodns_ns1 is now required. Provider class should ' + 'be updated to octodns_ns1.Ns1Provider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/ovh.py b/octodns/provider/ovh.py index 5f83560..de6f045 100644 --- a/octodns/provider/ovh.py +++ b/octodns/provider/ovh.py @@ -2,22 +2,31 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import getLogger logger = getLogger('Ovh') try: - logger.warning('octodns_ovh shimmed. Update your provider class to ' - 'octodns_ovh.OvhProvider. ' - 'Shim will be removed in 1.0') + logger.warning( + 'octodns_ovh shimmed. Update your provider class to ' + 'octodns_ovh.OvhProvider. ' + 'Shim will be removed in 1.0' + ) from octodns_ovh import OvhProvider + OvhProvider # pragma: no cover except ModuleNotFoundError: - logger.exception('OvhProvider has been moved into a separate module, ' - 'octodns_ovh is now required. Provider class should ' - 'be updated to octodns_ovh.OvhProvider. See ' - 'https://github.com/octodns/octodns#updating-' - 'to-use-extracted-providers for more information.') + logger.exception( + 'OvhProvider has been moved into a separate module, ' + 'octodns_ovh is now required. Provider class should ' + 'be updated to octodns_ovh.OvhProvider. See ' + 'https://github.com/octodns/octodns#updating-' + 'to-use-extracted-providers for more information.' + ) raise diff --git a/octodns/provider/plan.py b/octodns/provider/plan.py index 2d39c80..a436483 100644 --- a/octodns/provider/plan.py +++ b/octodns/provider/plan.py @@ -2,8 +2,12 @@ # # -from __future__ import absolute_import, division, print_function, \ - unicode_literals +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) from logging import DEBUG, ERROR, INFO, WARN, getLogger from sys import stdout @@ -16,30 +20,37 @@ class UnsafePlan(Exception): class RootNsChange(UnsafePlan): - def __init__(self): super().__init__('Root NS record change, force required') class TooMuchChange(UnsafePlan): - - def __init__(self, why, update_pcent, update_threshold, change_count, - existing_count): - msg = f'{why}, {update_pcent:.2f}% is over {update_threshold:.2f}% ' \ + def __init__( + self, why, update_pcent, update_threshold, change_count, existing_count + ): + msg = ( + f'{why}, {update_pcent:.2f}% is over {update_threshold:.2f}% ' f'({change_count}/{existing_count}), force required' + ) super().__init__(msg) class Plan(object): log = getLogger('Plan') - MAX_SAFE_UPDATE_PCENT = .3 - MAX_SAFE_DELETE_PCENT = .3 + MAX_SAFE_UPDATE_PCENT = 0.3 + MAX_SAFE_DELETE_PCENT = 0.3 MIN_EXISTING_RECORDS = 10 - def __init__(self, existing, desired, changes, exists, - update_pcent_threshold=MAX_SAFE_UPDATE_PCENT, - delete_pcent_threshold=MAX_SAFE_DELETE_PCENT): + def __init__( + self, + existing, + desired, + changes, + exists, + update_pcent_threshold=MAX_SAFE_UPDATE_PCENT, + delete_pcent_threshold=MAX_SAFE_DELETE_PCENT, + ): self.existing = existing self.desired = desired # Sort changes to ensure we always have a consistent ordering for @@ -51,11 +62,7 @@ class Plan(object): self.update_pcent_threshold = update_pcent_threshold self.delete_pcent_threshold = delete_pcent_threshold - change_counts = { - 'Create': 0, - 'Delete': 0, - 'Update': 0 - } + change_counts = {'Create': 0, 'Delete': 0, 'Update': 0} for change in changes: change_counts[change.__class__.__name__] += 1 self.change_counts = change_counts @@ -65,43 +72,57 @@ class Plan(object): except AttributeError: existing_n = 0 - self.log.debug('__init__: Creates=%d, Updates=%d, Deletes=%d ' - 'Existing=%d', - self.change_counts['Create'], - self.change_counts['Update'], - self.change_counts['Delete'], existing_n) + self.log.debug( + '__init__: Creates=%d, Updates=%d, Deletes=%d ' 'Existing=%d', + self.change_counts['Create'], + self.change_counts['Update'], + self.change_counts['Delete'], + existing_n, + ) def raise_if_unsafe(self): # TODO: what is safe really? - if self.existing and \ - len(self.existing.records) >= self.MIN_EXISTING_RECORDS: + if ( + self.existing + and len(self.existing.records) >= self.MIN_EXISTING_RECORDS + ): existing_record_count = len(self.existing.records) if existing_record_count > 0: - update_pcent = (self.change_counts['Update'] / - existing_record_count) - delete_pcent = (self.change_counts['Delete'] / - existing_record_count) + update_pcent = ( + self.change_counts['Update'] / existing_record_count + ) + delete_pcent = ( + self.change_counts['Delete'] / existing_record_count + ) else: update_pcent = 0 delete_pcent = 0 if update_pcent > self.update_pcent_threshold: - raise TooMuchChange('Too many updates', update_pcent * 100, - self.update_pcent_threshold * 100, - self.change_counts['Update'], - existing_record_count) + raise TooMuchChange( + 'Too many updates', + update_pcent * 100, + self.update_pcent_threshold * 100, + self.change_counts['Update'], + existing_record_count, + ) if delete_pcent > self.delete_pcent_threshold: - raise TooMuchChange('Too many deletes', delete_pcent * 100, - self.delete_pcent_threshold * 100, - self.change_counts['Delete'], - existing_record_count) + raise TooMuchChange( + 'Too many deletes', + delete_pcent * 100, + self.delete_pcent_threshold * 100, + self.change_counts['Delete'], + existing_record_count, + ) # If we have any changes of the root NS record for the zone it's a huge # deal and force should always be required for extra care - if self.exists and any(c for c in self.changes - if c.record and c.record._type == 'NS' and - c.record.name == ''): + if self.exists and any( + c + for c in self.changes + if c.record and c.record._type == 'NS' and c.record.name == '' + ): raise RootNsChange() def __repr__(self): @@ -109,18 +130,18 @@ class Plan(object): updates = self.change_counts['Update'] deletes = self.change_counts['Delete'] existing = len(self.existing.records) - return f'Creates={creates}, Updates={updates}, Deletes={deletes}, ' \ + return ( + f'Creates={creates}, Updates={updates}, Deletes={deletes}, ' f'Existing Records={existing}' + ) class _PlanOutput(object): - def __init__(self, name): self.name = name class PlanLogger(_PlanOutput): - def __init__(self, name, level='info'): super(PlanLogger, self).__init__(name) try: @@ -129,14 +150,16 @@ class PlanLogger(_PlanOutput): 'info': INFO, 'warn': WARN, 'warning': WARN, - 'error': ERROR + 'error': ERROR, }[level.lower()] except (AttributeError, KeyError): raise Exception(f'Unsupported level: {level}') def run(self, log, plans, *args, **kwargs): - hr = '*************************************************************' \ + hr = ( + '*************************************************************' '*******************\n' + ) buf = StringIO() buf.write('\n') if plans: @@ -188,7 +211,6 @@ def _value_stringifier(record, sep): class PlanMarkdown(_PlanOutput): - def run(self, plans, fh=stdout, *args, **kwargs): if plans: current_zone = None @@ -203,8 +225,10 @@ class PlanMarkdown(_PlanOutput): fh.write(target.id) fh.write('\n\n') - fh.write('| Operation | Name | Type | TTL | Value | Source |\n' - '|--|--|--|--|--|--|\n') + fh.write( + '| Operation | Name | Type | TTL | Value | Source |\n' + '|--|--|--|--|--|--|\n' + ) if plan.exists is False: fh.write('| Create | ') @@ -248,7 +272,6 @@ class PlanMarkdown(_PlanOutput): class PlanHtml(_PlanOutput): - def run(self, plans, fh=stdout, *args, **kwargs): if plans: current_zone = None @@ -261,7 +284,8 @@ class PlanHtml(_PlanOutput): fh.write('
Operation | @@ -271,7 +295,8 @@ class PlanHtml(_PlanOutput):Value | Source | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Create | \n')
diff --git a/octodns/provider/powerdns.py b/octodns/provider/powerdns.py
index 7a28f46..fd76abf 100644
--- a/octodns/provider/powerdns.py
+++ b/octodns/provider/powerdns.py
@@ -2,23 +2,32 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from logging import getLogger
logger = getLogger('PowerDns')
try:
- logger.warning('octodns_powerdns shimmed. Update your provider class to '
- 'octodns_powerdns.PowerDnsProvider. '
- 'Shim will be removed in 1.0')
+ logger.warning(
+ 'octodns_powerdns shimmed. Update your provider class to '
+ 'octodns_powerdns.PowerDnsProvider. '
+ 'Shim will be removed in 1.0'
+ )
from octodns_powerdns import PowerDnsProvider, PowerDnsBaseProvider
+
PowerDnsProvider # pragma: no cover
PowerDnsBaseProvider # pragma: no cover
except ModuleNotFoundError:
- logger.exception('PowerDnsProvider has been moved into a separate module, '
- 'octodns_powerdns is now required. Provider class should '
- 'be updated to octodns_powerdns.PowerDnsProvider. See '
- 'https://github.com/octodns/octodns#updating-'
- 'to-use-extracted-providers for more information.')
+ logger.exception(
+ 'PowerDnsProvider has been moved into a separate module, '
+ 'octodns_powerdns is now required. Provider class should '
+ 'be updated to octodns_powerdns.PowerDnsProvider. See '
+ 'https://github.com/octodns/octodns#updating-'
+ 'to-use-extracted-providers for more information.'
+ )
raise
diff --git a/octodns/provider/rackspace.py b/octodns/provider/rackspace.py
index 77436be..58b3443 100644
--- a/octodns/provider/rackspace.py
+++ b/octodns/provider/rackspace.py
@@ -2,23 +2,32 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from logging import getLogger
logger = getLogger('Rackspace')
try:
- logger.warning('octodns_rackspace shimmed. Update your provider class to '
- 'octodns_rackspace.RackspaceProvider. '
- 'Shim will be removed in 1.0')
+ logger.warning(
+ 'octodns_rackspace shimmed. Update your provider class to '
+ 'octodns_rackspace.RackspaceProvider. '
+ 'Shim will be removed in 1.0'
+ )
from octodns_rackspace import RackspaceProvider
+
RackspaceProvider # pragma: no cover
except ModuleNotFoundError:
- logger.exception('RackspaceProvider has been moved into a separate '
- 'module, octodns_rackspace is now required. Provider '
- 'class should be updated to '
- 'octodns_rackspace.RackspaceProvider. See '
- 'https://github.com/octodns/octodns#updating-'
- 'to-use-extracted-providers for more information.')
+ logger.exception(
+ 'RackspaceProvider has been moved into a separate '
+ 'module, octodns_rackspace is now required. Provider '
+ 'class should be updated to '
+ 'octodns_rackspace.RackspaceProvider. See '
+ 'https://github.com/octodns/octodns#updating-'
+ 'to-use-extracted-providers for more information.'
+ )
raise
diff --git a/octodns/provider/route53.py b/octodns/provider/route53.py
index 744281e..f5937c0 100644
--- a/octodns/provider/route53.py
+++ b/octodns/provider/route53.py
@@ -2,22 +2,31 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from logging import getLogger
logger = getLogger('Route53')
try:
- logger.warning('octodns_route53 shimmed. Update your provider class to '
- 'octodns_route53.Route53Provider. '
- 'Shim will be removed in 1.0')
+ logger.warning(
+ 'octodns_route53 shimmed. Update your provider class to '
+ 'octodns_route53.Route53Provider. '
+ 'Shim will be removed in 1.0'
+ )
from octodns_route53 import Route53Provider
+
Route53Provider # pragma: no cover
except ModuleNotFoundError:
- logger.exception('Route53Provider has been moved into a separate module, '
- 'octodns_route53 is now required. Provider class should '
- 'be updated to octodns_route53.Route53Provider. See '
- 'https://github.com/octodns/octodns#updating-'
- 'to-use-extracted-providers for more information.')
+ logger.exception(
+ 'Route53Provider has been moved into a separate module, '
+ 'octodns_route53 is now required. Provider class should '
+ 'be updated to octodns_route53.Route53Provider. See '
+ 'https://github.com/octodns/octodns#updating-'
+ 'to-use-extracted-providers for more information.'
+ )
raise
diff --git a/octodns/provider/selectel.py b/octodns/provider/selectel.py
index 44325db..04fcf7b 100644
--- a/octodns/provider/selectel.py
+++ b/octodns/provider/selectel.py
@@ -2,22 +2,31 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from logging import getLogger
logger = getLogger('Selectel')
try:
- logger.warning('octodns_selectel shimmed. Update your provider class to '
- 'octodns_selectel.SelectelProvider. '
- 'Shim will be removed in 1.0')
+ logger.warning(
+ 'octodns_selectel shimmed. Update your provider class to '
+ 'octodns_selectel.SelectelProvider. '
+ 'Shim will be removed in 1.0'
+ )
from octodns_selectel import SelectelProvider
+
SelectelProvider # pragma: no cover
except ModuleNotFoundError:
- logger.exception('SelectelProvider has been moved into a separate module, '
- 'octodns_selectel is now required. Provider class should '
- 'be updated to octodns_selectel.SelectelProvider. See '
- 'https://github.com/octodns/octodns#updating-'
- 'to-use-extracted-providers for more information.')
+ logger.exception(
+ 'SelectelProvider has been moved into a separate module, '
+ 'octodns_selectel is now required. Provider class should '
+ 'be updated to octodns_selectel.SelectelProvider. See '
+ 'https://github.com/octodns/octodns#updating-'
+ 'to-use-extracted-providers for more information.'
+ )
raise
diff --git a/octodns/provider/transip.py b/octodns/provider/transip.py
index 5282b42..c6c1e8c 100644
--- a/octodns/provider/transip.py
+++ b/octodns/provider/transip.py
@@ -2,22 +2,31 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from logging import getLogger
logger = getLogger('Transip')
try:
- logger.warning('octodns_transip shimmed. Update your provider class to '
- 'octodns_transip.TransipProvider. '
- 'Shim will be removed in 1.0')
+ logger.warning(
+ 'octodns_transip shimmed. Update your provider class to '
+ 'octodns_transip.TransipProvider. '
+ 'Shim will be removed in 1.0'
+ )
from octodns_transip import TransipProvider
+
TransipProvider # pragma: no cover
except ModuleNotFoundError:
- logger.exception('TransipProvider has been moved into a separate module, '
- 'octodns_transip is now required. Provider class should '
- 'be updated to octodns_transip.TransipProvider. See '
- 'https://github.com/octodns/octodns#updating-'
- 'to-use-extracted-providers for more information.')
+ logger.exception(
+ 'TransipProvider has been moved into a separate module, '
+ 'octodns_transip is now required. Provider class should '
+ 'be updated to octodns_transip.TransipProvider. See '
+ 'https://github.com/octodns/octodns#updating-'
+ 'to-use-extracted-providers for more information.'
+ )
raise
diff --git a/octodns/provider/ultra.py b/octodns/provider/ultra.py
index 6ccaf7a..271621b 100644
--- a/octodns/provider/ultra.py
+++ b/octodns/provider/ultra.py
@@ -2,22 +2,31 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from logging import getLogger
logger = getLogger('Ultra')
try:
- logger.warning('octodns_ultra shimmed. Update your provider class to '
- 'octodns_ultra.UltraProvider. '
- 'Shim will be removed in 1.0')
+ logger.warning(
+ 'octodns_ultra shimmed. Update your provider class to '
+ 'octodns_ultra.UltraProvider. '
+ 'Shim will be removed in 1.0'
+ )
from octodns_ultra import UltraProvider
+
UltraProvider # pragma: no cover
except ModuleNotFoundError:
- logger.exception('UltraProvider has been moved into a separate module, '
- 'octodns_ultra is now required. Provider class should '
- 'be updated to octodns_ultra.UltraProvider. See '
- 'https://github.com/octodns/octodns#updating-'
- 'to-use-extracted-providers for more information.')
+ logger.exception(
+ 'UltraProvider has been moved into a separate module, '
+ 'octodns_ultra is now required. Provider class should '
+ 'be updated to octodns_ultra.UltraProvider. See '
+ 'https://github.com/octodns/octodns#updating-'
+ 'to-use-extracted-providers for more information.'
+ )
raise
diff --git a/octodns/provider/yaml.py b/octodns/provider/yaml.py
index 16a4bc1..9ad0934 100644
--- a/octodns/provider/yaml.py
+++ b/octodns/provider/yaml.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from collections import defaultdict
from os import listdir, makedirs
@@ -102,23 +106,54 @@ class YamlProvider(BaseProvider):
`--config-file=internal.yaml`
'''
+
SUPPORTS_GEO = True
SUPPORTS_DYNAMIC = True
SUPPORTS_POOL_VALUE_STATUS = True
SUPPORTS_MULTIVALUE_PTR = True
- SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CAA', 'CNAME', 'DNAME', 'LOC', 'MX',
- 'NAPTR', 'NS', 'PTR', 'SSHFP', 'SPF', 'SRV', 'TXT',
- 'URLFWD'))
+ SUPPORTS = set(
+ (
+ 'A',
+ 'AAAA',
+ 'ALIAS',
+ 'CAA',
+ 'CNAME',
+ 'DNAME',
+ 'LOC',
+ 'MX',
+ 'NAPTR',
+ 'NS',
+ 'PTR',
+ 'SSHFP',
+ 'SPF',
+ 'SRV',
+ 'TXT',
+ 'URLFWD',
+ )
+ )
- def __init__(self, id, directory, default_ttl=3600, enforce_order=True,
- populate_should_replace=False, supports_root_ns=True,
- *args, **kwargs):
+ def __init__(
+ self,
+ id,
+ directory,
+ default_ttl=3600,
+ enforce_order=True,
+ populate_should_replace=False,
+ supports_root_ns=True,
+ *args,
+ **kwargs,
+ ):
klass = self.__class__.__name__
self.log = logging.getLogger(f'{klass}[{id}]')
- self.log.debug('__init__: id=%s, directory=%s, default_ttl=%d, '
- 'enforce_order=%d, populate_should_replace=%d',
- id, directory, default_ttl, enforce_order,
- populate_should_replace)
+ self.log.debug(
+ '__init__: id=%s, directory=%s, default_ttl=%d, '
+ 'enforce_order=%d, populate_should_replace=%d',
+ id,
+ directory,
+ default_ttl,
+ enforce_order,
+ populate_should_replace,
+ )
super(YamlProvider, self).__init__(id, *args, **kwargs)
self.directory = directory
self.default_ttl = default_ttl
@@ -126,6 +161,12 @@ class YamlProvider(BaseProvider):
self.populate_should_replace = populate_should_replace
self.supports_root_ns = supports_root_ns
+ def copy(self):
+ args = dict(self.__dict__)
+ args['id'] = f'{args["id"]}-copy'
+ del args['log']
+ return self.__class__(**args)
+
@property
def SUPPORTS_ROOT_NS(self):
return self.supports_root_ns
@@ -140,16 +181,25 @@ class YamlProvider(BaseProvider):
for d in data:
if 'ttl' not in d:
d['ttl'] = self.default_ttl
- record = Record.new(zone, name, d, source=self,
- lenient=lenient)
- zone.add_record(record, lenient=lenient,
- replace=self.populate_should_replace)
- self.log.debug('_populate_from_file: successfully loaded "%s"',
- filename)
+ record = Record.new(
+ zone, name, d, source=self, lenient=lenient
+ )
+ zone.add_record(
+ record,
+ lenient=lenient,
+ replace=self.populate_should_replace,
+ )
+ self.log.debug(
+ '_populate_from_file: successfully loaded "%s"', filename
+ )
def populate(self, zone, target=False, lenient=False):
- self.log.debug('populate: name=%s, target=%s, lenient=%s', zone.name,
- target, lenient)
+ self.log.debug(
+ 'populate: name=%s, target=%s, lenient=%s',
+ zone.name,
+ target,
+ lenient,
+ )
if target:
# When acting as a target we ignore any existing records so that we
@@ -160,15 +210,18 @@ class YamlProvider(BaseProvider):
filename = join(self.directory, f'{zone.name}yaml')
self._populate_from_file(filename, zone, lenient)
- self.log.info('populate: found %s records, exists=False',
- len(zone.records) - before)
+ self.log.info(
+ 'populate: found %s records, exists=False',
+ len(zone.records) - before,
+ )
return False
def _apply(self, plan):
desired = plan.desired
changes = plan.changes
- self.log.debug('_apply: zone=%s, len(changes)=%d', desired.name,
- len(changes))
+ self.log.debug(
+ '_apply: zone=%s, len(changes)=%d', desired.name, len(changes)
+ )
# Since we don't have existing we'll only see creates
records = [c.new for c in changes]
# Order things alphabetically (records sort that way
@@ -257,8 +310,12 @@ class SplitYamlProvider(YamlProvider):
return join(self.directory, filename)
def populate(self, zone, target=False, lenient=False):
- self.log.debug('populate: name=%s, target=%s, lenient=%s', zone.name,
- target, lenient)
+ self.log.debug(
+ 'populate: name=%s, target=%s, lenient=%s',
+ zone.name,
+ target,
+ lenient,
+ )
if target:
# When acting as a target we ignore any existing records so that we
@@ -271,8 +328,10 @@ class SplitYamlProvider(YamlProvider):
for yaml_filename in yaml_filenames:
self._populate_from_file(yaml_filename, zone, lenient)
- self.log.info('populate: found %s records, exists=False',
- len(zone.records) - before)
+ self.log.info(
+ 'populate: found %s records, exists=False',
+ len(zone.records) - before,
+ )
return False
def _do_apply(self, desired, data):
diff --git a/octodns/record/__init__.py b/octodns/record/__init__.py
index 9c520f5..d7c6be4 100644
--- a/octodns/record/__init__.py
+++ b/octodns/record/__init__.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from ipaddress import IPv4Address, IPv6Address
from logging import getLogger
@@ -16,7 +20,6 @@ from .geo import GeoCodes
class Change(EqualityTupleMixin):
-
def __init__(self, existing, new):
self.existing = existing
self.new = new
@@ -50,8 +53,10 @@ class Update(Change):
# do nothing
def __repr__(self, leader=''):
source = self.new.source.id if self.new.source else ''
- return f'Update\n{leader} {self.existing} ->\n' \
+ return (
+ f'Update\n{leader} {self.existing} ->\n'
f'{leader} {self.new} ({source})'
+ )
class Delete(Change):
@@ -69,7 +74,6 @@ class RecordException(Exception):
class ValidationError(RecordException):
-
@classmethod
def build_message(cls, fqdn, reasons):
reasons = '\n - '.join(reasons)
@@ -129,13 +133,17 @@ class Record(EqualityTupleMixin):
reasons.append('invalid name "@", use "" instead')
n = len(fqdn)
if n > 253:
- reasons.append(f'invalid fqdn, "{fqdn}" is too long at {n} '
- 'chars, max is 253')
+ reasons.append(
+ f'invalid fqdn, "{fqdn}" is too long at {n} '
+ 'chars, max is 253'
+ )
for label in name.split('.'):
n = len(label)
if n > 63:
- reasons.append(f'invalid label, "{label}" is too long at {n}'
- ' chars, max is 63')
+ reasons.append(
+ f'invalid label, "{label}" is too long at {n}'
+ ' chars, max is 63'
+ )
try:
ttl = int(data['ttl'])
if ttl < 0:
@@ -143,16 +151,23 @@ class Record(EqualityTupleMixin):
except KeyError:
reasons.append('missing ttl')
try:
- if data['octodns']['healthcheck']['protocol'] \
- not in ('HTTP', 'HTTPS', 'TCP'):
+ if data['octodns']['healthcheck']['protocol'] not in (
+ 'HTTP',
+ 'HTTPS',
+ 'TCP',
+ ):
reasons.append('invalid healthcheck protocol')
except KeyError:
pass
return reasons
def __init__(self, zone, name, data, source=None):
- self.log.debug('__init__: zone.name=%s, type=%11s, name=%s', zone.name,
- self.__class__.__name__, name)
+ self.log.debug(
+ '__init__: zone.name=%s, type=%11s, name=%s',
+ zone.name,
+ self.__class__.__name__,
+ name,
+ )
self.zone = zone
# force everything lower-case just to be safe
self.name = str(name).lower() if name else name
@@ -231,7 +246,7 @@ class Record(EqualityTupleMixin):
self.name,
data,
self.source,
- lenient=True
+ lenient=True,
)
# NOTE: we're using __hash__ and ordering methods that consider Records
@@ -250,8 +265,10 @@ class Record(EqualityTupleMixin):
class GeoValue(EqualityTupleMixin):
- geo_re = re.compile(r'^(?PSummary: Creates=2, Updates=1, '
- 'Deletes=1, Existing Records=0 | ' in out)
+ self.assertTrue(
+ ' Summary: Creates=2, Updates=1, '
+ 'Deletes=1, Existing Records=0 | ' in out
+ )
class TestPlanMarkdown(TestCase):
@@ -139,7 +154,6 @@ class TestPlanMarkdown(TestCase):
class HelperPlan(Plan):
-
def __init__(self, *args, min_existing=0, **kwargs):
super().__init__(*args, **kwargs)
self.MIN_EXISTING_RECORDS = min_existing
@@ -147,26 +161,18 @@ class HelperPlan(Plan):
class TestPlanSafety(TestCase):
existing = Zone('unit.tests.', [])
- record_1 = Record.new(existing, '1', data={
- 'type': 'A',
- 'ttl': 42,
- 'value': '1.2.3.4',
- })
- record_2 = Record.new(existing, '2', data={
- 'type': 'A',
- 'ttl': 42,
- 'value': '1.2.3.4',
- })
- record_3 = Record.new(existing, '3', data={
- 'type': 'A',
- 'ttl': 42,
- 'value': '1.2.3.4',
- })
- record_4 = Record.new(existing, '4', data={
- 'type': 'A',
- 'ttl': 42,
- 'value': '1.2.3.4',
- })
+ record_1 = Record.new(
+ existing, '1', data={'type': 'A', 'ttl': 42, 'value': '1.2.3.4'}
+ )
+ record_2 = Record.new(
+ existing, '2', data={'type': 'A', 'ttl': 42, 'value': '1.2.3.4'}
+ )
+ record_3 = Record.new(
+ existing, '3', data={'type': 'A', 'ttl': 42, 'value': '1.2.3.4'}
+ )
+ record_4 = Record.new(
+ existing, '4', data={'type': 'A', 'ttl': 42, 'value': '1.2.3.4'}
+ )
def test_too_many_updates(self):
existing = self.existing.copy()
@@ -267,11 +273,15 @@ class TestPlanSafety(TestCase):
plan.raise_if_unsafe()
# Add a change to a non-root NS record, we're OK
- ns_record = Record.new(existing, 'sub', data={
- 'type': 'NS',
- 'ttl': 43,
- 'values': ('ns1.unit.tests.', 'ns1.unit.tests.'),
- })
+ ns_record = Record.new(
+ existing,
+ 'sub',
+ data={
+ 'type': 'NS',
+ 'ttl': 43,
+ 'values': ('ns1.unit.tests.', 'ns1.unit.tests.'),
+ },
+ )
changes.append(Delete(ns_record))
plan = HelperPlan(existing, None, changes, True)
plan.raise_if_unsafe()
@@ -279,11 +289,15 @@ class TestPlanSafety(TestCase):
changes.pop(-1)
# Delete the root NS record and we get an unsafe
- root_ns_record = Record.new(existing, '', data={
- 'type': 'NS',
- 'ttl': 43,
- 'values': ('ns3.unit.tests.', 'ns4.unit.tests.'),
- })
+ root_ns_record = Record.new(
+ existing,
+ '',
+ data={
+ 'type': 'NS',
+ 'ttl': 43,
+ 'values': ('ns3.unit.tests.', 'ns4.unit.tests.'),
+ },
+ )
changes.append(Delete(root_ns_record))
plan = HelperPlan(existing, None, changes, True)
with self.assertRaises(RootNsChange) as ctx:
diff --git a/tests/test_octodns_processor_acme.py b/tests/test_octodns_processor_acme.py
index 505d15c..78a4f5d 100644
--- a/tests/test_octodns_processor_acme.py
+++ b/tests/test_octodns_processor_acme.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
@@ -13,46 +17,43 @@ from octodns.zone import Zone
zone = Zone('unit.tests.', [])
records = {
- 'root-unowned': Record.new(zone, '_acme-challenge', {
- 'ttl': 30,
- 'type': 'TXT',
- 'value': 'magic bit',
- }),
- 'sub-unowned': Record.new(zone, '_acme-challenge.sub-unowned', {
- 'ttl': 30,
- 'type': 'TXT',
- 'value': 'magic bit',
- }),
- 'not-txt': Record.new(zone, '_acme-challenge.not-txt', {
- 'ttl': 30,
- 'type': 'AAAA',
- 'value': '::1',
- }),
- 'not-acme': Record.new(zone, 'not-acme', {
- 'ttl': 30,
- 'type': 'TXT',
- 'value': 'Hello World!',
- }),
- 'managed': Record.new(zone, '_acme-challenge.managed', {
- 'ttl': 30,
- 'type': 'TXT',
- 'value': 'magic bit',
- }),
- 'owned': Record.new(zone, '_acme-challenge.owned', {
- 'ttl': 30,
- 'type': 'TXT',
- 'values': ['*octoDNS*', 'magic bit'],
- }),
- 'going-away': Record.new(zone, '_acme-challenge.going-away', {
- 'ttl': 30,
- 'type': 'TXT',
- 'values': ['*octoDNS*', 'magic bit'],
- }),
+ 'root-unowned': Record.new(
+ zone,
+ '_acme-challenge',
+ {'ttl': 30, 'type': 'TXT', 'value': 'magic bit'},
+ ),
+ 'sub-unowned': Record.new(
+ zone,
+ '_acme-challenge.sub-unowned',
+ {'ttl': 30, 'type': 'TXT', 'value': 'magic bit'},
+ ),
+ 'not-txt': Record.new(
+ zone,
+ '_acme-challenge.not-txt',
+ {'ttl': 30, 'type': 'AAAA', 'value': '::1'},
+ ),
+ 'not-acme': Record.new(
+ zone, 'not-acme', {'ttl': 30, 'type': 'TXT', 'value': 'Hello World!'}
+ ),
+ 'managed': Record.new(
+ zone,
+ '_acme-challenge.managed',
+ {'ttl': 30, 'type': 'TXT', 'value': 'magic bit'},
+ ),
+ 'owned': Record.new(
+ zone,
+ '_acme-challenge.owned',
+ {'ttl': 30, 'type': 'TXT', 'values': ['*octoDNS*', 'magic bit']},
+ ),
+ 'going-away': Record.new(
+ zone,
+ '_acme-challenge.going-away',
+ {'ttl': 30, 'type': 'TXT', 'values': ['*octoDNS*', 'magic bit']},
+ ),
}
class TestAcmeMangingProcessor(TestCase):
-
def test_process_zones(self):
acme = AcmeMangingProcessor('acme')
@@ -64,11 +65,10 @@ class TestAcmeMangingProcessor(TestCase):
source.add_record(records['managed'])
got = acme.process_source_zone(source)
- self.assertEqual([
- '_acme-challenge.managed',
- '_acme-challenge.not-txt',
- 'not-acme',
- ], sorted([r.name for r in got.records]))
+ self.assertEqual(
+ ['_acme-challenge.managed', '_acme-challenge.not-txt', 'not-acme'],
+ sorted([r.name for r in got.records]),
+ )
managed = None
for record in got.records:
if record.name.endswith('managed'):
@@ -93,10 +93,13 @@ class TestAcmeMangingProcessor(TestCase):
existing.add_record(records['going-away'])
got = acme.process_target_zone(existing)
- self.assertEqual([
- '_acme-challenge.going-away',
- '_acme-challenge.managed',
- '_acme-challenge.not-txt',
- '_acme-challenge.owned',
- 'not-acme'
- ], sorted([r.name for r in got.records]))
+ self.assertEqual(
+ [
+ '_acme-challenge.going-away',
+ '_acme-challenge.managed',
+ '_acme-challenge.not-txt',
+ '_acme-challenge.owned',
+ 'not-acme',
+ ],
+ sorted([r.name for r in got.records]),
+ )
diff --git a/tests/test_octodns_processor_awsacm.py b/tests/test_octodns_processor_awsacm.py
index 3a99447..8d9e071 100644
--- a/tests/test_octodns_processor_awsacm.py
+++ b/tests/test_octodns_processor_awsacm.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestAwsAcmMangingProcessor(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.processor.awsacm import AwsAcmMangingProcessor
+
AwsAcmMangingProcessor
diff --git a/tests/test_octodns_processor_filter.py b/tests/test_octodns_processor_filter.py
index d4a38ec..859677d 100644
--- a/tests/test_octodns_processor_filter.py
+++ b/tests/test_octodns_processor_filter.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
@@ -13,37 +17,20 @@ from octodns.zone import Zone
zone = Zone('unit.tests.', [])
for record in [
- Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- }),
- Record.new(zone, 'aaaa', {
- 'ttl': 30,
- 'type': 'AAAA',
- 'value': '::1',
- }),
- Record.new(zone, 'txt', {
- 'ttl': 30,
- 'type': 'TXT',
- 'value': 'Hello World!',
- }),
- Record.new(zone, 'a2', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '2.3.4.5',
- }),
- Record.new(zone, 'txt2', {
- 'ttl': 30,
- 'type': 'TXT',
- 'value': 'That will do',
- }),
+ Record.new(zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}),
+ Record.new(zone, 'aaaa', {'ttl': 30, 'type': 'AAAA', 'value': '::1'}),
+ Record.new(
+ zone, 'txt', {'ttl': 30, 'type': 'TXT', 'value': 'Hello World!'}
+ ),
+ Record.new(zone, 'a2', {'ttl': 30, 'type': 'A', 'value': '2.3.4.5'}),
+ Record.new(
+ zone, 'txt2', {'ttl': 30, 'type': 'TXT', 'value': 'That will do'}
+ ),
]:
zone.add_record(record)
class TestTypeAllowListFilter(TestCase):
-
def test_basics(self):
filter_a = TypeAllowlistFilter('only-a', set(('A')))
@@ -56,35 +43,36 @@ class TestTypeAllowListFilter(TestCase):
filter_txt = TypeAllowlistFilter('only-txt', ['TXT'])
got = filter_txt.process_target_zone(zone.copy())
- self.assertEqual(['txt', 'txt2'],
- sorted([r.name for r in got.records]))
+ self.assertEqual(['txt', 'txt2'], sorted([r.name for r in got.records]))
filter_a_aaaa = TypeAllowlistFilter('only-aaaa', set(('A', 'AAAA')))
got = filter_a_aaaa.process_target_zone(zone.copy())
- self.assertEqual(['a', 'a2', 'aaaa'],
- sorted([r.name for r in got.records]))
+ self.assertEqual(
+ ['a', 'a2', 'aaaa'], sorted([r.name for r in got.records])
+ )
class TestTypeRejectListFilter(TestCase):
-
def test_basics(self):
filter_a = TypeRejectlistFilter('not-a', set(('A')))
got = filter_a.process_source_zone(zone.copy())
- self.assertEqual(['aaaa', 'txt', 'txt2'],
- sorted([r.name for r in got.records]))
+ self.assertEqual(
+ ['aaaa', 'txt', 'txt2'], sorted([r.name for r in got.records])
+ )
filter_aaaa = TypeRejectlistFilter('not-aaaa', ('AAAA',))
got = filter_aaaa.process_source_zone(zone.copy())
- self.assertEqual(['a', 'a2', 'txt', 'txt2'],
- sorted([r.name for r in got.records]))
+ self.assertEqual(
+ ['a', 'a2', 'txt', 'txt2'], sorted([r.name for r in got.records])
+ )
filter_txt = TypeRejectlistFilter('not-txt', ['TXT'])
got = filter_txt.process_target_zone(zone.copy())
- self.assertEqual(['a', 'a2', 'aaaa'],
- sorted([r.name for r in got.records]))
+ self.assertEqual(
+ ['a', 'a2', 'aaaa'], sorted([r.name for r in got.records])
+ )
filter_a_aaaa = TypeRejectlistFilter('not-a-aaaa', set(('A', 'AAAA')))
got = filter_a_aaaa.process_target_zone(zone.copy())
- self.assertEqual(['txt', 'txt2'],
- sorted([r.name for r in got.records]))
+ self.assertEqual(['txt', 'txt2'], sorted([r.name for r in got.records]))
diff --git a/tests/test_octodns_processor_ownership.py b/tests/test_octodns_processor_ownership.py
index a989926..debfacc 100644
--- a/tests/test_octodns_processor_ownership.py
+++ b/tests/test_octodns_processor_ownership.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
@@ -17,57 +21,40 @@ from helpers import PlannableProvider
zone = Zone('unit.tests.', [])
records = {}
for record in [
- Record.new(zone, '', {
- 'ttl': 30,
- 'type': 'A',
- 'values': [
- '1.2.3.4',
- '5.6.7.8',
- ],
- }),
- Record.new(zone, 'the-a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- }),
- Record.new(zone, 'the-aaaa', {
- 'ttl': 30,
- 'type': 'AAAA',
- 'value': '::1',
- }),
- Record.new(zone, 'the-txt', {
- 'ttl': 30,
- 'type': 'TXT',
- 'value': 'Hello World!',
- }),
- Record.new(zone, '*', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '4.3.2.1',
- }),
+ Record.new(
+ zone, '', {'ttl': 30, 'type': 'A', 'values': ['1.2.3.4', '5.6.7.8']}
+ ),
+ Record.new(zone, 'the-a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}),
+ Record.new(zone, 'the-aaaa', {'ttl': 30, 'type': 'AAAA', 'value': '::1'}),
+ Record.new(
+ zone, 'the-txt', {'ttl': 30, 'type': 'TXT', 'value': 'Hello World!'}
+ ),
+ Record.new(zone, '*', {'ttl': 30, 'type': 'A', 'value': '4.3.2.1'}),
]:
records[record.name] = record
zone.add_record(record)
class TestOwnershipProcessor(TestCase):
-
def test_process_source_zone(self):
ownership = OwnershipProcessor('ownership')
got = ownership.process_source_zone(zone.copy())
- self.assertEqual([
- '',
- '*',
- '_owner.a',
- '_owner.a._wildcard',
- '_owner.a.the-a',
- '_owner.aaaa.the-aaaa',
- '_owner.txt.the-txt',
- 'the-a',
- 'the-aaaa',
- 'the-txt',
- ], sorted([r.name for r in got.records]))
+ self.assertEqual(
+ [
+ '',
+ '*',
+ '_owner.a',
+ '_owner.a._wildcard',
+ '_owner.a.the-a',
+ '_owner.aaaa.the-aaaa',
+ '_owner.txt.the-txt',
+ 'the-a',
+ 'the-aaaa',
+ 'the-txt',
+ ],
+ sorted([r.name for r in got.records]),
+ )
found = False
for record in got.records:
@@ -101,11 +88,9 @@ class TestOwnershipProcessor(TestCase):
# Something extra exists and doesn't have ownership TXT, leave it
# alone, we don't own it.
- extra_a = Record.new(zone, 'extra-a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '4.4.4.4',
- })
+ extra_a = Record.new(
+ zone, 'extra-a', {'ttl': 30, 'type': 'A', 'value': '4.4.4.4'}
+ )
plan.existing.add_record(extra_a)
# If we'd done a "real" plan we'd have a delete for the extra thing.
plan.changes.append(Delete(extra_a))
@@ -130,11 +115,9 @@ class TestOwnershipProcessor(TestCase):
the_a = records['the-a']
plan.existing.add_record(the_a)
name = f'{ownership.txt_name}.a.the-a'
- the_a_ownership = Record.new(zone, name, {
- 'ttl': 30,
- 'type': 'TXT',
- 'value': ownership.txt_value,
- })
+ the_a_ownership = Record.new(
+ zone, name, {'ttl': 30, 'type': 'TXT', 'value': ownership.txt_value}
+ )
plan.existing.add_record(the_a_ownership)
plan.changes.append(Delete(the_a))
plan.changes.append(Delete(the_a_ownership))
diff --git a/tests/test_octodns_provider_azuredns.py b/tests/test_octodns_provider_azuredns.py
index 4990ad3..f220756 100644
--- a/tests/test_octodns_provider_azuredns.py
+++ b/tests/test_octodns_provider_azuredns.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestAzureShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.azuredns import AzureProvider
+
AzureProvider
diff --git a/tests/test_octodns_provider_base.py b/tests/test_octodns_provider_base.py
index e1140c5..b47cc3c 100644
--- a/tests/test_octodns_provider_base.py
+++ b/tests/test_octodns_provider_base.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from logging import getLogger
from unittest import TestCase
@@ -27,8 +31,12 @@ class HelperProvider(BaseProvider):
id = 'test'
strict_supports = False
- def __init__(self, extra_changes=[], apply_disabled=False,
- include_change_callback=None):
+ def __init__(
+ self,
+ extra_changes=[],
+ apply_disabled=False,
+ include_change_callback=None,
+ ):
self.__extra_changes = extra_changes
self.apply_disabled = apply_disabled
self.include_change_callback = include_change_callback
@@ -39,8 +47,9 @@ class HelperProvider(BaseProvider):
return True
def _include_change(self, change):
- return not self.include_change_callback or \
- self.include_change_callback(change)
+ return not self.include_change_callback or self.include_change_callback(
+ change
+ )
def _extra_changes(self, **kwargs):
return self.__extra_changes
@@ -50,7 +59,6 @@ class HelperProvider(BaseProvider):
class TrickyProcessor(BaseProcessor):
-
def __init__(self, name, add_during_process_target_zone):
super(TrickyProcessor, self).__init__(name)
self.add_during_process_target_zone = add_during_process_target_zone
@@ -73,20 +81,22 @@ class TrickyProcessor(BaseProcessor):
class TestBaseProvider(TestCase):
-
def test_base_provider(self):
with self.assertRaises(NotImplementedError) as ctx:
BaseProvider('base')
- self.assertEqual('Abstract base class, log property missing',
- str(ctx.exception))
+ self.assertEqual(
+ 'Abstract base class, log property missing', str(ctx.exception)
+ )
class HasLog(BaseProvider):
log = getLogger('HasLog')
with self.assertRaises(NotImplementedError) as ctx:
HasLog('haslog')
- self.assertEqual('Abstract base class, SUPPORTS_GEO property missing',
- str(ctx.exception))
+ self.assertEqual(
+ 'Abstract base class, SUPPORTS_GEO property missing',
+ str(ctx.exception),
+ )
class HasSupportsGeo(HasLog):
SUPPORTS_GEO = False
@@ -94,15 +104,18 @@ class TestBaseProvider(TestCase):
zone = Zone('unit.tests.', ['sub'])
with self.assertRaises(NotImplementedError) as ctx:
HasSupportsGeo('hassupportsgeo').populate(zone)
- self.assertEqual('Abstract base class, SUPPORTS property missing',
- str(ctx.exception))
+ self.assertEqual(
+ 'Abstract base class, SUPPORTS property missing', str(ctx.exception)
+ )
class HasSupports(HasSupportsGeo):
SUPPORTS = set(('A',))
+
with self.assertRaises(NotImplementedError) as ctx:
HasSupports('hassupports').populate(zone)
- self.assertEqual('Abstract base class, populate method missing',
- str(ctx.exception))
+ self.assertEqual(
+ 'Abstract base class, populate method missing', str(ctx.exception)
+ )
# SUPPORTS_DYNAMIC has a default/fallback
self.assertFalse(HasSupports('hassupports').SUPPORTS_DYNAMIC)
@@ -111,44 +124,51 @@ class TestBaseProvider(TestCase):
class HasSupportsDyanmic(HasSupports):
SUPPORTS_DYNAMIC = True
- self.assertTrue(HasSupportsDyanmic('hassupportsdynamic')
- .SUPPORTS_DYNAMIC)
+ self.assertTrue(
+ HasSupportsDyanmic('hassupportsdynamic').SUPPORTS_DYNAMIC
+ )
class HasPopulate(HasSupports):
-
def populate(self, zone, target=False, lenient=False):
- zone.add_record(Record.new(zone, '', {
- 'ttl': 60,
- 'type': 'A',
- 'value': '2.3.4.5'
- }), lenient=lenient)
- zone.add_record(Record.new(zone, 'going', {
- 'ttl': 60,
- 'type': 'A',
- 'value': '3.4.5.6'
- }), lenient=lenient)
- zone.add_record(Record.new(zone, 'foo.sub', {
- 'ttl': 61,
- 'type': 'A',
- 'value': '4.5.6.7'
- }), lenient=lenient)
+ zone.add_record(
+ Record.new(
+ zone, '', {'ttl': 60, 'type': 'A', 'value': '2.3.4.5'}
+ ),
+ lenient=lenient,
+ )
+ zone.add_record(
+ Record.new(
+ zone,
+ 'going',
+ {'ttl': 60, 'type': 'A', 'value': '3.4.5.6'},
+ ),
+ lenient=lenient,
+ )
+ zone.add_record(
+ Record.new(
+ zone,
+ 'foo.sub',
+ {'ttl': 61, 'type': 'A', 'value': '4.5.6.7'},
+ ),
+ lenient=lenient,
+ )
- zone.add_record(Record.new(zone, '', {
- 'ttl': 60,
- 'type': 'A',
- 'value': '1.2.3.4'
- }))
+ zone.add_record(
+ Record.new(zone, '', {'ttl': 60, 'type': 'A', 'value': '1.2.3.4'})
+ )
- self.assertTrue(HasSupports('hassupportsgeo')
- .supports(list(zone.records)[0]))
+ self.assertTrue(
+ HasSupports('hassupportsgeo').supports(list(zone.records)[0])
+ )
plan = HasPopulate('haspopulate').plan(zone)
self.assertEqual(3, len(plan.changes))
with self.assertRaises(NotImplementedError) as ctx:
HasPopulate('haspopulate').apply(plan)
- self.assertEqual('Abstract base class, _apply method missing',
- str(ctx.exception))
+ self.assertEqual(
+ 'Abstract base class, _apply method missing', str(ctx.exception)
+ )
def test_plan(self):
ignored = Zone('unit.tests.', [])
@@ -157,11 +177,9 @@ class TestBaseProvider(TestCase):
provider = HelperProvider([])
self.assertEqual(None, provider.plan(ignored))
- record = Record.new(ignored, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ ignored, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
provider = HelperProvider([Create(record)])
plan = provider.plan(ignored)
self.assertTrue(plan)
@@ -171,7 +189,6 @@ class TestBaseProvider(TestCase):
ignored = Zone('unit.tests.', [])
class OldApiProvider(HelperProvider):
-
def _process_desired_zone(self, desired):
return desired
@@ -180,7 +197,6 @@ class TestBaseProvider(TestCase):
self.assertEqual(None, provider.plan(ignored))
class OtherTypeErrorProvider(HelperProvider):
-
def _process_desired_zone(self, desired, exists=False):
raise TypeError('foo')
@@ -193,18 +209,20 @@ class TestBaseProvider(TestCase):
zone = Zone('unit.tests.', [])
# supported
- supported = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ supported = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
zone.add_record(supported)
# not supported
- not_supported = Record.new(zone, 'aaaa', {
- 'ttl': 30,
- 'type': 'AAAA',
- 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
- })
+ not_supported = Record.new(
+ zone,
+ 'aaaa',
+ {
+ 'ttl': 30,
+ 'type': 'AAAA',
+ 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
+ },
+ )
zone.add_record(not_supported)
provider = HelperProvider()
plan = provider.plan(zone)
@@ -215,11 +233,9 @@ class TestBaseProvider(TestCase):
def test_plan_with_processors(self):
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
provider = HelperProvider()
# Processor that adds a record to the zone, which planning will then
# delete since it won't know anything about it
@@ -233,11 +249,9 @@ class TestBaseProvider(TestCase):
self.assertEqual(zone.name, tricky.existing.name)
# Chain of processors happen one after the other
- other = Record.new(zone, 'b', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '5.6.7.8',
- })
+ other = Record.new(
+ zone, 'b', {'ttl': 30, 'type': 'A', 'value': '5.6.7.8'}
+ )
# Another processor will add its record, thus 2 deletes
another = TrickyProcessor('tricky', [other])
plan = provider.plan(zone, processors=[tricky, another])
@@ -253,11 +267,9 @@ class TestBaseProvider(TestCase):
def test_plan_with_root_ns(self):
zone = Zone('unit.tests.', [])
- record = Record.new(zone, '', {
- 'ttl': 30,
- 'type': 'NS',
- 'value': '1.2.3.4.',
- })
+ record = Record.new(
+ zone, '', {'ttl': 30, 'type': 'NS', 'value': '1.2.3.4.'}
+ )
zone.add_record(record)
# No root NS support, no change, thus no plan
@@ -273,11 +285,9 @@ class TestBaseProvider(TestCase):
def test_apply(self):
ignored = Zone('unit.tests.', [])
- record = Record.new(ignored, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ ignored, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
provider = HelperProvider([Create(record)], apply_disabled=True)
plan = provider.plan(ignored)
provider.apply(plan)
@@ -288,11 +298,9 @@ class TestBaseProvider(TestCase):
def test_include_change(self):
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
zone.add_record(record)
provider = HelperProvider([], include_change_callback=lambda c: False)
plan = provider.plan(zone)
@@ -300,7 +308,6 @@ class TestBaseProvider(TestCase):
self.assertFalse(plan)
def test_plan_order_of_operations(self):
-
class MockProvider(BaseProvider):
log = getLogger('mock-provider')
SUPPORTS = set(('A',))
@@ -327,8 +334,10 @@ class TestBaseProvider(TestCase):
self.assertFalse(provider.plan(zone))
# ensure the calls were made in the expected order, populate comes
# first, then desired, then existing
- self.assertEqual(['populate', '_process_desired_zone',
- '_process_existing_zone'], provider.calls)
+ self.assertEqual(
+ ['populate', '_process_desired_zone', '_process_existing_zone'],
+ provider.calls,
+ )
def test_process_desired_zone(self):
provider = HelperProvider('test')
@@ -336,11 +345,11 @@ class TestBaseProvider(TestCase):
# SUPPORTS_MULTIVALUE_PTR
provider.SUPPORTS_MULTIVALUE_PTR = False
zone1 = Zone('unit.tests.', [])
- record1 = Record.new(zone1, 'ptr', {
- 'type': 'PTR',
- 'ttl': 3600,
- 'values': ['foo.com.', 'bar.com.'],
- })
+ record1 = Record.new(
+ zone1,
+ 'ptr',
+ {'type': 'PTR', 'ttl': 3600, 'values': ['foo.com.', 'bar.com.']},
+ )
zone1.add_record(record1)
zone2 = provider._process_desired_zone(zone1.copy())
@@ -355,23 +364,19 @@ class TestBaseProvider(TestCase):
# SUPPORTS_DYNAMIC
provider.SUPPORTS_DYNAMIC = False
zone1 = Zone('unit.tests.', [])
- record1 = Record.new(zone1, 'a', {
- 'dynamic': {
- 'pools': {
- 'one': {
- 'values': [{
- 'value': '1.1.1.1',
- }],
- },
+ record1 = Record.new(
+ zone1,
+ 'a',
+ {
+ 'dynamic': {
+ 'pools': {'one': {'values': [{'value': '1.1.1.1'}]}},
+ 'rules': [{'pool': 'one'}],
},
- 'rules': [{
- 'pool': 'one',
- }],
+ 'type': 'A',
+ 'ttl': 3600,
+ 'values': ['2.2.2.2'],
},
- 'type': 'A',
- 'ttl': 3600,
- 'values': ['2.2.2.2'],
- })
+ )
self.assertTrue(record1.dynamic)
zone1.add_record(record1)
@@ -393,18 +398,17 @@ class TestBaseProvider(TestCase):
zone2 = provider._process_desired_zone(zone1.copy())
record2 = list(zone2.records)[0]
self.assertEqual(
- record2.dynamic.pools['one'].data['values'][0]['status'],
- 'obey'
+ record2.dynamic.pools['one'].data['values'][0]['status'], 'obey'
)
# SUPPORTS_ROOT_NS
provider.SUPPORTS_ROOT_NS = False
zone1 = Zone('unit.tests.', [])
- record1 = Record.new(zone1, '', {
- 'type': 'NS',
- 'ttl': 3600,
- 'values': ['foo.com.', 'bar.com.'],
- })
+ record1 = Record.new(
+ zone1,
+ '',
+ {'type': 'NS', 'ttl': 3600, 'values': ['foo.com.', 'bar.com.']},
+ )
zone1.add_record(record1)
zone2 = provider._process_desired_zone(zone1.copy())
@@ -421,11 +425,11 @@ class TestBaseProvider(TestCase):
# SUPPORTS_ROOT_NS
provider.SUPPORTS_ROOT_NS = False
zone1 = Zone('unit.tests.', [])
- record1 = Record.new(zone1, '', {
- 'type': 'NS',
- 'ttl': 3600,
- 'values': ['foo.com.', 'bar.com.'],
- })
+ record1 = Record.new(
+ zone1,
+ '',
+ {'type': 'NS', 'ttl': 3600, 'values': ['foo.com.', 'bar.com.']},
+ )
zone1.add_record(record1)
zone2 = provider._process_existing_zone(zone1.copy(), zone1)
@@ -444,42 +448,38 @@ class TestBaseProvider(TestCase):
# Creates are safe when existing records is under MIN_EXISTING_RECORDS
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
- Plan(zone, zone, [Create(record) for i in range(10)], True) \
- .raise_if_unsafe()
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
+ Plan(
+ zone, zone, [Create(record) for i in range(10)], True
+ ).raise_if_unsafe()
def test_safe_min_existing_creates(self):
# Creates are safe when existing records is over MIN_EXISTING_RECORDS
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
for i in range(int(Plan.MIN_EXISTING_RECORDS)):
- zone.add_record(Record.new(zone, str(i), {
- 'ttl': 60,
- 'type': 'A',
- 'value': '2.3.4.5'
- }))
+ zone.add_record(
+ Record.new(
+ zone, str(i), {'ttl': 60, 'type': 'A', 'value': '2.3.4.5'}
+ )
+ )
- Plan(zone, zone, [Create(record) for i in range(10)], True) \
- .raise_if_unsafe()
+ Plan(
+ zone, zone, [Create(record) for i in range(10)], True
+ ).raise_if_unsafe()
def test_safe_no_existing(self):
# existing records fewer than MIN_EXISTING_RECORDS is safe
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
updates = [Update(record, record), Update(record, record)]
Plan(zone, zone, updates, True).raise_if_unsafe()
@@ -488,22 +488,23 @@ class TestBaseProvider(TestCase):
# MAX_SAFE_UPDATE_PCENT+1 fails when more
# than MIN_EXISTING_RECORDS exist
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
for i in range(int(Plan.MIN_EXISTING_RECORDS)):
- zone.add_record(Record.new(zone, str(i), {
- 'ttl': 60,
- 'type': 'A',
- 'value': '2.3.4.5'
- }))
+ zone.add_record(
+ Record.new(
+ zone, str(i), {'ttl': 60, 'type': 'A', 'value': '2.3.4.5'}
+ )
+ )
- changes = [Update(record, record)
- for i in range(int(Plan.MIN_EXISTING_RECORDS *
- Plan.MAX_SAFE_UPDATE_PCENT) + 1)]
+ changes = [
+ Update(record, record)
+ for i in range(
+ int(Plan.MIN_EXISTING_RECORDS * Plan.MAX_SAFE_UPDATE_PCENT) + 1
+ )
+ ]
with self.assertRaises(UnsafePlan) as ctx:
Plan(zone, zone, changes, True).raise_if_unsafe()
@@ -514,21 +515,22 @@ class TestBaseProvider(TestCase):
# MAX_SAFE_UPDATE_PCENT is safe when more
# than MIN_EXISTING_RECORDS exist
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
for i in range(int(Plan.MIN_EXISTING_RECORDS)):
- zone.add_record(Record.new(zone, str(i), {
- 'ttl': 60,
- 'type': 'A',
- 'value': '2.3.4.5'
- }))
- changes = [Update(record, record)
- for i in range(int(Plan.MIN_EXISTING_RECORDS *
- Plan.MAX_SAFE_UPDATE_PCENT))]
+ zone.add_record(
+ Record.new(
+ zone, str(i), {'ttl': 60, 'type': 'A', 'value': '2.3.4.5'}
+ )
+ )
+ changes = [
+ Update(record, record)
+ for i in range(
+ int(Plan.MIN_EXISTING_RECORDS * Plan.MAX_SAFE_UPDATE_PCENT)
+ )
+ ]
Plan(zone, zone, changes, True).raise_if_unsafe()
@@ -536,22 +538,23 @@ class TestBaseProvider(TestCase):
# MAX_SAFE_DELETE_PCENT+1 fails when more
# than MIN_EXISTING_RECORDS exist
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
for i in range(int(Plan.MIN_EXISTING_RECORDS)):
- zone.add_record(Record.new(zone, str(i), {
- 'ttl': 60,
- 'type': 'A',
- 'value': '2.3.4.5'
- }))
+ zone.add_record(
+ Record.new(
+ zone, str(i), {'ttl': 60, 'type': 'A', 'value': '2.3.4.5'}
+ )
+ )
- changes = [Delete(record)
- for i in range(int(Plan.MIN_EXISTING_RECORDS *
- Plan.MAX_SAFE_DELETE_PCENT) + 1)]
+ changes = [
+ Delete(record)
+ for i in range(
+ int(Plan.MIN_EXISTING_RECORDS * Plan.MAX_SAFE_DELETE_PCENT) + 1
+ )
+ ]
with self.assertRaises(UnsafePlan) as ctx:
Plan(zone, zone, changes, True).raise_if_unsafe()
@@ -562,77 +565,78 @@ class TestBaseProvider(TestCase):
# MAX_SAFE_DELETE_PCENT is safe when more
# than MIN_EXISTING_RECORDS exist
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
for i in range(int(Plan.MIN_EXISTING_RECORDS)):
- zone.add_record(Record.new(zone, str(i), {
- 'ttl': 60,
- 'type': 'A',
- 'value': '2.3.4.5'
- }))
- changes = [Delete(record)
- for i in range(int(Plan.MIN_EXISTING_RECORDS *
- Plan.MAX_SAFE_DELETE_PCENT))]
+ zone.add_record(
+ Record.new(
+ zone, str(i), {'ttl': 60, 'type': 'A', 'value': '2.3.4.5'}
+ )
+ )
+ changes = [
+ Delete(record)
+ for i in range(
+ int(Plan.MIN_EXISTING_RECORDS * Plan.MAX_SAFE_DELETE_PCENT)
+ )
+ ]
Plan(zone, zone, changes, True).raise_if_unsafe()
def test_safe_updates_min_existing_override(self):
- safe_pcent = .4
+ safe_pcent = 0.4
# 40% + 1 fails when more
# than MIN_EXISTING_RECORDS exist
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
for i in range(int(Plan.MIN_EXISTING_RECORDS)):
- zone.add_record(Record.new(zone, str(i), {
- 'ttl': 60,
- 'type': 'A',
- 'value': '2.3.4.5'
- }))
+ zone.add_record(
+ Record.new(
+ zone, str(i), {'ttl': 60, 'type': 'A', 'value': '2.3.4.5'}
+ )
+ )
- changes = [Update(record, record)
- for i in range(int(Plan.MIN_EXISTING_RECORDS *
- safe_pcent) + 1)]
+ changes = [
+ Update(record, record)
+ for i in range(int(Plan.MIN_EXISTING_RECORDS * safe_pcent) + 1)
+ ]
with self.assertRaises(UnsafePlan) as ctx:
- Plan(zone, zone, changes, True,
- update_pcent_threshold=safe_pcent).raise_if_unsafe()
+ Plan(
+ zone, zone, changes, True, update_pcent_threshold=safe_pcent
+ ).raise_if_unsafe()
self.assertTrue('Too many updates' in str(ctx.exception))
def test_safe_deletes_min_existing_override(self):
- safe_pcent = .4
+ safe_pcent = 0.4
# 40% + 1 fails when more
# than MIN_EXISTING_RECORDS exist
zone = Zone('unit.tests.', [])
- record = Record.new(zone, 'a', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = Record.new(
+ zone, 'a', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
for i in range(int(Plan.MIN_EXISTING_RECORDS)):
- zone.add_record(Record.new(zone, str(i), {
- 'ttl': 60,
- 'type': 'A',
- 'value': '2.3.4.5'
- }))
+ zone.add_record(
+ Record.new(
+ zone, str(i), {'ttl': 60, 'type': 'A', 'value': '2.3.4.5'}
+ )
+ )
- changes = [Delete(record)
- for i in range(int(Plan.MIN_EXISTING_RECORDS *
- safe_pcent) + 1)]
+ changes = [
+ Delete(record)
+ for i in range(int(Plan.MIN_EXISTING_RECORDS * safe_pcent) + 1)
+ ]
with self.assertRaises(UnsafePlan) as ctx:
- Plan(zone, zone, changes, True,
- delete_pcent_threshold=safe_pcent).raise_if_unsafe()
+ Plan(
+ zone, zone, changes, True, delete_pcent_threshold=safe_pcent
+ ).raise_if_unsafe()
self.assertTrue('Too many deletes' in str(ctx.exception))
@@ -649,9 +653,9 @@ class TestBaseProvider(TestCase):
# Should log and not expect
normal.supports_warn_or_except('Hello World!', 'Goodbye')
normal.log.warning.assert_called_once()
- normal.log.warning.assert_has_calls([
- call('%s; %s', 'Hello World!', 'Goodbye')
- ])
+ normal.log.warning.assert_has_calls(
+ [call('%s; %s', 'Hello World!', 'Goodbye')]
+ )
strict = MinimalProvider(strict_supports=True)
# Should log and not expect
@@ -662,7 +666,6 @@ class TestBaseProvider(TestCase):
class TestBaseProviderSupportsRootNs(TestCase):
-
class Provider(BaseProvider):
log = getLogger('Provider')
@@ -684,33 +687,33 @@ class TestBaseProviderSupportsRootNs(TestCase):
return False
zone = Zone('unit.tests.', [])
- a_record = Record.new(zone, 'ptr', {
- 'type': 'A',
- 'ttl': 3600,
- 'values': ['1.2.3.4', '2.3.4.5'],
- })
- ns_record = Record.new(zone, 'sub', {
- 'type': 'NS',
- 'ttl': 3600,
- 'values': ['ns2.foo.com.', 'ns2.bar.com.'],
- })
+ a_record = Record.new(
+ zone,
+ 'ptr',
+ {'type': 'A', 'ttl': 3600, 'values': ['1.2.3.4', '2.3.4.5']},
+ )
+ ns_record = Record.new(
+ zone,
+ 'sub',
+ {'type': 'NS', 'ttl': 3600, 'values': ['ns2.foo.com.', 'ns2.bar.com.']},
+ )
no_root = zone.copy()
no_root.add_record(a_record)
no_root.add_record(ns_record)
- root_ns_record = Record.new(zone, '', {
- 'type': 'NS',
- 'ttl': 3600,
- 'values': ['ns1.foo.com.', 'ns1.bar.com.'],
- })
+ root_ns_record = Record.new(
+ zone,
+ '',
+ {'type': 'NS', 'ttl': 3600, 'values': ['ns1.foo.com.', 'ns1.bar.com.']},
+ )
has_root = no_root.copy()
has_root.add_record(root_ns_record)
- other_root_ns_record = Record.new(zone, '', {
- 'type': 'NS',
- 'ttl': 3600,
- 'values': ['ns4.foo.com.', 'ns4.bar.com.'],
- })
+ other_root_ns_record = Record.new(
+ zone,
+ '',
+ {'type': 'NS', 'ttl': 3600, 'values': ['ns4.foo.com.', 'ns4.bar.com.']},
+ )
different_root = no_root.copy()
different_root.add_record(other_root_ns_record)
@@ -733,8 +736,10 @@ class TestBaseProviderSupportsRootNs(TestCase):
provider.strict_supports = True
with self.assertRaises(SupportsException) as ctx:
provider.plan(self.has_root)
- self.assertEqual('test: root NS record not supported for unit.tests.',
- str(ctx.exception))
+ self.assertEqual(
+ 'test: root NS record not supported for unit.tests.',
+ str(ctx.exception),
+ )
def test_supports_root_ns_false_different(self):
# provider has a non-matching existing record
@@ -754,8 +759,10 @@ class TestBaseProviderSupportsRootNs(TestCase):
provider.strict_supports = True
with self.assertRaises(SupportsException) as ctx:
provider.plan(self.has_root)
- self.assertEqual('test: root NS record not supported for unit.tests.',
- str(ctx.exception))
+ self.assertEqual(
+ 'test: root NS record not supported for unit.tests.',
+ str(ctx.exception),
+ )
def test_supports_root_ns_false_missing(self):
# provider has an existing record
@@ -792,8 +799,10 @@ class TestBaseProviderSupportsRootNs(TestCase):
provider.strict_supports = True
with self.assertRaises(SupportsException) as ctx:
provider.plan(self.has_root)
- self.assertEqual('test: root NS record not supported for unit.tests.',
- str(ctx.exception))
+ self.assertEqual(
+ 'test: root NS record not supported for unit.tests.',
+ str(ctx.exception),
+ )
def test_supports_root_ns_false_create_zone_missing(self):
# provider has no existing records (create)
@@ -889,8 +898,9 @@ class TestBaseProviderSupportsRootNs(TestCase):
# we'll get a plan that creates everything, including it
self.assertTrue(plan)
self.assertEqual(3, len(plan.changes))
- change = [c for c in plan.changes
- if c.new.name == '' and c.new._type == 'NS'][0]
+ change = [
+ c for c in plan.changes if c.new.name == '' and c.new._type == 'NS'
+ ][0]
self.assertFalse(change.existing)
self.assertEqual(self.root_ns_record, change.new)
@@ -900,8 +910,9 @@ class TestBaseProviderSupportsRootNs(TestCase):
plan = provider.plan(self.has_root)
self.assertTrue(plan)
self.assertEqual(3, len(plan.changes))
- change = [c for c in plan.changes
- if c.new.name == '' and c.new._type == 'NS'][0]
+ change = [
+ c for c in plan.changes if c.new.name == '' and c.new._type == 'NS'
+ ][0]
self.assertFalse(change.existing)
self.assertEqual(self.root_ns_record, change.new)
diff --git a/tests/test_octodns_provider_cloudflare.py b/tests/test_octodns_provider_cloudflare.py
index 1053b7d..3b5f1ff 100644
--- a/tests/test_octodns_provider_cloudflare.py
+++ b/tests/test_octodns_provider_cloudflare.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestCloudflareShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.cloudflare import CloudflareProvider
+
CloudflareProvider
diff --git a/tests/test_octodns_provider_constellix.py b/tests/test_octodns_provider_constellix.py
index 46e87ce..97528d2 100644
--- a/tests/test_octodns_provider_constellix.py
+++ b/tests/test_octodns_provider_constellix.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestConstellixShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.constellix import ConstellixProvider
+
ConstellixProvider
diff --git a/tests/test_octodns_provider_digitalocean.py b/tests/test_octodns_provider_digitalocean.py
index 56ca965..0b36a4c 100644
--- a/tests/test_octodns_provider_digitalocean.py
+++ b/tests/test_octodns_provider_digitalocean.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestDigitalOceanShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.digitalocean import DigitalOceanProvider
+
DigitalOceanProvider
diff --git a/tests/test_octodns_provider_dnsimple.py b/tests/test_octodns_provider_dnsimple.py
index 611caea..33a2430 100644
--- a/tests/test_octodns_provider_dnsimple.py
+++ b/tests/test_octodns_provider_dnsimple.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestDnsimpleShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.dnsimple import DnsimpleProvider
+
DnsimpleProvider
diff --git a/tests/test_octodns_provider_dnsmadeeasy.py b/tests/test_octodns_provider_dnsmadeeasy.py
index 968ae30..18fa968 100644
--- a/tests/test_octodns_provider_dnsmadeeasy.py
+++ b/tests/test_octodns_provider_dnsmadeeasy.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestDnsMadeEasyShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.dnsmadeeasy import DnsMadeEasyProvider
+
DnsMadeEasyProvider
diff --git a/tests/test_octodns_provider_dyn.py b/tests/test_octodns_provider_dyn.py
index 07fcc7b..ad5735f 100644
--- a/tests/test_octodns_provider_dyn.py
+++ b/tests/test_octodns_provider_dyn.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestDynShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.dyn import DynProvider
+
DynProvider
diff --git a/tests/test_octodns_provider_easydns.py b/tests/test_octodns_provider_easydns.py
index b92e68e..151a6d7 100644
--- a/tests/test_octodns_provider_easydns.py
+++ b/tests/test_octodns_provider_easydns.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestEasyDnsShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.easydns import EasyDnsProvider
+
EasyDnsProvider
diff --git a/tests/test_octodns_provider_edgedns.py b/tests/test_octodns_provider_edgedns.py
index d1ba0d3..1df1fdc 100644
--- a/tests/test_octodns_provider_edgedns.py
+++ b/tests/test_octodns_provider_edgedns.py
@@ -2,20 +2,25 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
# Just for coverage
import octodns.provider.fastdns
+
# Quell warnings
octodns.provider.fastdns
class TestAkamaiShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.edgedns import AkamaiProvider
+
AkamaiProvider
diff --git a/tests/test_octodns_provider_etc_hosts.py b/tests/test_octodns_provider_etc_hosts.py
index afefc0e..9a08106 100644
--- a/tests/test_octodns_provider_etc_hosts.py
+++ b/tests/test_octodns_provider_etc_hosts.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestEtcHostsShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.etc_hosts import EtcHostsProvider
+
EtcHostsProvider
diff --git a/tests/test_octodns_provider_gandi.py b/tests/test_octodns_provider_gandi.py
index 1e3df1e..00f2c30 100644
--- a/tests/test_octodns_provider_gandi.py
+++ b/tests/test_octodns_provider_gandi.py
@@ -2,20 +2,25 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
# Just for coverage
import octodns.provider.fastdns
+
# Quell warnings
octodns.provider.fastdns
class TestGandiShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.gandi import GandiProvider
+
GandiProvider
diff --git a/tests/test_octodns_provider_gcore.py b/tests/test_octodns_provider_gcore.py
index 0f40c8b..dd54268 100644
--- a/tests/test_octodns_provider_gcore.py
+++ b/tests/test_octodns_provider_gcore.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestGCoreShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.gcore import GCoreProvider
+
GCoreProvider
diff --git a/tests/test_octodns_provider_googlecloud.py b/tests/test_octodns_provider_googlecloud.py
index 4a8fdf5..5188cd8 100644
--- a/tests/test_octodns_provider_googlecloud.py
+++ b/tests/test_octodns_provider_googlecloud.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestGoogleCloudShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.googlecloud import GoogleCloudProvider
+
GoogleCloudProvider
diff --git a/tests/test_octodns_provider_hetzner.py b/tests/test_octodns_provider_hetzner.py
index 0976157..7f28345 100644
--- a/tests/test_octodns_provider_hetzner.py
+++ b/tests/test_octodns_provider_hetzner.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestHetznerShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.hetzner import HetznerProvider
+
HetznerProvider
diff --git a/tests/test_octodns_provider_mythicbeasts.py b/tests/test_octodns_provider_mythicbeasts.py
index f8c316c..7ae74b8 100644
--- a/tests/test_octodns_provider_mythicbeasts.py
+++ b/tests/test_octodns_provider_mythicbeasts.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestMythicBeastsShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.mythicbeasts import MythicBeastsProvider
+
MythicBeastsProvider
diff --git a/tests/test_octodns_provider_ns1.py b/tests/test_octodns_provider_ns1.py
index 3d85dd0..09ab1e3 100644
--- a/tests/test_octodns_provider_ns1.py
+++ b/tests/test_octodns_provider_ns1.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestNs1Provider(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.ns1 import Ns1Provider
+
Ns1Provider
diff --git a/tests/test_octodns_provider_ovh.py b/tests/test_octodns_provider_ovh.py
index 27ac8f6..8973af7 100644
--- a/tests/test_octodns_provider_ovh.py
+++ b/tests/test_octodns_provider_ovh.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestOvhShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.ovh import OvhProvider
+
OvhProvider
diff --git a/tests/test_octodns_provider_powerdns.py b/tests/test_octodns_provider_powerdns.py
index 464efef..9698c8c 100644
--- a/tests/test_octodns_provider_powerdns.py
+++ b/tests/test_octodns_provider_powerdns.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestPowerDnsShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.powerdns import PowerDnsProvider
+
PowerDnsProvider
diff --git a/tests/test_octodns_provider_rackspace.py b/tests/test_octodns_provider_rackspace.py
index 971c450..cb30d56 100644
--- a/tests/test_octodns_provider_rackspace.py
+++ b/tests/test_octodns_provider_rackspace.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestRackspaceShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.rackspace import RackspaceProvider
+
RackspaceProvider
diff --git a/tests/test_octodns_provider_route53.py b/tests/test_octodns_provider_route53.py
index 23e5748..2486adc 100644
--- a/tests/test_octodns_provider_route53.py
+++ b/tests/test_octodns_provider_route53.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestRoute53Provider(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.route53 import Route53Provider
+
Route53Provider
diff --git a/tests/test_octodns_provider_selectel.py b/tests/test_octodns_provider_selectel.py
index 6a0a37a..5c429d9 100644
--- a/tests/test_octodns_provider_selectel.py
+++ b/tests/test_octodns_provider_selectel.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestSelectelShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.selectel import SelectelProvider
+
SelectelProvider
diff --git a/tests/test_octodns_provider_transip.py b/tests/test_octodns_provider_transip.py
index faa90b3..eddddb0 100644
--- a/tests/test_octodns_provider_transip.py
+++ b/tests/test_octodns_provider_transip.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestTransipShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.transip import TransipProvider
+
TransipProvider
diff --git a/tests/test_octodns_provider_ultra.py b/tests/test_octodns_provider_ultra.py
index acf2805..0e6d9f2 100644
--- a/tests/test_octodns_provider_ultra.py
+++ b/tests/test_octodns_provider_ultra.py
@@ -2,15 +2,19 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
class TestUltraShim(TestCase):
-
def test_missing(self):
with self.assertRaises(ModuleNotFoundError):
from octodns.provider.ultra import UltraProvider
+
UltraProvider
diff --git a/tests/test_octodns_provider_yaml.py b/tests/test_octodns_provider_yaml.py
index 51e55eb..e2f55c2 100644
--- a/tests/test_octodns_provider_yaml.py
+++ b/tests/test_octodns_provider_yaml.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from os import makedirs
from os.path import basename, dirname, isdir, isfile, join
@@ -13,15 +17,17 @@ from yaml.constructor import ConstructorError
from octodns.record import Create
from octodns.provider.base import Plan
-from octodns.provider.yaml import _list_all_yaml_files, \
- SplitYamlProvider, YamlProvider
+from octodns.provider.yaml import (
+ _list_all_yaml_files,
+ SplitYamlProvider,
+ YamlProvider,
+)
from octodns.zone import SubzoneRecordException, Zone
from helpers import TemporaryDirectory
class TestYamlProvider(TestCase):
-
def test_provider(self):
source = YamlProvider('test', join(dirname(__file__), 'config'))
@@ -34,7 +40,7 @@ class TestYamlProvider(TestCase):
# without it we see everything
source.populate(zone)
- self.assertEqual(23, len(zone.records))
+ self.assertEqual(25, len(zone.records))
source.populate(dynamic_zone)
self.assertEqual(6, len(dynamic_zone.records))
@@ -57,18 +63,20 @@ class TestYamlProvider(TestCase):
# We add everything
plan = target.plan(zone)
- self.assertEqual(20, len([c for c in plan.changes
- if isinstance(c, Create)]))
+ self.assertEqual(
+ 22, len([c for c in plan.changes if isinstance(c, Create)])
+ )
self.assertFalse(isfile(yaml_file))
# Now actually do it
- self.assertEqual(20, target.apply(plan))
+ self.assertEqual(22, target.apply(plan))
self.assertTrue(isfile(yaml_file))
# Dynamic plan
plan = target.plan(dynamic_zone)
- self.assertEqual(6, len([c for c in plan.changes
- if isinstance(c, Create)]))
+ self.assertEqual(
+ 6, len([c for c in plan.changes if isinstance(c, Create)])
+ )
self.assertFalse(isfile(dynamic_yaml_file))
# Apply it
self.assertEqual(6, target.apply(plan))
@@ -79,8 +87,10 @@ class TestYamlProvider(TestCase):
target.populate(reloaded)
self.assertDictEqual(
{'included': ['test']},
- [x for x in reloaded.records
- if x.name == 'included'][0]._octodns)
+ [x for x in reloaded.records if x.name == 'included'][
+ 0
+ ]._octodns,
+ )
# manually copy over the root since it will have been ignored
# when things were written out
@@ -90,8 +100,9 @@ class TestYamlProvider(TestCase):
# A 2nd sync should still create everything
plan = target.plan(zone)
- self.assertEqual(20, len([c for c in plan.changes
- if isinstance(c, Create)]))
+ self.assertEqual(
+ 22, len([c for c in plan.changes if isinstance(c, Create)])
+ )
with open(yaml_file) as fh:
data = safe_load(fh.read())
@@ -100,7 +111,7 @@ class TestYamlProvider(TestCase):
roots = sorted(data.pop(''), key=lambda r: r['type'])
self.assertTrue('values' in roots[0]) # A
self.assertTrue('geo' in roots[0]) # geo made the trip
- self.assertTrue('value' in roots[1]) # CAA
+ self.assertTrue('value' in roots[1]) # CAA
self.assertTrue('values' in roots[2]) # SSHFP
# these are stored as plural 'values'
@@ -111,6 +122,8 @@ class TestYamlProvider(TestCase):
self.assertTrue('values' in data.pop('txt'))
self.assertTrue('values' in data.pop('loc'))
self.assertTrue('values' in data.pop('urlfwd'))
+ self.assertTrue('values' in data.pop('sub.txt'))
+ self.assertTrue('values' in data.pop('subzone'))
# these are stored as singular 'value'
self.assertTrue('value' in data.pop('_imap._tcp'))
self.assertTrue('value' in data.pop('_pop3._tcp'))
@@ -160,8 +173,9 @@ class TestYamlProvider(TestCase):
self.assertEqual([], list(data.keys()))
def test_empty(self):
- source = YamlProvider('test', join(dirname(__file__), 'config'),
- supports_root_ns=False)
+ source = YamlProvider(
+ 'test', join(dirname(__file__), 'config'), supports_root_ns=False
+ )
zone = Zone('empty.', [])
@@ -170,34 +184,41 @@ class TestYamlProvider(TestCase):
self.assertEqual(0, len(zone.records))
def test_unsorted(self):
- source = YamlProvider('test', join(dirname(__file__), 'config'),
- supports_root_ns=False)
+ source = YamlProvider(
+ 'test', join(dirname(__file__), 'config'), supports_root_ns=False
+ )
zone = Zone('unordered.', [])
with self.assertRaises(ConstructorError):
source.populate(zone)
- source = YamlProvider('test', join(dirname(__file__), 'config'),
- enforce_order=False, supports_root_ns=False)
+ source = YamlProvider(
+ 'test',
+ join(dirname(__file__), 'config'),
+ enforce_order=False,
+ supports_root_ns=False,
+ )
# no exception
source.populate(zone)
self.assertEqual(2, len(zone.records))
def test_subzone_handling(self):
- source = YamlProvider('test', join(dirname(__file__), 'config'),
- supports_root_ns=False)
+ source = YamlProvider(
+ 'test', join(dirname(__file__), 'config'), supports_root_ns=False
+ )
# If we add `sub` as a sub-zone we'll reject `www.sub`
zone = Zone('unit.tests.', ['sub'])
with self.assertRaises(SubzoneRecordException) as ctx:
source.populate(zone)
- self.assertEqual('Record www.sub.unit.tests. is under a managed '
- 'subzone', str(ctx.exception))
+ self.assertEqual(
+ 'Record www.sub.unit.tests. is under a managed ' 'subzone',
+ str(ctx.exception),
+ )
class TestSplitYamlProvider(TestCase):
-
def test_list_all_yaml_files(self):
yaml_files = ('foo.yaml', '1.yaml', '$unit.tests.yaml')
all_files = ('something', 'else', '1', '$$', '-f') + yaml_files
@@ -221,19 +242,21 @@ class TestSplitYamlProvider(TestCase):
def test_zone_directory(self):
source = SplitYamlProvider(
- 'test', join(dirname(__file__), 'config/split'),
- extension='.tst')
+ 'test', join(dirname(__file__), 'config/split'), extension='.tst'
+ )
zone = Zone('unit.tests.', [])
self.assertEqual(
join(dirname(__file__), 'config/split', 'unit.tests.tst'),
- source._zone_directory(zone))
+ source._zone_directory(zone),
+ )
def test_apply_handles_existing_zone_directory(self):
with TemporaryDirectory() as td:
- provider = SplitYamlProvider('test', join(td.dirname, 'config'),
- extension='.tst')
+ provider = SplitYamlProvider(
+ 'test', join(td.dirname, 'config'), extension='.tst'
+ )
makedirs(join(td.dirname, 'config', 'does.exist.tst'))
zone = Zone('does.exist.', [])
@@ -243,8 +266,8 @@ class TestSplitYamlProvider(TestCase):
def test_provider(self):
source = SplitYamlProvider(
- 'test', join(dirname(__file__), 'config/split'),
- extension='.tst')
+ 'test', join(dirname(__file__), 'config/split'), extension='.tst'
+ )
zone = Zone('unit.tests.', [])
dynamic_zone = Zone('dynamic.tests.', [])
@@ -265,14 +288,15 @@ class TestSplitYamlProvider(TestCase):
directory = join(td.dirname, 'sub', 'dir')
zone_dir = join(directory, 'unit.tests.tst')
dynamic_zone_dir = join(directory, 'dynamic.tests.tst')
- target = SplitYamlProvider('test', directory,
- extension='.tst',
- supports_root_ns=False)
+ target = SplitYamlProvider(
+ 'test', directory, extension='.tst', supports_root_ns=False
+ )
# We add everything
plan = target.plan(zone)
- self.assertEqual(17, len([c for c in plan.changes
- if isinstance(c, Create)]))
+ self.assertEqual(
+ 17, len([c for c in plan.changes if isinstance(c, Create)])
+ )
self.assertFalse(isdir(zone_dir))
# Now actually do it
@@ -280,8 +304,9 @@ class TestSplitYamlProvider(TestCase):
# Dynamic plan
plan = target.plan(dynamic_zone)
- self.assertEqual(5, len([c for c in plan.changes
- if isinstance(c, Create)]))
+ self.assertEqual(
+ 5, len([c for c in plan.changes if isinstance(c, Create)])
+ )
self.assertFalse(isdir(dynamic_zone_dir))
# Apply it
self.assertEqual(5, target.apply(plan))
@@ -292,8 +317,10 @@ class TestSplitYamlProvider(TestCase):
target.populate(reloaded)
self.assertDictEqual(
{'included': ['test']},
- [x for x in reloaded.records
- if x.name == 'included'][0]._octodns)
+ [x for x in reloaded.records if x.name == 'included'][
+ 0
+ ]._octodns,
+ )
# manually copy over the root since it will have been ignored
# when things were written out
@@ -303,8 +330,9 @@ class TestSplitYamlProvider(TestCase):
# A 2nd sync should still create everything
plan = target.plan(zone)
- self.assertEqual(17, len([c for c in plan.changes
- if isinstance(c, Create)]))
+ self.assertEqual(
+ 17, len([c for c in plan.changes if isinstance(c, Create)])
+ )
yaml_file = join(zone_dir, '$unit.tests.yaml')
self.assertTrue(isfile(yaml_file))
@@ -313,13 +341,19 @@ class TestSplitYamlProvider(TestCase):
roots = sorted(data.pop(''), key=lambda r: r['type'])
self.assertTrue('values' in roots[0]) # A
self.assertTrue('geo' in roots[0]) # geo made the trip
- self.assertTrue('value' in roots[1]) # CAA
+ self.assertTrue('value' in roots[1]) # CAA
self.assertTrue('values' in roots[2]) # SSHFP
# These records are stored as plural "values." Check each file to
# ensure correctness.
- for record_name in ('_srv._tcp', 'mx', 'naptr', 'sub', 'txt',
- 'urlfwd'):
+ for record_name in (
+ '_srv._tcp',
+ 'mx',
+ 'naptr',
+ 'sub',
+ 'txt',
+ 'urlfwd',
+ ):
yaml_file = join(zone_dir, f'{record_name}.yaml')
self.assertTrue(isfile(yaml_file))
with open(yaml_file) as fh:
@@ -327,8 +361,16 @@ class TestSplitYamlProvider(TestCase):
self.assertTrue('values' in data.pop(record_name))
# These are stored as singular "value." Again, check each file.
- for record_name in ('aaaa', 'cname', 'dname', 'included', 'ptr',
- 'spf', 'www.sub', 'www'):
+ for record_name in (
+ 'aaaa',
+ 'cname',
+ 'dname',
+ 'included',
+ 'ptr',
+ 'spf',
+ 'www.sub',
+ 'www',
+ ):
yaml_file = join(zone_dir, f'{record_name}.yaml')
self.assertTrue(isfile(yaml_file))
with open(yaml_file) as fh:
@@ -337,8 +379,7 @@ class TestSplitYamlProvider(TestCase):
# Again with the plural, this time checking dynamic.tests.
for record_name in ('a', 'aaaa', 'real-ish-a'):
- yaml_file = join(
- dynamic_zone_dir, f'{record_name}.yaml')
+ yaml_file = join(dynamic_zone_dir, f'{record_name}.yaml')
self.assertTrue(isfile(yaml_file))
with open(yaml_file) as fh:
data = safe_load(fh.read())
@@ -358,8 +399,8 @@ class TestSplitYamlProvider(TestCase):
def test_empty(self):
source = SplitYamlProvider(
- 'test', join(dirname(__file__), 'config/split'),
- extension='.tst')
+ 'test', join(dirname(__file__), 'config/split'), extension='.tst'
+ )
zone = Zone('empty.', [])
@@ -369,8 +410,8 @@ class TestSplitYamlProvider(TestCase):
def test_unsorted(self):
source = SplitYamlProvider(
- 'test', join(dirname(__file__), 'config/split'),
- extension='.tst')
+ 'test', join(dirname(__file__), 'config/split'), extension='.tst'
+ )
zone = Zone('unordered.', [])
@@ -380,35 +421,86 @@ class TestSplitYamlProvider(TestCase):
zone = Zone('unordered.', [])
source = SplitYamlProvider(
- 'test', join(dirname(__file__), 'config/split'),
- extension='.tst', enforce_order=False)
+ 'test',
+ join(dirname(__file__), 'config/split'),
+ extension='.tst',
+ enforce_order=False,
+ )
# no exception
source.populate(zone)
self.assertEqual(2, len(zone.records))
def test_subzone_handling(self):
source = SplitYamlProvider(
- 'test', join(dirname(__file__), 'config/split'),
- extension='.tst')
+ 'test', join(dirname(__file__), 'config/split'), extension='.tst'
+ )
# If we add `sub` as a sub-zone we'll reject `www.sub`
zone = Zone('unit.tests.', ['sub'])
with self.assertRaises(SubzoneRecordException) as ctx:
source.populate(zone)
- self.assertEqual('Record www.sub.unit.tests. is under a managed '
- 'subzone', str(ctx.exception))
+ self.assertEqual(
+ 'Record www.sub.unit.tests. is under a managed ' 'subzone',
+ str(ctx.exception),
+ )
+
+ def test_copy(self):
+ # going to put some sentinal values in here to ensure, these aren't
+ # valid, but we shouldn't hit any code that cares during this test
+ source = YamlProvider(
+ 'test',
+ 42,
+ default_ttl=43,
+ enforce_order=44,
+ populate_should_replace=45,
+ supports_root_ns=46,
+ )
+ copy = source.copy()
+ self.assertEqual(source.directory, copy.directory)
+ self.assertEqual(source.default_ttl, copy.default_ttl)
+ self.assertEqual(source.enforce_order, copy.enforce_order)
+ self.assertEqual(
+ source.populate_should_replace, copy.populate_should_replace
+ )
+ self.assertEqual(source.supports_root_ns, copy.supports_root_ns)
+
+ # same for split
+ source = SplitYamlProvider(
+ 'test',
+ 42,
+ extension=42.5,
+ default_ttl=43,
+ enforce_order=44,
+ populate_should_replace=45,
+ supports_root_ns=46,
+ )
+ copy = source.copy()
+ self.assertEqual(source.directory, copy.directory)
+ self.assertEqual(source.extension, copy.extension)
+ self.assertEqual(source.default_ttl, copy.default_ttl)
+ self.assertEqual(source.enforce_order, copy.enforce_order)
+ self.assertEqual(
+ source.populate_should_replace, copy.populate_should_replace
+ )
+ self.assertEqual(source.supports_root_ns, copy.supports_root_ns)
class TestOverridingYamlProvider(TestCase):
-
def test_provider(self):
config = join(dirname(__file__), 'config')
override_config = join(dirname(__file__), 'config', 'override')
- base = YamlProvider('base', config, populate_should_replace=False,
- supports_root_ns=False)
- override = YamlProvider('test', override_config,
- populate_should_replace=True,
- supports_root_ns=False)
+ base = YamlProvider(
+ 'base',
+ config,
+ populate_should_replace=False,
+ supports_root_ns=False,
+ )
+ override = YamlProvider(
+ 'test',
+ override_config,
+ populate_should_replace=True,
+ supports_root_ns=False,
+ )
zone = Zone('dynamic.tests.', [])
@@ -426,9 +518,8 @@ class TestOverridingYamlProvider(TestCase):
got = {r.name: r for r in zone.records}
self.assertEqual(7, len(got))
# 'a' was replaced with a generic record
- self.assertEqual({
- 'ttl': 3600,
- 'values': ['4.4.4.4', '5.5.5.5']
- }, got['a'].data)
+ self.assertEqual(
+ {'ttl': 3600, 'values': ['4.4.4.4', '5.5.5.5']}, got['a'].data
+ )
# And we have the new one
self.assertTrue('added' in got)
diff --git a/tests/test_octodns_record.py b/tests/test_octodns_record.py
index 4649745..2bbea5d 100644
--- a/tests/test_octodns_record.py
+++ b/tests/test_octodns_record.py
@@ -2,18 +2,53 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
-from octodns.record import ARecord, AaaaRecord, AliasRecord, CaaRecord, \
- CaaValue, CnameRecord, DnameRecord, Create, Delete, GeoValue, LocRecord, \
- LocValue, MxRecord, MxValue, NaptrRecord, NaptrValue, NsRecord, \
- PtrRecord, Record, RecordException, SshfpRecord, SshfpValue, SpfRecord, \
- SrvRecord, SrvValue, TlsaRecord, TxtRecord, Update, UrlfwdRecord, \
- UrlfwdValue, ValidationError, _Dynamic, _DynamicPool, _DynamicRule, \
- _NsValue, ValuesMixin
+from octodns.record import (
+ ARecord,
+ AaaaRecord,
+ AliasRecord,
+ CaaRecord,
+ CaaValue,
+ CnameRecord,
+ DnameRecord,
+ Create,
+ Delete,
+ GeoValue,
+ LocRecord,
+ LocValue,
+ MxRecord,
+ MxValue,
+ NaptrRecord,
+ NaptrValue,
+ NsRecord,
+ PtrRecord,
+ Record,
+ RecordException,
+ SshfpRecord,
+ SshfpValue,
+ SpfRecord,
+ SrvRecord,
+ SrvValue,
+ TlsaRecord,
+ TxtRecord,
+ Update,
+ UrlfwdRecord,
+ UrlfwdValue,
+ ValidationError,
+ _Dynamic,
+ _DynamicPool,
+ _DynamicRule,
+ _NsValue,
+ ValuesMixin,
+)
from octodns.zone import Zone
from helpers import DynamicProvider, GeoProvider, SimpleProvider
@@ -25,79 +60,79 @@ class TestRecord(TestCase):
def test_registration(self):
with self.assertRaises(RecordException) as ctx:
Record.register_type(None, 'A')
- self.assertEqual('Type "A" already registered by '
- 'octodns.record.ARecord', str(ctx.exception))
+ self.assertEqual(
+ 'Type "A" already registered by ' 'octodns.record.ARecord',
+ str(ctx.exception),
+ )
class AaRecord(ValuesMixin, Record):
_type = 'AA'
_value_type = _NsValue
Record.register_type(AaRecord)
- aa = Record.new(self.zone, 'registered', {
- 'ttl': 360,
- 'type': 'AA',
- 'value': 'does.not.matter.',
- })
+ aa = Record.new(
+ self.zone,
+ 'registered',
+ {'ttl': 360, 'type': 'AA', 'value': 'does.not.matter.'},
+ )
self.assertEqual(AaRecord, aa.__class__)
def test_lowering(self):
- record = ARecord(self.zone, 'MiXeDcAsE', {
- 'ttl': 30,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ record = ARecord(
+ self.zone, 'MiXeDcAsE', {'ttl': 30, 'type': 'A', 'value': '1.2.3.4'}
+ )
self.assertEqual('mixedcase', record.name)
def test_alias_lowering_value(self):
- upper_record = AliasRecord(self.zone, 'aliasUppwerValue', {
- 'ttl': 30,
- 'type': 'ALIAS',
- 'value': 'GITHUB.COM',
- })
- lower_record = AliasRecord(self.zone, 'aliasLowerValue', {
- 'ttl': 30,
- 'type': 'ALIAS',
- 'value': 'github.com',
- })
+ upper_record = AliasRecord(
+ self.zone,
+ 'aliasUppwerValue',
+ {'ttl': 30, 'type': 'ALIAS', 'value': 'GITHUB.COM'},
+ )
+ lower_record = AliasRecord(
+ self.zone,
+ 'aliasLowerValue',
+ {'ttl': 30, 'type': 'ALIAS', 'value': 'github.com'},
+ )
self.assertEqual(upper_record.value, lower_record.value)
def test_cname_lowering_value(self):
- upper_record = CnameRecord(self.zone, 'CnameUppwerValue', {
- 'ttl': 30,
- 'type': 'CNAME',
- 'value': 'GITHUB.COM',
- })
- lower_record = CnameRecord(self.zone, 'CnameLowerValue', {
- 'ttl': 30,
- 'type': 'CNAME',
- 'value': 'github.com',
- })
+ upper_record = CnameRecord(
+ self.zone,
+ 'CnameUppwerValue',
+ {'ttl': 30, 'type': 'CNAME', 'value': 'GITHUB.COM'},
+ )
+ lower_record = CnameRecord(
+ self.zone,
+ 'CnameLowerValue',
+ {'ttl': 30, 'type': 'CNAME', 'value': 'github.com'},
+ )
self.assertEqual(upper_record.value, lower_record.value)
def test_dname_lowering_value(self):
- upper_record = DnameRecord(self.zone, 'DnameUppwerValue', {
- 'ttl': 30,
- 'type': 'DNAME',
- 'value': 'GITHUB.COM',
- })
- lower_record = DnameRecord(self.zone, 'DnameLowerValue', {
- 'ttl': 30,
- 'type': 'DNAME',
- 'value': 'github.com',
- })
+ upper_record = DnameRecord(
+ self.zone,
+ 'DnameUppwerValue',
+ {'ttl': 30, 'type': 'DNAME', 'value': 'GITHUB.COM'},
+ )
+ lower_record = DnameRecord(
+ self.zone,
+ 'DnameLowerValue',
+ {'ttl': 30, 'type': 'DNAME', 'value': 'github.com'},
+ )
self.assertEqual(upper_record.value, lower_record.value)
def test_ptr_lowering_value(self):
- upper_record = PtrRecord(self.zone, 'PtrUppwerValue', {
- 'ttl': 30,
- 'type': 'PTR',
- 'value': 'GITHUB.COM',
- })
- lower_record = PtrRecord(self.zone, 'PtrLowerValue', {
- 'ttl': 30,
- 'type': 'PTR',
- 'value': 'github.com',
- })
+ upper_record = PtrRecord(
+ self.zone,
+ 'PtrUppwerValue',
+ {'ttl': 30, 'type': 'PTR', 'value': 'GITHUB.COM'},
+ )
+ lower_record = PtrRecord(
+ self.zone,
+ 'PtrLowerValue',
+ {'ttl': 30, 'type': 'PTR', 'value': 'github.com'},
+ )
self.assertEqual(upper_record.value, lower_record.value)
def test_a_and_record(self):
@@ -126,11 +161,13 @@ class TestRecord(TestCase):
# Records with differing names and same type don't equate
self.assertFalse(a == b)
# Records with same name & type equate even if ttl is different
- self.assertTrue(a == ARecord(self.zone, 'a',
- {'ttl': 31, 'values': a_values}))
+ self.assertTrue(
+ a == ARecord(self.zone, 'a', {'ttl': 31, 'values': a_values})
+ )
# Records with same name & type equate even if values are different
- self.assertTrue(a == ARecord(self.zone, 'a',
- {'ttl': 30, 'value': b_value}))
+ self.assertTrue(
+ a == ARecord(self.zone, 'a', {'ttl': 30, 'value': b_value})
+ )
target = SimpleProvider()
# no changes if self
@@ -162,8 +199,8 @@ class TestRecord(TestCase):
a.__repr__()
# Record.__repr__ does
with self.assertRaises(NotImplementedError):
- class DummyRecord(Record):
+ class DummyRecord(Record):
def __init__(self):
pass
@@ -171,69 +208,65 @@ class TestRecord(TestCase):
def test_values_mixin_data(self):
# no values, no value or values in data
- a = ARecord(self.zone, '', {
- 'type': 'A',
- 'ttl': 600,
- 'values': []
- })
+ a = ARecord(self.zone, '', {'type': 'A', 'ttl': 600, 'values': []})
self.assertNotIn('values', a.data)
# empty value, no value or values in data
- b = ARecord(self.zone, '', {
- 'type': 'A',
- 'ttl': 600,
- 'values': ['']
- })
+ b = ARecord(self.zone, '', {'type': 'A', 'ttl': 600, 'values': ['']})
self.assertNotIn('value', b.data)
# empty/None values, no value or values in data
- c = ARecord(self.zone, '', {
- 'type': 'A',
- 'ttl': 600,
- 'values': ['', None]
- })
+ c = ARecord(
+ self.zone, '', {'type': 'A', 'ttl': 600, 'values': ['', None]}
+ )
self.assertNotIn('values', c.data)
# empty/None values and valid, value in data
- c = ARecord(self.zone, '', {
- 'type': 'A',
- 'ttl': 600,
- 'values': ['', None, '10.10.10.10']
- })
+ c = ARecord(
+ self.zone,
+ '',
+ {'type': 'A', 'ttl': 600, 'values': ['', None, '10.10.10.10']},
+ )
self.assertNotIn('values', c.data)
self.assertEqual('10.10.10.10', c.data['value'])
def test_value_mixin_data(self):
# unspecified value, no value in data
- a = AliasRecord(self.zone, '', {
- 'type': 'ALIAS',
- 'ttl': 600,
- 'value': None
- })
+ a = AliasRecord(
+ self.zone, '', {'type': 'ALIAS', 'ttl': 600, 'value': None}
+ )
self.assertNotIn('value', a.data)
# unspecified value, no value in data
- a = AliasRecord(self.zone, '', {
- 'type': 'ALIAS',
- 'ttl': 600,
- 'value': ''
- })
+ a = AliasRecord(
+ self.zone, '', {'type': 'ALIAS', 'ttl': 600, 'value': ''}
+ )
self.assertNotIn('value', a.data)
def test_geo(self):
- geo_data = {'ttl': 42, 'values': ['5.2.3.4', '6.2.3.4'],
- 'geo': {'AF': ['1.1.1.1'],
- 'AS-JP': ['2.2.2.2', '3.3.3.3'],
- 'NA-US': ['4.4.4.4', '5.5.5.5'],
- 'NA-US-CA': ['6.6.6.6', '7.7.7.7']}}
+ geo_data = {
+ 'ttl': 42,
+ 'values': ['5.2.3.4', '6.2.3.4'],
+ 'geo': {
+ 'AF': ['1.1.1.1'],
+ 'AS-JP': ['2.2.2.2', '3.3.3.3'],
+ 'NA-US': ['4.4.4.4', '5.5.5.5'],
+ 'NA-US-CA': ['6.6.6.6', '7.7.7.7'],
+ },
+ }
geo = ARecord(self.zone, 'geo', geo_data)
self.assertEqual(geo_data, geo.data)
- other_data = {'ttl': 42, 'values': ['5.2.3.4', '6.2.3.4'],
- 'geo': {'AF': ['1.1.1.1'],
- 'AS-JP': ['2.2.2.2', '3.3.3.3'],
- 'NA-US': ['4.4.4.4', '5.5.5.5'],
- 'NA-US-CA': ['6.6.6.6', '7.7.7.7']}}
+ other_data = {
+ 'ttl': 42,
+ 'values': ['5.2.3.4', '6.2.3.4'],
+ 'geo': {
+ 'AF': ['1.1.1.1'],
+ 'AS-JP': ['2.2.2.2', '3.3.3.3'],
+ 'NA-US': ['4.4.4.4', '5.5.5.5'],
+ 'NA-US-CA': ['6.6.6.6', '7.7.7.7'],
+ },
+ }
other = ARecord(self.zone, 'geo', other_data)
self.assertEqual(other_data, other.data)
@@ -277,18 +310,19 @@ class TestRecord(TestCase):
self.assertEqual(b_data, b.data)
def test_aaaa(self):
- a_values = ['2001:db8:3c4d:15::1a2f:1a2b',
- '2001:db8:3c4d:15::1a2f:1a3b']
+ a_values = [
+ '2001:db8:3c4d:15::1a2f:1a2b',
+ '2001:db8:3c4d:15::1a2f:1a3b',
+ ]
b_value = '2001:db8:3c4d:15::1a2f:1a4b'
self.assertMultipleValues(AaaaRecord, a_values, b_value)
# Specifically validate that we normalize IPv6 addresses
- values = ['2001:db8:3c4d:15:0000:0000:1a2f:1a2b',
- '2001:0db8:3c4d:0015::1a2f:1a3b']
- data = {
- 'ttl': 30,
- 'values': values,
- }
+ values = [
+ '2001:db8:3c4d:15:0000:0000:1a2f:1a2b',
+ '2001:0db8:3c4d:0015::1a2f:1a3b',
+ ]
+ data = {'ttl': 30, 'values': values}
record = AaaaRecord(self.zone, 'aaaa', data)
self.assertEqual(a_values, record.values)
@@ -341,15 +375,14 @@ class TestRecord(TestCase):
a.__repr__()
def test_caa(self):
- a_values = [{
- 'flags': 0,
- 'tag': 'issue',
- 'value': 'ca.example.net',
- }, {
- 'flags': 128,
- 'tag': 'iodef',
- 'value': 'mailto:security@example.com',
- }]
+ a_values = [
+ {'flags': 0, 'tag': 'issue', 'value': 'ca.example.net'},
+ {
+ 'flags': 128,
+ 'tag': 'iodef',
+ 'value': 'mailto:security@example.com',
+ },
+ ]
a_data = {'ttl': 30, 'values': a_values}
a = CaaRecord(self.zone, 'a', a_data)
self.assertEqual('a', a.name)
@@ -363,10 +396,7 @@ class TestRecord(TestCase):
self.assertEqual(a_values[1]['value'], a.values[1].value)
self.assertEqual(a_data, a.data)
- b_value = {
- 'tag': 'iodef',
- 'value': 'http://iodef.example.com/',
- }
+ b_value = {'tag': 'iodef', 'value': 'http://iodef.example.com/'}
b_data = {'ttl': 30, 'value': b_value}
b = CaaRecord(self.zone, 'b', b_data)
self.assertEqual(0, b.values[0].flags)
@@ -401,28 +431,28 @@ class TestRecord(TestCase):
a.__repr__()
def test_cname(self):
- self.assertSingleValue(CnameRecord, 'target.foo.com.',
- 'other.foo.com.')
+ self.assertSingleValue(CnameRecord, 'target.foo.com.', 'other.foo.com.')
def test_dname(self):
- self.assertSingleValue(DnameRecord, 'target.foo.com.',
- 'other.foo.com.')
+ self.assertSingleValue(DnameRecord, 'target.foo.com.', 'other.foo.com.')
def test_loc(self):
- a_values = [{
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_seconds': 52.1,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }]
+ a_values = [
+ {
+ 'lat_degrees': 31,
+ 'lat_minutes': 58,
+ 'lat_seconds': 52.1,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ }
+ ]
a_data = {'ttl': 30, 'values': a_values}
a = LocRecord(self.zone, 'a', a_data)
self.assertEqual('a', a.name)
@@ -431,22 +461,23 @@ class TestRecord(TestCase):
self.assertEqual(a_values[0]['lat_degrees'], a.values[0].lat_degrees)
self.assertEqual(a_values[0]['lat_minutes'], a.values[0].lat_minutes)
self.assertEqual(a_values[0]['lat_seconds'], a.values[0].lat_seconds)
- self.assertEqual(a_values[0]['lat_direction'],
- a.values[0].lat_direction)
- self.assertEqual(a_values[0]['long_degrees'],
- a.values[0].long_degrees)
- self.assertEqual(a_values[0]['long_minutes'],
- a.values[0].long_minutes)
- self.assertEqual(a_values[0]['long_seconds'],
- a.values[0].long_seconds)
- self.assertEqual(a_values[0]['long_direction'],
- a.values[0].long_direction)
+ self.assertEqual(
+ a_values[0]['lat_direction'], a.values[0].lat_direction
+ )
+ self.assertEqual(a_values[0]['long_degrees'], a.values[0].long_degrees)
+ self.assertEqual(a_values[0]['long_minutes'], a.values[0].long_minutes)
+ self.assertEqual(a_values[0]['long_seconds'], a.values[0].long_seconds)
+ self.assertEqual(
+ a_values[0]['long_direction'], a.values[0].long_direction
+ )
self.assertEqual(a_values[0]['altitude'], a.values[0].altitude)
self.assertEqual(a_values[0]['size'], a.values[0].size)
- self.assertEqual(a_values[0]['precision_horz'],
- a.values[0].precision_horz)
- self.assertEqual(a_values[0]['precision_vert'],
- a.values[0].precision_vert)
+ self.assertEqual(
+ a_values[0]['precision_horz'], a.values[0].precision_horz
+ )
+ self.assertEqual(
+ a_values[0]['precision_vert'], a.values[0].precision_vert
+ )
b_value = {
'lat_degrees': 32,
@@ -471,14 +502,11 @@ class TestRecord(TestCase):
self.assertEqual(b_value['long_degrees'], b.values[0].long_degrees)
self.assertEqual(b_value['long_minutes'], b.values[0].long_minutes)
self.assertEqual(b_value['long_seconds'], b.values[0].long_seconds)
- self.assertEqual(b_value['long_direction'],
- b.values[0].long_direction)
+ self.assertEqual(b_value['long_direction'], b.values[0].long_direction)
self.assertEqual(b_value['altitude'], b.values[0].altitude)
self.assertEqual(b_value['size'], b.values[0].size)
- self.assertEqual(b_value['precision_horz'],
- b.values[0].precision_horz)
- self.assertEqual(b_value['precision_vert'],
- b.values[0].precision_vert)
+ self.assertEqual(b_value['precision_horz'], b.values[0].precision_horz)
+ self.assertEqual(b_value['precision_vert'], b.values[0].precision_vert)
self.assertEqual(b_data, b.data)
target = SimpleProvider()
@@ -501,13 +529,10 @@ class TestRecord(TestCase):
a.__repr__()
def test_mx(self):
- a_values = [{
- 'preference': 10,
- 'exchange': 'smtp1.'
- }, {
- 'priority': 20,
- 'value': 'smtp2.'
- }]
+ a_values = [
+ {'preference': 10, 'exchange': 'smtp1.'},
+ {'priority': 20, 'value': 'smtp2.'},
+ ]
a_data = {'ttl': 30, 'values': a_values}
a = MxRecord(self.zone, 'a', a_data)
self.assertEqual('a', a.name)
@@ -517,29 +542,20 @@ class TestRecord(TestCase):
self.assertEqual(a_values[0]['exchange'], a.values[0].exchange)
self.assertEqual(a_values[1]['priority'], a.values[1].preference)
self.assertEqual(a_values[1]['value'], a.values[1].exchange)
- a_data['values'][1] = {
- 'preference': 20,
- 'exchange': 'smtp2.',
- }
+ a_data['values'][1] = {'preference': 20, 'exchange': 'smtp2.'}
self.assertEqual(a_data, a.data)
- b_value = {
- 'preference': 0,
- 'exchange': 'smtp3.',
- }
+ b_value = {'preference': 0, 'exchange': 'smtp3.'}
b_data = {'ttl': 30, 'value': b_value}
b = MxRecord(self.zone, 'b', b_data)
self.assertEqual(b_value['preference'], b.values[0].preference)
self.assertEqual(b_value['exchange'], b.values[0].exchange)
self.assertEqual(b_data, b.data)
- a_upper_values = [{
- 'preference': 10,
- 'exchange': 'SMTP1.'
- }, {
- 'priority': 20,
- 'value': 'SMTP2.'
- }]
+ a_upper_values = [
+ {'preference': 10, 'exchange': 'SMTP1.'},
+ {'priority': 20, 'value': 'SMTP2.'},
+ ]
a_upper_data = {'ttl': 30, 'values': a_upper_values}
a_upper = MxRecord(self.zone, 'a', a_upper_data)
self.assertEqual(a_upper.data, a.data)
@@ -564,21 +580,24 @@ class TestRecord(TestCase):
a.__repr__()
def test_naptr(self):
- a_values = [{
- 'order': 10,
- 'preference': 11,
- 'flags': 'X',
- 'service': 'Y',
- 'regexp': 'Z',
- 'replacement': '.',
- }, {
- 'order': 20,
- 'preference': 21,
- 'flags': 'A',
- 'service': 'B',
- 'regexp': 'C',
- 'replacement': 'foo.com',
- }]
+ a_values = [
+ {
+ 'order': 10,
+ 'preference': 11,
+ 'flags': 'X',
+ 'service': 'Y',
+ 'regexp': 'Z',
+ 'replacement': '.',
+ },
+ {
+ 'order': 20,
+ 'preference': 21,
+ 'flags': 'A',
+ 'service': 'B',
+ 'regexp': 'C',
+ 'replacement': 'foo.com',
+ },
+ ]
a_data = {'ttl': 30, 'values': a_values}
a = NaptrRecord(self.zone, 'a', a_data)
self.assertEqual('a', a.name)
@@ -627,128 +646,192 @@ class TestRecord(TestCase):
self.assertTrue(b_naptr_value <= b_naptr_value)
self.assertTrue(b_naptr_value >= b_naptr_value)
# by order
- self.assertTrue(b_naptr_value > NaptrValue({
- 'order': 10,
- 'preference': 31,
- 'flags': 'M',
- 'service': 'N',
- 'regexp': 'O',
- 'replacement': 'x',
- }))
- self.assertTrue(b_naptr_value < NaptrValue({
- 'order': 40,
- 'preference': 31,
- 'flags': 'M',
- 'service': 'N',
- 'regexp': 'O',
- 'replacement': 'x',
- }))
+ self.assertTrue(
+ b_naptr_value
+ > NaptrValue(
+ {
+ 'order': 10,
+ 'preference': 31,
+ 'flags': 'M',
+ 'service': 'N',
+ 'regexp': 'O',
+ 'replacement': 'x',
+ }
+ )
+ )
+ self.assertTrue(
+ b_naptr_value
+ < NaptrValue(
+ {
+ 'order': 40,
+ 'preference': 31,
+ 'flags': 'M',
+ 'service': 'N',
+ 'regexp': 'O',
+ 'replacement': 'x',
+ }
+ )
+ )
# by preference
- self.assertTrue(b_naptr_value > NaptrValue({
- 'order': 30,
- 'preference': 10,
- 'flags': 'M',
- 'service': 'N',
- 'regexp': 'O',
- 'replacement': 'x',
- }))
- self.assertTrue(b_naptr_value < NaptrValue({
- 'order': 30,
- 'preference': 40,
- 'flags': 'M',
- 'service': 'N',
- 'regexp': 'O',
- 'replacement': 'x',
- }))
+ self.assertTrue(
+ b_naptr_value
+ > NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 10,
+ 'flags': 'M',
+ 'service': 'N',
+ 'regexp': 'O',
+ 'replacement': 'x',
+ }
+ )
+ )
+ self.assertTrue(
+ b_naptr_value
+ < NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 40,
+ 'flags': 'M',
+ 'service': 'N',
+ 'regexp': 'O',
+ 'replacement': 'x',
+ }
+ )
+ )
# by flags
- self.assertTrue(b_naptr_value > NaptrValue({
- 'order': 30,
- 'preference': 31,
- 'flags': 'A',
- 'service': 'N',
- 'regexp': 'O',
- 'replacement': 'x',
- }))
- self.assertTrue(b_naptr_value < NaptrValue({
- 'order': 30,
- 'preference': 31,
- 'flags': 'Z',
- 'service': 'N',
- 'regexp': 'O',
- 'replacement': 'x',
- }))
+ self.assertTrue(
+ b_naptr_value
+ > NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 31,
+ 'flags': 'A',
+ 'service': 'N',
+ 'regexp': 'O',
+ 'replacement': 'x',
+ }
+ )
+ )
+ self.assertTrue(
+ b_naptr_value
+ < NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 31,
+ 'flags': 'Z',
+ 'service': 'N',
+ 'regexp': 'O',
+ 'replacement': 'x',
+ }
+ )
+ )
# by service
- self.assertTrue(b_naptr_value > NaptrValue({
- 'order': 30,
- 'preference': 31,
- 'flags': 'M',
- 'service': 'A',
- 'regexp': 'O',
- 'replacement': 'x',
- }))
- self.assertTrue(b_naptr_value < NaptrValue({
- 'order': 30,
- 'preference': 31,
- 'flags': 'M',
- 'service': 'Z',
- 'regexp': 'O',
- 'replacement': 'x',
- }))
+ self.assertTrue(
+ b_naptr_value
+ > NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 31,
+ 'flags': 'M',
+ 'service': 'A',
+ 'regexp': 'O',
+ 'replacement': 'x',
+ }
+ )
+ )
+ self.assertTrue(
+ b_naptr_value
+ < NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 31,
+ 'flags': 'M',
+ 'service': 'Z',
+ 'regexp': 'O',
+ 'replacement': 'x',
+ }
+ )
+ )
# by regexp
- self.assertTrue(b_naptr_value > NaptrValue({
- 'order': 30,
- 'preference': 31,
- 'flags': 'M',
- 'service': 'N',
- 'regexp': 'A',
- 'replacement': 'x',
- }))
- self.assertTrue(b_naptr_value < NaptrValue({
- 'order': 30,
- 'preference': 31,
- 'flags': 'M',
- 'service': 'N',
- 'regexp': 'Z',
- 'replacement': 'x',
- }))
+ self.assertTrue(
+ b_naptr_value
+ > NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 31,
+ 'flags': 'M',
+ 'service': 'N',
+ 'regexp': 'A',
+ 'replacement': 'x',
+ }
+ )
+ )
+ self.assertTrue(
+ b_naptr_value
+ < NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 31,
+ 'flags': 'M',
+ 'service': 'N',
+ 'regexp': 'Z',
+ 'replacement': 'x',
+ }
+ )
+ )
# by replacement
- self.assertTrue(b_naptr_value > NaptrValue({
- 'order': 30,
- 'preference': 31,
- 'flags': 'M',
- 'service': 'N',
- 'regexp': 'O',
- 'replacement': 'a',
- }))
- self.assertTrue(b_naptr_value < NaptrValue({
- 'order': 30,
- 'preference': 31,
- 'flags': 'M',
- 'service': 'N',
- 'regexp': 'O',
- 'replacement': 'z',
- }))
+ self.assertTrue(
+ b_naptr_value
+ > NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 31,
+ 'flags': 'M',
+ 'service': 'N',
+ 'regexp': 'O',
+ 'replacement': 'a',
+ }
+ )
+ )
+ self.assertTrue(
+ b_naptr_value
+ < NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 31,
+ 'flags': 'M',
+ 'service': 'N',
+ 'regexp': 'O',
+ 'replacement': 'z',
+ }
+ )
+ )
# __repr__ doesn't blow up
a.__repr__()
# Hash
- v = NaptrValue({
- 'order': 30,
- 'preference': 31,
- 'flags': 'M',
- 'service': 'N',
- 'regexp': 'O',
- 'replacement': 'z',
- })
- o = NaptrValue({
- 'order': 30,
- 'preference': 32,
- 'flags': 'M',
- 'service': 'N',
- 'regexp': 'O',
- 'replacement': 'z',
- })
+ v = NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 31,
+ 'flags': 'M',
+ 'service': 'N',
+ 'regexp': 'O',
+ 'replacement': 'z',
+ }
+ )
+ o = NaptrValue(
+ {
+ 'order': 30,
+ 'preference': 32,
+ 'flags': 'M',
+ 'service': 'N',
+ 'regexp': 'O',
+ 'replacement': 'z',
+ }
+ )
values = set()
values.add(v)
self.assertTrue(v in values)
@@ -773,23 +856,19 @@ class TestRecord(TestCase):
self.assertEqual(b_data, b.data)
def test_sshfp(self):
- a_values = [{
- 'algorithm': 10,
- 'fingerprint_type': 11,
- 'fingerprint': 'abc123',
- }, {
- 'algorithm': 20,
- 'fingerprint_type': 21,
- 'fingerprint': 'def456',
- }]
+ a_values = [
+ {'algorithm': 10, 'fingerprint_type': 11, 'fingerprint': 'abc123'},
+ {'algorithm': 20, 'fingerprint_type': 21, 'fingerprint': 'def456'},
+ ]
a_data = {'ttl': 30, 'values': a_values}
a = SshfpRecord(self.zone, 'a', a_data)
self.assertEqual('a', a.name)
self.assertEqual('a.unit.tests.', a.fqdn)
self.assertEqual(30, a.ttl)
self.assertEqual(a_values[0]['algorithm'], a.values[0].algorithm)
- self.assertEqual(a_values[0]['fingerprint_type'],
- a.values[0].fingerprint_type)
+ self.assertEqual(
+ a_values[0]['fingerprint_type'], a.values[0].fingerprint_type
+ )
self.assertEqual(a_values[0]['fingerprint'], a.values[0].fingerprint)
self.assertEqual(a_data, a.data)
@@ -801,8 +880,9 @@ class TestRecord(TestCase):
b_data = {'ttl': 30, 'value': b_value}
b = SshfpRecord(self.zone, 'b', b_data)
self.assertEqual(b_value['algorithm'], b.values[0].algorithm)
- self.assertEqual(b_value['fingerprint_type'],
- b.values[0].fingerprint_type)
+ self.assertEqual(
+ b_value['fingerprint_type'], b.values[0].fingerprint_type
+ )
self.assertEqual(b_value['fingerprint'], b.values[0].fingerprint)
self.assertEqual(b_data, b.data)
@@ -839,17 +919,10 @@ class TestRecord(TestCase):
self.assertMultipleValues(SpfRecord, a_values, b_value)
def test_srv(self):
- a_values = [{
- 'priority': 10,
- 'weight': 11,
- 'port': 12,
- 'target': 'server1',
- }, {
- 'priority': 20,
- 'weight': 21,
- 'port': 22,
- 'target': 'server2',
- }]
+ a_values = [
+ {'priority': 10, 'weight': 11, 'port': 12, 'target': 'server1'},
+ {'priority': 20, 'weight': 21, 'port': 22, 'target': 'server2'},
+ ]
a_data = {'ttl': 30, 'values': a_values}
a = SrvRecord(self.zone, '_a._tcp', a_data)
self.assertEqual('_a._tcp', a.name)
@@ -879,8 +952,9 @@ class TestRecord(TestCase):
# No changes with self
self.assertFalse(a.changes(a, target))
# Diff in priority causes change
- other = SrvRecord(self.zone, '_a._icmp',
- {'ttl': 30, 'values': a_values})
+ other = SrvRecord(
+ self.zone, '_a._icmp', {'ttl': 30, 'values': a_values}
+ )
other.values[0].priority = 22
change = a.changes(other, target)
self.assertEqual(change.existing, a)
@@ -908,38 +982,48 @@ class TestRecord(TestCase):
a.__repr__()
def test_tlsa(self):
- a_values = [{
- 'certificate_usage': 1,
- 'selector': 1,
- 'matching_type': 1,
- 'certificate_association_data': 'ABABABABABABABABAB',
- }, {
- 'certificate_usage': 2,
- 'selector': 0,
- 'matching_type': 2,
- 'certificate_association_data': 'ABABABABABABABABAC',
- }]
+ a_values = [
+ {
+ 'certificate_usage': 1,
+ 'selector': 1,
+ 'matching_type': 1,
+ 'certificate_association_data': 'ABABABABABABABABAB',
+ },
+ {
+ 'certificate_usage': 2,
+ 'selector': 0,
+ 'matching_type': 2,
+ 'certificate_association_data': 'ABABABABABABABABAC',
+ },
+ ]
a_data = {'ttl': 30, 'values': a_values}
a = TlsaRecord(self.zone, 'a', a_data)
self.assertEqual('a.unit.tests.', a.fqdn)
self.assertEqual('a', a.name)
self.assertEqual(30, a.ttl)
- self.assertEqual(a_values[0]['certificate_usage'],
- a.values[0].certificate_usage)
+ self.assertEqual(
+ a_values[0]['certificate_usage'], a.values[0].certificate_usage
+ )
self.assertEqual(a_values[0]['selector'], a.values[0].selector)
- self.assertEqual(a_values[0]['matching_type'],
- a.values[0].matching_type)
- self.assertEqual(a_values[0]['certificate_association_data'],
- a.values[0].certificate_association_data)
+ self.assertEqual(
+ a_values[0]['matching_type'], a.values[0].matching_type
+ )
+ self.assertEqual(
+ a_values[0]['certificate_association_data'],
+ a.values[0].certificate_association_data,
+ )
- self.assertEqual(a_values[1]['certificate_usage'],
- a.values[1].certificate_usage)
- self.assertEqual(a_values[1]['selector'],
- a.values[1].selector)
- self.assertEqual(a_values[1]['matching_type'],
- a.values[1].matching_type)
- self.assertEqual(a_values[1]['certificate_association_data'],
- a.values[1].certificate_association_data)
+ self.assertEqual(
+ a_values[1]['certificate_usage'], a.values[1].certificate_usage
+ )
+ self.assertEqual(a_values[1]['selector'], a.values[1].selector)
+ self.assertEqual(
+ a_values[1]['matching_type'], a.values[1].matching_type
+ )
+ self.assertEqual(
+ a_values[1]['certificate_association_data'],
+ a.values[1].certificate_association_data,
+ )
self.assertEqual(a_data, a.data)
b_value = {
@@ -950,13 +1034,15 @@ class TestRecord(TestCase):
}
b_data = {'ttl': 30, 'value': b_value}
b = TlsaRecord(self.zone, 'b', b_data)
- self.assertEqual(b_value['certificate_usage'],
- b.values[0].certificate_usage)
+ self.assertEqual(
+ b_value['certificate_usage'], b.values[0].certificate_usage
+ )
self.assertEqual(b_value['selector'], b.values[0].selector)
- self.assertEqual(b_value['matching_type'],
- b.values[0].matching_type)
- self.assertEqual(b_value['certificate_association_data'],
- b.values[0].certificate_association_data)
+ self.assertEqual(b_value['matching_type'], b.values[0].matching_type)
+ self.assertEqual(
+ b_value['certificate_association_data'],
+ b.values[0].certificate_association_data,
+ )
self.assertEqual(b_data, b.data)
target = SimpleProvider()
@@ -996,19 +1082,22 @@ class TestRecord(TestCase):
self.assertMultipleValues(TxtRecord, a_values, b_value)
def test_urlfwd(self):
- a_values = [{
- 'path': '/',
- 'target': 'http://foo',
- 'code': 301,
- 'masking': 2,
- 'query': 0,
- }, {
- 'path': '/target',
- 'target': 'http://target',
- 'code': 302,
- 'masking': 2,
- 'query': 0,
- }]
+ a_values = [
+ {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'code': 301,
+ 'masking': 2,
+ 'query': 0,
+ },
+ {
+ 'path': '/target',
+ 'target': 'http://target',
+ 'code': 302,
+ 'masking': 2,
+ 'query': 0,
+ },
+ ]
a_data = {'ttl': 30, 'values': a_values}
a = UrlfwdRecord(self.zone, 'a', a_data)
self.assertEqual('a', a.name)
@@ -1077,20 +1166,24 @@ class TestRecord(TestCase):
self.assertEqual(change.new, other)
# hash
- v = UrlfwdValue({
- 'path': '/',
- 'target': 'http://place',
- 'code': 301,
- 'masking': 2,
- 'query': 0,
- })
- o = UrlfwdValue({
- 'path': '/location',
- 'target': 'http://redirect',
- 'code': 302,
- 'masking': 2,
- 'query': 0,
- })
+ v = UrlfwdValue(
+ {
+ 'path': '/',
+ 'target': 'http://place',
+ 'code': 301,
+ 'masking': 2,
+ 'query': 0,
+ }
+ )
+ o = UrlfwdValue(
+ {
+ 'path': '/location',
+ 'target': 'http://redirect',
+ 'code': 302,
+ 'masking': 2,
+ 'query': 0,
+ }
+ )
values = set()
values.add(v)
self.assertTrue(v in values)
@@ -1102,11 +1195,9 @@ class TestRecord(TestCase):
a.__repr__()
def test_record_new(self):
- txt = Record.new(self.zone, 'txt', {
- 'ttl': 44,
- 'type': 'TXT',
- 'value': 'some text',
- })
+ txt = Record.new(
+ self.zone, 'txt', {'ttl': 44, 'type': 'TXT', 'value': 'some text'}
+ )
self.assertIsInstance(txt, TxtRecord)
self.assertEqual('TXT', txt._type)
self.assertEqual(['some text'], txt.values)
@@ -1118,17 +1209,13 @@ class TestRecord(TestCase):
# Unknown type
with self.assertRaises(Exception) as ctx:
- Record.new(self.zone, 'unknown', {
- 'type': 'XXX',
- })
+ Record.new(self.zone, 'unknown', {'type': 'XXX'})
self.assertTrue('Unknown record type' in str(ctx.exception))
def test_record_copy(self):
- a = Record.new(self.zone, 'a', {
- 'ttl': 44,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ a = Record.new(
+ self.zone, 'a', {'ttl': 44, 'type': 'A', 'value': '1.2.3.4'}
+ )
# Identical copy.
b = a.copy()
@@ -1148,10 +1235,7 @@ class TestRecord(TestCase):
self.assertEqual(['1.2.3.4'], c.values)
# Record with no record type specified in data.
- d_data = {
- 'ttl': 600,
- 'values': ['just a test']
- }
+ d_data = {'ttl': 600, 'values': ['just a test']}
d = TxtRecord(self.zone, 'txt', d_data)
d.copy()
self.assertEqual('TXT', d._type)
@@ -1159,45 +1243,25 @@ class TestRecord(TestCase):
def test_dynamic_record_copy(self):
a_data = {
'dynamic': {
- 'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }],
- },
- },
- 'rules': [{
- 'pool': 'one',
- }],
- },
- 'octodns': {
- 'healthcheck': {
- 'protocol': 'TCP',
- 'port': 80,
- },
+ 'pools': {'one': {'values': [{'value': '3.3.3.3'}]}},
+ 'rules': [{'pool': 'one'}],
},
+ 'octodns': {'healthcheck': {'protocol': 'TCP', 'port': 80}},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
record1 = Record.new(self.zone, 'a', a_data)
record2 = record1.copy()
self.assertEqual(record1._octodns, record2._octodns)
def test_change(self):
- existing = Record.new(self.zone, 'txt', {
- 'ttl': 44,
- 'type': 'TXT',
- 'value': 'some text',
- })
- new = Record.new(self.zone, 'txt', {
- 'ttl': 44,
- 'type': 'TXT',
- 'value': 'some change',
- })
+ existing = Record.new(
+ self.zone, 'txt', {'ttl': 44, 'type': 'TXT', 'value': 'some text'}
+ )
+ new = Record.new(
+ self.zone, 'txt', {'ttl': 44, 'type': 'TXT', 'value': 'some change'}
+ )
create = Create(new)
self.assertEqual(new.values, create.record.values)
update = Update(existing, new)
@@ -1249,131 +1313,141 @@ class TestRecord(TestCase):
self.assertTrue(c >= b)
def test_healthcheck(self):
- new = Record.new(self.zone, 'a', {
- 'ttl': 44,
- 'type': 'A',
- 'value': '1.2.3.4',
- 'octodns': {
- 'healthcheck': {
- 'path': '/_ready',
- 'host': 'bleep.bloop',
- 'protocol': 'HTTP',
- 'port': 8080,
- }
- }
- })
+ new = Record.new(
+ self.zone,
+ 'a',
+ {
+ 'ttl': 44,
+ 'type': 'A',
+ 'value': '1.2.3.4',
+ 'octodns': {
+ 'healthcheck': {
+ 'path': '/_ready',
+ 'host': 'bleep.bloop',
+ 'protocol': 'HTTP',
+ 'port': 8080,
+ }
+ },
+ },
+ )
self.assertEqual('/_ready', new.healthcheck_path)
self.assertEqual('bleep.bloop', new.healthcheck_host())
self.assertEqual('HTTP', new.healthcheck_protocol)
self.assertEqual(8080, new.healthcheck_port)
# empty host value in healthcheck
- new = Record.new(self.zone, 'a', {
- 'ttl': 44,
- 'type': 'A',
- 'value': '1.2.3.4',
- 'octodns': {
- 'healthcheck': {
- 'path': '/_ready',
- 'host': None,
- 'protocol': 'HTTP',
- 'port': 8080,
- }
- }
- })
+ new = Record.new(
+ self.zone,
+ 'a',
+ {
+ 'ttl': 44,
+ 'type': 'A',
+ 'value': '1.2.3.4',
+ 'octodns': {
+ 'healthcheck': {
+ 'path': '/_ready',
+ 'host': None,
+ 'protocol': 'HTTP',
+ 'port': 8080,
+ }
+ },
+ },
+ )
self.assertEqual('1.2.3.4', new.healthcheck_host(value="1.2.3.4"))
- new = Record.new(self.zone, 'a', {
- 'ttl': 44,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ new = Record.new(
+ self.zone, 'a', {'ttl': 44, 'type': 'A', 'value': '1.2.3.4'}
+ )
self.assertEqual('/_dns', new.healthcheck_path)
self.assertEqual('a.unit.tests', new.healthcheck_host())
self.assertEqual('HTTPS', new.healthcheck_protocol)
self.assertEqual(443, new.healthcheck_port)
def test_healthcheck_tcp(self):
- new = Record.new(self.zone, 'a', {
- 'ttl': 44,
- 'type': 'A',
- 'value': '1.2.3.4',
- 'octodns': {
- 'healthcheck': {
- 'path': '/ignored',
- 'host': 'completely.ignored',
- 'protocol': 'TCP',
- 'port': 8080,
- }
- }
- })
+ new = Record.new(
+ self.zone,
+ 'a',
+ {
+ 'ttl': 44,
+ 'type': 'A',
+ 'value': '1.2.3.4',
+ 'octodns': {
+ 'healthcheck': {
+ 'path': '/ignored',
+ 'host': 'completely.ignored',
+ 'protocol': 'TCP',
+ 'port': 8080,
+ }
+ },
+ },
+ )
self.assertIsNone(new.healthcheck_path)
self.assertIsNone(new.healthcheck_host())
self.assertEqual('TCP', new.healthcheck_protocol)
self.assertEqual(8080, new.healthcheck_port)
- new = Record.new(self.zone, 'a', {
- 'ttl': 44,
- 'type': 'A',
- 'value': '1.2.3.4',
- 'octodns': {
- 'healthcheck': {
- 'protocol': 'TCP',
- }
- }
- })
+ new = Record.new(
+ self.zone,
+ 'a',
+ {
+ 'ttl': 44,
+ 'type': 'A',
+ 'value': '1.2.3.4',
+ 'octodns': {'healthcheck': {'protocol': 'TCP'}},
+ },
+ )
self.assertIsNone(new.healthcheck_path)
self.assertIsNone(new.healthcheck_host())
self.assertEqual('TCP', new.healthcheck_protocol)
self.assertEqual(443, new.healthcheck_port)
def test_inored(self):
- new = Record.new(self.zone, 'txt', {
- 'ttl': 44,
- 'type': 'TXT',
- 'value': 'some change',
- 'octodns': {
- 'ignored': True,
- }
- })
+ new = Record.new(
+ self.zone,
+ 'txt',
+ {
+ 'ttl': 44,
+ 'type': 'TXT',
+ 'value': 'some change',
+ 'octodns': {'ignored': True},
+ },
+ )
self.assertTrue(new.ignored)
- new = Record.new(self.zone, 'txt', {
- 'ttl': 44,
- 'type': 'TXT',
- 'value': 'some change',
- 'octodns': {
- 'ignored': False,
- }
- })
+ new = Record.new(
+ self.zone,
+ 'txt',
+ {
+ 'ttl': 44,
+ 'type': 'TXT',
+ 'value': 'some change',
+ 'octodns': {'ignored': False},
+ },
+ )
self.assertFalse(new.ignored)
- new = Record.new(self.zone, 'txt', {
- 'ttl': 44,
- 'type': 'TXT',
- 'value': 'some change',
- })
+ new = Record.new(
+ self.zone, 'txt', {'ttl': 44, 'type': 'TXT', 'value': 'some change'}
+ )
self.assertFalse(new.ignored)
def test_ordering_functions(self):
- a = Record.new(self.zone, 'a', {
- 'ttl': 44,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
- b = Record.new(self.zone, 'b', {
- 'ttl': 44,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
- c = Record.new(self.zone, 'c', {
- 'ttl': 44,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
- aaaa = Record.new(self.zone, 'a', {
- 'ttl': 44,
- 'type': 'AAAA',
- 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
- })
+ a = Record.new(
+ self.zone, 'a', {'ttl': 44, 'type': 'A', 'value': '1.2.3.4'}
+ )
+ b = Record.new(
+ self.zone, 'b', {'ttl': 44, 'type': 'A', 'value': '1.2.3.4'}
+ )
+ c = Record.new(
+ self.zone, 'c', {'ttl': 44, 'type': 'A', 'value': '1.2.3.4'}
+ )
+ aaaa = Record.new(
+ self.zone,
+ 'a',
+ {
+ 'ttl': 44,
+ 'type': 'AAAA',
+ 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
+ },
+ )
self.assertEqual(a, a)
self.assertEqual(b, b)
@@ -1485,48 +1559,54 @@ class TestRecord(TestCase):
self.assertTrue(d <= d)
def test_loc_value(self):
- a = LocValue({
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_seconds': 52.1,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- })
- b = LocValue({
- 'lat_degrees': 32,
- 'lat_minutes': 7,
- 'lat_seconds': 19,
- 'lat_direction': 'S',
- 'long_degrees': 116,
- 'long_minutes': 2,
- 'long_seconds': 25,
- 'long_direction': 'E',
- 'altitude': 10,
- 'size': 1,
- 'precision_horz': 10000,
- 'precision_vert': 10,
- })
- c = LocValue({
- 'lat_degrees': 53,
- 'lat_minutes': 14,
- 'lat_seconds': 10,
- 'lat_direction': 'N',
- 'long_degrees': 2,
- 'long_minutes': 18,
- 'long_seconds': 26,
- 'long_direction': 'W',
- 'altitude': 10,
- 'size': 1,
- 'precision_horz': 1000,
- 'precision_vert': 10,
- })
+ a = LocValue(
+ {
+ 'lat_degrees': 31,
+ 'lat_minutes': 58,
+ 'lat_seconds': 52.1,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ }
+ )
+ b = LocValue(
+ {
+ 'lat_degrees': 32,
+ 'lat_minutes': 7,
+ 'lat_seconds': 19,
+ 'lat_direction': 'S',
+ 'long_degrees': 116,
+ 'long_minutes': 2,
+ 'long_seconds': 25,
+ 'long_direction': 'E',
+ 'altitude': 10,
+ 'size': 1,
+ 'precision_horz': 10000,
+ 'precision_vert': 10,
+ }
+ )
+ c = LocValue(
+ {
+ 'lat_degrees': 53,
+ 'lat_minutes': 14,
+ 'lat_seconds': 10,
+ 'lat_direction': 'N',
+ 'long_degrees': 2,
+ 'long_minutes': 18,
+ 'long_seconds': 26,
+ 'long_direction': 'W',
+ 'altitude': 10,
+ 'size': 1,
+ 'precision_horz': 1000,
+ 'precision_vert': 10,
+ }
+ )
self.assertEqual(a, a)
self.assertEqual(b, b)
@@ -1572,12 +1652,15 @@ class TestRecord(TestCase):
self.assertTrue(b in values)
def test_mx_value(self):
- a = MxValue({'preference': 0, 'priority': 'a', 'exchange': 'v',
- 'value': '1'})
- b = MxValue({'preference': 10, 'priority': 'a', 'exchange': 'v',
- 'value': '2'})
- c = MxValue({'preference': 0, 'priority': 'b', 'exchange': 'z',
- 'value': '3'})
+ a = MxValue(
+ {'preference': 0, 'priority': 'a', 'exchange': 'v', 'value': '1'}
+ )
+ b = MxValue(
+ {'preference': 10, 'priority': 'a', 'exchange': 'v', 'value': '2'}
+ )
+ c = MxValue(
+ {'preference': 0, 'priority': 'b', 'exchange': 'z', 'value': '3'}
+ )
self.assertEqual(a, a)
self.assertEqual(b, b)
@@ -1618,14 +1701,18 @@ class TestRecord(TestCase):
self.assertNotEqual(a.__hash__(), b.__hash__())
def test_sshfp_value(self):
- a = SshfpValue({'algorithm': 0, 'fingerprint_type': 0,
- 'fingerprint': 'abcd'})
- b = SshfpValue({'algorithm': 1, 'fingerprint_type': 0,
- 'fingerprint': 'abcd'})
- c = SshfpValue({'algorithm': 0, 'fingerprint_type': 1,
- 'fingerprint': 'abcd'})
- d = SshfpValue({'algorithm': 0, 'fingerprint_type': 0,
- 'fingerprint': 'bcde'})
+ a = SshfpValue(
+ {'algorithm': 0, 'fingerprint_type': 0, 'fingerprint': 'abcd'}
+ )
+ b = SshfpValue(
+ {'algorithm': 1, 'fingerprint_type': 0, 'fingerprint': 'abcd'}
+ )
+ c = SshfpValue(
+ {'algorithm': 0, 'fingerprint_type': 1, 'fingerprint': 'abcd'}
+ )
+ d = SshfpValue(
+ {'algorithm': 0, 'fingerprint_type': 0, 'fingerprint': 'bcde'}
+ )
self.assertEqual(a, a)
self.assertEqual(b, b)
@@ -1751,11 +1838,9 @@ class TestRecordValidation(TestCase):
# name = '@'
with self.assertRaises(ValidationError) as ctx:
name = '@'
- Record.new(self.zone, name, {
- 'ttl': 300,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ Record.new(
+ self.zone, name, {'ttl': 300, 'type': 'A', 'value': '1.2.3.4'}
+ )
reason = ctx.exception.reasons[0]
self.assertTrue(reason.startswith('invalid name "@", use "" instead'))
@@ -1763,718 +1848,704 @@ class TestRecordValidation(TestCase):
with self.assertRaises(ValidationError) as ctx:
# The . will put this over the edge
name = 'x' * (253 - len(self.zone.name))
- Record.new(self.zone, name, {
- 'ttl': 300,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ Record.new(
+ self.zone, name, {'ttl': 300, 'type': 'A', 'value': '1.2.3.4'}
+ )
reason = ctx.exception.reasons[0]
self.assertTrue(reason.startswith('invalid fqdn, "xxxx'))
- self.assertTrue(reason.endswith('.unit.tests." is too long at 254'
- ' chars, max is 253'))
+ self.assertTrue(
+ reason.endswith(
+ '.unit.tests." is too long at 254' ' chars, max is 253'
+ )
+ )
# label length, DNS defines max as 63
with self.assertRaises(ValidationError) as ctx:
# The . will put this over the edge
name = 'x' * 64
- Record.new(self.zone, name, {
- 'ttl': 300,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ Record.new(
+ self.zone, name, {'ttl': 300, 'type': 'A', 'value': '1.2.3.4'}
+ )
reason = ctx.exception.reasons[0]
self.assertTrue(reason.startswith('invalid label, "xxxx'))
- self.assertTrue(reason.endswith('xxx" is too long at 64'
- ' chars, max is 63'))
+ self.assertTrue(
+ reason.endswith('xxx" is too long at 64' ' chars, max is 63')
+ )
with self.assertRaises(ValidationError) as ctx:
name = 'foo.' + 'x' * 64 + '.bar'
- Record.new(self.zone, name, {
- 'ttl': 300,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ Record.new(
+ self.zone, name, {'ttl': 300, 'type': 'A', 'value': '1.2.3.4'}
+ )
reason = ctx.exception.reasons[0]
self.assertTrue(reason.startswith('invalid label, "xxxx'))
- self.assertTrue(reason.endswith('xxx" is too long at 64'
- ' chars, max is 63'))
+ self.assertTrue(
+ reason.endswith('xxx" is too long at 64' ' chars, max is 63')
+ )
# should not raise with dots
name = 'xxxxxxxx.' * 10
- Record.new(self.zone, name, {
- 'ttl': 300,
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ Record.new(
+ self.zone, name, {'ttl': 300, 'type': 'A', 'value': '1.2.3.4'}
+ )
# no ttl
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'A',
- 'value': '1.2.3.4',
- })
+ Record.new(self.zone, '', {'type': 'A', 'value': '1.2.3.4'})
self.assertEqual(['missing ttl'], ctx.exception.reasons)
# invalid ttl
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'A',
- 'ttl': -1,
- 'value': '1.2.3.4',
- })
+ Record.new(
+ self.zone, 'www', {'type': 'A', 'ttl': -1, 'value': '1.2.3.4'}
+ )
self.assertEqual('www.unit.tests.', ctx.exception.fqdn)
self.assertEqual(['invalid ttl'], ctx.exception.reasons)
# no exception if we're in lenient mode
- Record.new(self.zone, 'www', {
- 'type': 'A',
- 'ttl': -1,
- 'value': '1.2.3.4',
- }, lenient=True)
+ Record.new(
+ self.zone,
+ 'www',
+ {'type': 'A', 'ttl': -1, 'value': '1.2.3.4'},
+ lenient=True,
+ )
# __init__ may still blow up, even if validation is lenient
with self.assertRaises(KeyError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'A',
- 'ttl': -1,
- }, lenient=True)
+ Record.new(self.zone, 'www', {'type': 'A', 'ttl': -1}, lenient=True)
self.assertEqual(('value',), ctx.exception.args)
# no exception if we're in lenient mode from config
- Record.new(self.zone, 'www', {
- 'octodns': {
- 'lenient': True
+ Record.new(
+ self.zone,
+ 'www',
+ {
+ 'octodns': {'lenient': True},
+ 'type': 'A',
+ 'ttl': -1,
+ 'value': '1.2.3.4',
},
- 'type': 'A',
- 'ttl': -1,
- 'value': '1.2.3.4',
- }, lenient=True)
+ lenient=True,
+ )
def test_A_and_values_mixin(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'A',
- 'ttl': 600,
- 'value': '1.2.3.4',
- })
- Record.new(self.zone, '', {
- 'type': 'A',
- 'ttl': 600,
- 'values': [
- '1.2.3.4',
- ]
- })
- Record.new(self.zone, '', {
- 'type': 'A',
- 'ttl': 600,
- 'values': [
- '1.2.3.4',
- '1.2.3.5',
- ]
- })
+ Record.new(self.zone, '', {'type': 'A', 'ttl': 600, 'value': '1.2.3.4'})
+ Record.new(
+ self.zone, '', {'type': 'A', 'ttl': 600, 'values': ['1.2.3.4']}
+ )
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'A', 'ttl': 600, 'values': ['1.2.3.4', '1.2.3.5']},
+ )
# missing value(s), no value or value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'A',
- 'ttl': 600,
- })
+ Record.new(self.zone, '', {'type': 'A', 'ttl': 600})
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# missing value(s), empty values
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'A',
- 'ttl': 600,
- 'values': []
- })
+ Record.new(
+ self.zone, 'www', {'type': 'A', 'ttl': 600, 'values': []}
+ )
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# missing value(s), None values
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'A',
- 'ttl': 600,
- 'values': None
- })
+ Record.new(
+ self.zone, 'www', {'type': 'A', 'ttl': 600, 'values': None}
+ )
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# missing value(s) and empty value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'A',
- 'ttl': 600,
- 'values': [None, '']
- })
- self.assertEqual(['missing value(s)',
- 'empty value'], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ 'www',
+ {'type': 'A', 'ttl': 600, 'values': [None, '']},
+ )
+ self.assertEqual(
+ ['missing value(s)', 'empty value'], ctx.exception.reasons
+ )
# missing value(s), None value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'A',
- 'ttl': 600,
- 'value': None
- })
+ Record.new(
+ self.zone, 'www', {'type': 'A', 'ttl': 600, 'value': None}
+ )
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# empty value, empty string value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'A',
- 'ttl': 600,
- 'value': ''
- })
+ Record.new(self.zone, 'www', {'type': 'A', 'ttl': 600, 'value': ''})
self.assertEqual(['empty value'], ctx.exception.reasons)
# missing value(s) & ttl
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'A',
- })
- self.assertEqual(['missing ttl', 'missing value(s)'],
- ctx.exception.reasons)
+ Record.new(self.zone, '', {'type': 'A'})
+ self.assertEqual(
+ ['missing ttl', 'missing value(s)'], ctx.exception.reasons
+ )
# invalid ipv4 address
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'A',
- 'ttl': 600,
- 'value': 'hello'
- })
- self.assertEqual(['invalid IPv4 address "hello"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone, '', {'type': 'A', 'ttl': 600, 'value': 'hello'}
+ )
+ self.assertEqual(
+ ['invalid IPv4 address "hello"'], ctx.exception.reasons
+ )
# invalid ipv4 addresses
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'A',
- 'ttl': 600,
- 'values': ['hello', 'goodbye']
- })
- self.assertEqual([
- 'invalid IPv4 address "hello"',
- 'invalid IPv4 address "goodbye"'
- ], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'A', 'ttl': 600, 'values': ['hello', 'goodbye']},
+ )
+ self.assertEqual(
+ ['invalid IPv4 address "hello"', 'invalid IPv4 address "goodbye"'],
+ ctx.exception.reasons,
+ )
# invalid & valid ipv4 addresses, no ttl
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'A',
- 'values': ['1.2.3.4', 'hello', '5.6.7.8']
- })
- self.assertEqual([
- 'missing ttl',
- 'invalid IPv4 address "hello"',
- ], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'A', 'values': ['1.2.3.4', 'hello', '5.6.7.8']},
+ )
+ self.assertEqual(
+ ['missing ttl', 'invalid IPv4 address "hello"'],
+ ctx.exception.reasons,
+ )
def test_AAAA_validation(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
- })
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'values': [
- '2601:644:500:e210:62f8:1dff:feb8:947a',
- ]
- })
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'values': [
- '2601:644:500:e210:62f8:1dff:feb8:947a',
- '2601:642:500:e210:62f8:1dff:feb8:947a',
- ]
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'AAAA',
+ 'ttl': 600,
+ 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
+ },
+ )
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'AAAA',
+ 'ttl': 600,
+ 'values': ['2601:644:500:e210:62f8:1dff:feb8:947a'],
+ },
+ )
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'AAAA',
+ 'ttl': 600,
+ 'values': [
+ '2601:644:500:e210:62f8:1dff:feb8:947a',
+ '2601:642:500:e210:62f8:1dff:feb8:947a',
+ ],
+ },
+ )
# missing value(s), no value or value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- 'ttl': 600,
- })
+ Record.new(self.zone, '', {'type': 'AAAA', 'ttl': 600})
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# missing value(s), empty values
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'values': []
- })
+ Record.new(
+ self.zone, 'www', {'type': 'AAAA', 'ttl': 600, 'values': []}
+ )
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# missing value(s), None values
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'values': None
- })
+ Record.new(
+ self.zone, 'www', {'type': 'AAAA', 'ttl': 600, 'values': None}
+ )
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# missing value(s) and empty value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'values': [None, '']
- })
- self.assertEqual(['missing value(s)',
- 'empty value'], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ 'www',
+ {'type': 'AAAA', 'ttl': 600, 'values': [None, '']},
+ )
+ self.assertEqual(
+ ['missing value(s)', 'empty value'], ctx.exception.reasons
+ )
# missing value(s), None value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'value': None
- })
+ Record.new(
+ self.zone, 'www', {'type': 'AAAA', 'ttl': 600, 'value': None}
+ )
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# empty value, empty string value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'value': ''
- })
+ Record.new(
+ self.zone, 'www', {'type': 'AAAA', 'ttl': 600, 'value': ''}
+ )
self.assertEqual(['empty value'], ctx.exception.reasons)
# missing value(s) & ttl
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- })
- self.assertEqual(['missing ttl', 'missing value(s)'],
- ctx.exception.reasons)
+ Record.new(self.zone, '', {'type': 'AAAA'})
+ self.assertEqual(
+ ['missing ttl', 'missing value(s)'], ctx.exception.reasons
+ )
# invalid IPv6 address
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'value': 'hello'
- })
- self.assertEqual(['invalid IPv6 address "hello"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone, '', {'type': 'AAAA', 'ttl': 600, 'value': 'hello'}
+ )
+ self.assertEqual(
+ ['invalid IPv6 address "hello"'], ctx.exception.reasons
+ )
# invalid IPv6 addresses
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'values': ['hello', 'goodbye']
- })
- self.assertEqual([
- 'invalid IPv6 address "hello"',
- 'invalid IPv6 address "goodbye"'
- ], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'AAAA', 'ttl': 600, 'values': ['hello', 'goodbye']},
+ )
+ self.assertEqual(
+ ['invalid IPv6 address "hello"', 'invalid IPv6 address "goodbye"'],
+ ctx.exception.reasons,
+ )
# invalid & valid IPv6 addresses, no ttl
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- 'values': [
- '2601:644:500:e210:62f8:1dff:feb8:947a',
- 'hello',
- '2601:642:500:e210:62f8:1dff:feb8:947a'
- ]
- })
- self.assertEqual([
- 'missing ttl',
- 'invalid IPv6 address "hello"',
- ], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'AAAA',
+ 'values': [
+ '2601:644:500:e210:62f8:1dff:feb8:947a',
+ 'hello',
+ '2601:642:500:e210:62f8:1dff:feb8:947a',
+ ],
+ },
+ )
+ self.assertEqual(
+ ['missing ttl', 'invalid IPv6 address "hello"'],
+ ctx.exception.reasons,
+ )
def test_geo(self):
- Record.new(self.zone, '', {
- 'geo': {
- 'NA': ['1.2.3.5'],
- 'NA-US': ['1.2.3.5', '1.2.3.6']
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'geo': {'NA': ['1.2.3.5'], 'NA-US': ['1.2.3.5', '1.2.3.6']},
+ 'type': 'A',
+ 'ttl': 600,
+ 'value': '1.2.3.4',
},
- 'type': 'A',
- 'ttl': 600,
- 'value': '1.2.3.4',
- })
+ )
# invalid ip address
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'geo': {
- 'NA': ['hello'],
- 'NA-US': ['1.2.3.5', '1.2.3.6']
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'geo': {'NA': ['hello'], 'NA-US': ['1.2.3.5', '1.2.3.6']},
+ 'type': 'A',
+ 'ttl': 600,
+ 'value': '1.2.3.4',
},
- 'type': 'A',
- 'ttl': 600,
- 'value': '1.2.3.4',
- })
- self.assertEqual(['invalid IPv4 address "hello"'],
- ctx.exception.reasons)
+ )
+ self.assertEqual(
+ ['invalid IPv4 address "hello"'], ctx.exception.reasons
+ )
# invalid geo code
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'geo': {
- 'XYZ': ['1.2.3.4'],
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'geo': {'XYZ': ['1.2.3.4']},
+ 'type': 'A',
+ 'ttl': 600,
+ 'value': '1.2.3.4',
},
- 'type': 'A',
- 'ttl': 600,
- 'value': '1.2.3.4',
- })
+ )
self.assertEqual(['invalid geo "XYZ"'], ctx.exception.reasons)
# invalid ip address
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'geo': {
- 'NA': ['hello'],
- 'NA-US': ['1.2.3.5', 'goodbye']
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'geo': {'NA': ['hello'], 'NA-US': ['1.2.3.5', 'goodbye']},
+ 'type': 'A',
+ 'ttl': 600,
+ 'value': '1.2.3.4',
},
- 'type': 'A',
- 'ttl': 600,
- 'value': '1.2.3.4',
- })
- self.assertEqual([
- 'invalid IPv4 address "hello"',
- 'invalid IPv4 address "goodbye"'
- ], ctx.exception.reasons)
+ )
+ self.assertEqual(
+ ['invalid IPv4 address "hello"', 'invalid IPv4 address "goodbye"'],
+ ctx.exception.reasons,
+ )
# invalid healthcheck protocol
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'a', {
- 'geo': {
- 'NA': ['1.2.3.5'],
- 'NA-US': ['1.2.3.5', '1.2.3.6']
+ Record.new(
+ self.zone,
+ 'a',
+ {
+ 'geo': {'NA': ['1.2.3.5'], 'NA-US': ['1.2.3.5', '1.2.3.6']},
+ 'type': 'A',
+ 'ttl': 600,
+ 'value': '1.2.3.4',
+ 'octodns': {'healthcheck': {'protocol': 'FTP'}},
},
- 'type': 'A',
- 'ttl': 600,
- 'value': '1.2.3.4',
- 'octodns': {
- 'healthcheck': {
- 'protocol': 'FTP',
- }
- }
- })
- self.assertEqual(['invalid healthcheck protocol'],
- ctx.exception.reasons)
+ )
+ self.assertEqual(
+ ['invalid healthcheck protocol'], ctx.exception.reasons
+ )
def test_AAAA(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
- })
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'values': [
- '2601:644:500:e210:62f8:1dff:feb8:947a',
- '2601:644:500:e210:62f8:1dff:feb8:947b',
- ]
- })
-
- # invalid ip address
- with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
+ Record.new(
+ self.zone,
+ '',
+ {
'type': 'AAAA',
'ttl': 600,
- 'value': 'hello'
- })
- self.assertEqual(['invalid IPv6 address "hello"'],
- ctx.exception.reasons)
- with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
+ 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
+ },
+ )
+ Record.new(
+ self.zone,
+ '',
+ {
'type': 'AAAA',
'ttl': 600,
'values': [
- '1.2.3.4',
- '2.3.4.5',
+ '2601:644:500:e210:62f8:1dff:feb8:947a',
+ '2601:644:500:e210:62f8:1dff:feb8:947b',
],
- })
- self.assertEqual([
- 'invalid IPv6 address "1.2.3.4"',
- 'invalid IPv6 address "2.3.4.5"',
- ], ctx.exception.reasons)
+ },
+ )
+
+ # invalid ip address
+ with self.assertRaises(ValidationError) as ctx:
+ Record.new(
+ self.zone, '', {'type': 'AAAA', 'ttl': 600, 'value': 'hello'}
+ )
+ self.assertEqual(
+ ['invalid IPv6 address "hello"'], ctx.exception.reasons
+ )
+ with self.assertRaises(ValidationError) as ctx:
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'AAAA', 'ttl': 600, 'values': ['1.2.3.4', '2.3.4.5']},
+ )
+ self.assertEqual(
+ [
+ 'invalid IPv6 address "1.2.3.4"',
+ 'invalid IPv6 address "2.3.4.5"',
+ ],
+ ctx.exception.reasons,
+ )
# invalid ip addresses
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'AAAA',
- 'ttl': 600,
- 'values': ['hello', 'goodbye']
- })
- self.assertEqual([
- 'invalid IPv6 address "hello"',
- 'invalid IPv6 address "goodbye"'
- ], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'AAAA', 'ttl': 600, 'values': ['hello', 'goodbye']},
+ )
+ self.assertEqual(
+ ['invalid IPv6 address "hello"', 'invalid IPv6 address "goodbye"'],
+ ctx.exception.reasons,
+ )
def test_ALIAS_and_value_mixin(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'ALIAS',
- 'ttl': 600,
- 'value': 'foo.bar.com.',
- })
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'ALIAS', 'ttl': 600, 'value': 'foo.bar.com.'},
+ )
# root only
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'nope', {
- 'type': 'ALIAS',
- 'ttl': 600,
- 'value': 'foo.bar.com.',
- })
- self.assertEqual(['non-root ALIAS not allowed'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ 'nope',
+ {'type': 'ALIAS', 'ttl': 600, 'value': 'foo.bar.com.'},
+ )
+ self.assertEqual(['non-root ALIAS not allowed'], ctx.exception.reasons)
# missing value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'ALIAS',
- 'ttl': 600,
- })
+ Record.new(self.zone, '', {'type': 'ALIAS', 'ttl': 600})
self.assertEqual(['missing value'], ctx.exception.reasons)
# missing value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'ALIAS',
- 'ttl': 600,
- 'value': None
- })
+ Record.new(
+ self.zone, '', {'type': 'ALIAS', 'ttl': 600, 'value': None}
+ )
self.assertEqual(['missing value'], ctx.exception.reasons)
# empty value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'ALIAS',
- 'ttl': 600,
- 'value': ''
- })
+ Record.new(
+ self.zone, '', {'type': 'ALIAS', 'ttl': 600, 'value': ''}
+ )
self.assertEqual(['empty value'], ctx.exception.reasons)
# not a valid FQDN
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'ALIAS',
- 'ttl': 600,
- 'value': '__.',
- })
- self.assertEqual(['ALIAS value "__." is not a valid FQDN'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone, '', {'type': 'ALIAS', 'ttl': 600, 'value': '__.'}
+ )
+ self.assertEqual(
+ ['ALIAS value "__." is not a valid FQDN'], ctx.exception.reasons
+ )
# missing trailing .
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'ALIAS',
- 'ttl': 600,
- 'value': 'foo.bar.com',
- })
- self.assertEqual(['ALIAS value "foo.bar.com" missing trailing .'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'ALIAS', 'ttl': 600, 'value': 'foo.bar.com'},
+ )
+ self.assertEqual(
+ ['ALIAS value "foo.bar.com" missing trailing .'],
+ ctx.exception.reasons,
+ )
def test_CAA(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'CAA',
- 'ttl': 600,
- 'value': {
- 'flags': 128,
- 'tag': 'iodef',
- 'value': 'http://foo.bar.com/'
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'CAA',
+ 'ttl': 600,
+ 'value': {
+ 'flags': 128,
+ 'tag': 'iodef',
+ 'value': 'http://foo.bar.com/',
+ },
+ },
+ )
# invalid flags
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'CAA',
- 'ttl': 600,
- 'value': {
- 'flags': -42,
- 'tag': 'iodef',
- 'value': 'http://foo.bar.com/',
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'CAA',
+ 'ttl': 600,
+ 'value': {
+ 'flags': -42,
+ 'tag': 'iodef',
+ 'value': 'http://foo.bar.com/',
+ },
+ },
+ )
self.assertEqual(['invalid flags "-42"'], ctx.exception.reasons)
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'CAA',
- 'ttl': 600,
- 'value': {
- 'flags': 442,
- 'tag': 'iodef',
- 'value': 'http://foo.bar.com/',
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'CAA',
+ 'ttl': 600,
+ 'value': {
+ 'flags': 442,
+ 'tag': 'iodef',
+ 'value': 'http://foo.bar.com/',
+ },
+ },
+ )
self.assertEqual(['invalid flags "442"'], ctx.exception.reasons)
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'CAA',
- 'ttl': 600,
- 'value': {
- 'flags': 'nope',
- 'tag': 'iodef',
- 'value': 'http://foo.bar.com/',
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'CAA',
+ 'ttl': 600,
+ 'value': {
+ 'flags': 'nope',
+ 'tag': 'iodef',
+ 'value': 'http://foo.bar.com/',
+ },
+ },
+ )
self.assertEqual(['invalid flags "nope"'], ctx.exception.reasons)
# missing tag
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'CAA',
- 'ttl': 600,
- 'value': {
- 'value': 'http://foo.bar.com/',
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'CAA',
+ 'ttl': 600,
+ 'value': {'value': 'http://foo.bar.com/'},
+ },
+ )
self.assertEqual(['missing tag'], ctx.exception.reasons)
# missing value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'CAA',
- 'ttl': 600,
- 'value': {
- 'tag': 'iodef',
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'CAA', 'ttl': 600, 'value': {'tag': 'iodef'}},
+ )
self.assertEqual(['missing value'], ctx.exception.reasons)
def test_CNAME(self):
# doesn't blow up
- Record.new(self.zone, 'www', {
- 'type': 'CNAME',
- 'ttl': 600,
- 'value': 'foo.bar.com.',
- })
+ Record.new(
+ self.zone,
+ 'www',
+ {'type': 'CNAME', 'ttl': 600, 'value': 'foo.bar.com.'},
+ )
# root cname is a no-no
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'CNAME',
- 'ttl': 600,
- 'value': 'foo.bar.com.',
- })
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'CNAME', 'ttl': 600, 'value': 'foo.bar.com.'},
+ )
self.assertEqual(['root CNAME not allowed'], ctx.exception.reasons)
# not a valid FQDN
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'CNAME',
- 'ttl': 600,
- 'value': '___.',
- })
- self.assertEqual(['CNAME value "___." is not a valid FQDN'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone, 'www', {'type': 'CNAME', 'ttl': 600, 'value': '___.'}
+ )
+ self.assertEqual(
+ ['CNAME value "___." is not a valid FQDN'], ctx.exception.reasons
+ )
# missing trailing .
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'CNAME',
- 'ttl': 600,
- 'value': 'foo.bar.com',
- })
- self.assertEqual(['CNAME value "foo.bar.com" missing trailing .'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ 'www',
+ {'type': 'CNAME', 'ttl': 600, 'value': 'foo.bar.com'},
+ )
+ self.assertEqual(
+ ['CNAME value "foo.bar.com" missing trailing .'],
+ ctx.exception.reasons,
+ )
# doesn't allow urls
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'CNAME',
- 'ttl': 600,
- 'value': 'https://google.com',
- })
- self.assertEqual(['CNAME value "https://google.com" is not a valid '
- 'FQDN'], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ 'www',
+ {'type': 'CNAME', 'ttl': 600, 'value': 'https://google.com'},
+ )
+ self.assertEqual(
+ ['CNAME value "https://google.com" is not a valid ' 'FQDN'],
+ ctx.exception.reasons,
+ )
# doesn't allow urls with paths
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'CNAME',
- 'ttl': 600,
- 'value': 'https://google.com/a/b/c',
- })
- self.assertEqual(['CNAME value "https://google.com/a/b/c" is not a '
- 'valid FQDN'], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ 'www',
+ {
+ 'type': 'CNAME',
+ 'ttl': 600,
+ 'value': 'https://google.com/a/b/c',
+ },
+ )
+ self.assertEqual(
+ ['CNAME value "https://google.com/a/b/c" is not a ' 'valid FQDN'],
+ ctx.exception.reasons,
+ )
# doesn't allow paths
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'CNAME',
- 'ttl': 600,
- 'value': 'google.com/some/path',
- })
- self.assertEqual(['CNAME value "google.com/some/path" is not a valid '
- 'FQDN'], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ 'www',
+ {'type': 'CNAME', 'ttl': 600, 'value': 'google.com/some/path'},
+ )
+ self.assertEqual(
+ ['CNAME value "google.com/some/path" is not a valid ' 'FQDN'],
+ ctx.exception.reasons,
+ )
def test_DNAME(self):
# A valid DNAME record.
- Record.new(self.zone, 'sub', {
- 'type': 'DNAME',
- 'ttl': 600,
- 'value': 'foo.bar.com.',
- })
+ Record.new(
+ self.zone,
+ 'sub',
+ {'type': 'DNAME', 'ttl': 600, 'value': 'foo.bar.com.'},
+ )
# A DNAME record can be present at the zone APEX.
- Record.new(self.zone, '', {
- 'type': 'DNAME',
- 'ttl': 600,
- 'value': 'foo.bar.com.',
- })
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'DNAME', 'ttl': 600, 'value': 'foo.bar.com.'},
+ )
# not a valid FQDN
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'DNAME',
- 'ttl': 600,
- 'value': '.',
- })
- self.assertEqual(['DNAME value "." is not a valid FQDN'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone, 'www', {'type': 'DNAME', 'ttl': 600, 'value': '.'}
+ )
+ self.assertEqual(
+ ['DNAME value "." is not a valid FQDN'], ctx.exception.reasons
+ )
# missing trailing .
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'www', {
- 'type': 'DNAME',
- 'ttl': 600,
- 'value': 'foo.bar.com',
- })
- self.assertEqual(['DNAME value "foo.bar.com" missing trailing .'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ 'www',
+ {'type': 'DNAME', 'ttl': 600, 'value': 'foo.bar.com'},
+ )
+ self.assertEqual(
+ ['DNAME value "foo.bar.com" missing trailing .'],
+ ctx.exception.reasons,
+ )
def test_LOC(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_seconds': 52.1,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
-
- # missing int key
- with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
+ Record.new(
+ self.zone,
+ '',
+ {
'type': 'LOC',
'ttl': 600,
'value': {
+ 'lat_degrees': 31,
'lat_minutes': 58,
'lat_seconds': 52.1,
'lat_direction': 'S',
@@ -2486,364 +2557,450 @@ class TestRecordValidation(TestCase):
'size': 10,
'precision_horz': 10,
'precision_vert': 2,
- }
- })
+ },
+ },
+ )
+
+ # missing int key
+ with self.assertRaises(ValidationError) as ctx:
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_minutes': 58,
+ 'lat_seconds': 52.1,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
self.assertEqual(['missing lat_degrees'], ctx.exception.reasons)
# missing float key
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 31,
+ 'lat_minutes': 58,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
self.assertEqual(['missing lat_seconds'], ctx.exception.reasons)
# missing text key
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_seconds': 52.1,
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 31,
+ 'lat_minutes': 58,
+ 'lat_seconds': 52.1,
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
self.assertEqual(['missing lat_direction'], ctx.exception.reasons)
# invalid direction
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_seconds': 52.1,
- 'lat_direction': 'U',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 31,
+ 'lat_minutes': 58,
+ 'lat_seconds': 52.1,
+ 'lat_direction': 'U',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
- self.assertEqual(['invalid direction for lat_direction "U"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['invalid direction for lat_direction "U"'], ctx.exception.reasons
+ )
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_seconds': 52.1,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'N',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 31,
+ 'lat_minutes': 58,
+ 'lat_seconds': 52.1,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'N',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
- self.assertEqual(['invalid direction for long_direction "N"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['invalid direction for long_direction "N"'], ctx.exception.reasons
+ )
# invalid degrees
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 360,
- 'lat_minutes': 58,
- 'lat_seconds': 52.1,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 360,
+ 'lat_minutes': 58,
+ 'lat_seconds': 52.1,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
- self.assertEqual(['invalid value for lat_degrees "360"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['invalid value for lat_degrees "360"'], ctx.exception.reasons
+ )
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 'nope',
- 'lat_minutes': 58,
- 'lat_seconds': 52.1,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 'nope',
+ 'lat_minutes': 58,
+ 'lat_seconds': 52.1,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
- self.assertEqual(['invalid lat_degrees "nope"'],
- ctx.exception.reasons)
+ self.assertEqual(['invalid lat_degrees "nope"'], ctx.exception.reasons)
# invalid minutes
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 31,
- 'lat_minutes': 60,
- 'lat_seconds': 52.1,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 31,
+ 'lat_minutes': 60,
+ 'lat_seconds': 52.1,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
- self.assertEqual(['invalid value for lat_minutes "60"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['invalid value for lat_minutes "60"'], ctx.exception.reasons
+ )
# invalid seconds
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_seconds': 60,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 31,
+ 'lat_minutes': 58,
+ 'lat_seconds': 60,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
- self.assertEqual(['invalid value for lat_seconds "60"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['invalid value for lat_seconds "60"'], ctx.exception.reasons
+ )
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_seconds': 'nope',
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 31,
+ 'lat_minutes': 58,
+ 'lat_seconds': 'nope',
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
- self.assertEqual(['invalid lat_seconds "nope"'],
- ctx.exception.reasons)
+ self.assertEqual(['invalid lat_seconds "nope"'], ctx.exception.reasons)
# invalid altitude
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_seconds': 52.1,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': -666666,
- 'size': 10,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 31,
+ 'lat_minutes': 58,
+ 'lat_seconds': 52.1,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': -666666,
+ 'size': 10,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
- self.assertEqual(['invalid value for altitude "-666666"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['invalid value for altitude "-666666"'], ctx.exception.reasons
+ )
# invalid size
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'LOC',
- 'ttl': 600,
- 'value': {
- 'lat_degrees': 31,
- 'lat_minutes': 58,
- 'lat_seconds': 52.1,
- 'lat_direction': 'S',
- 'long_degrees': 115,
- 'long_minutes': 49,
- 'long_seconds': 11.7,
- 'long_direction': 'E',
- 'altitude': 20,
- 'size': 99999999.99,
- 'precision_horz': 10,
- 'precision_vert': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'LOC',
+ 'ttl': 600,
+ 'value': {
+ 'lat_degrees': 31,
+ 'lat_minutes': 58,
+ 'lat_seconds': 52.1,
+ 'lat_direction': 'S',
+ 'long_degrees': 115,
+ 'long_minutes': 49,
+ 'long_seconds': 11.7,
+ 'long_direction': 'E',
+ 'altitude': 20,
+ 'size': 99999999.99,
+ 'precision_horz': 10,
+ 'precision_vert': 2,
+ },
+ },
+ )
- self.assertEqual(['invalid value for size "99999999.99"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['invalid value for size "99999999.99"'], ctx.exception.reasons
+ )
def test_MX(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'MX',
- 'ttl': 600,
- 'value': {
- 'preference': 10,
- 'exchange': 'foo.bar.com.'
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'MX',
+ 'ttl': 600,
+ 'value': {'preference': 10, 'exchange': 'foo.bar.com.'},
+ },
+ )
# missing preference
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'MX',
- 'ttl': 600,
- 'value': {
- 'exchange': 'foo.bar.com.'
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'MX',
+ 'ttl': 600,
+ 'value': {'exchange': 'foo.bar.com.'},
+ },
+ )
self.assertEqual(['missing preference'], ctx.exception.reasons)
# invalid preference
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'MX',
- 'ttl': 600,
- 'value': {
- 'preference': 'nope',
- 'exchange': 'foo.bar.com.'
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'MX',
+ 'ttl': 600,
+ 'value': {'preference': 'nope', 'exchange': 'foo.bar.com.'},
+ },
+ )
self.assertEqual(['invalid preference "nope"'], ctx.exception.reasons)
# missing exchange
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'MX',
- 'ttl': 600,
- 'value': {
- 'preference': 10,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'MX', 'ttl': 600, 'value': {'preference': 10}},
+ )
self.assertEqual(['missing exchange'], ctx.exception.reasons)
# missing trailing .
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'MX',
- 'ttl': 600,
- 'value': {
- 'preference': 10,
- 'exchange': 'foo.bar.com'
- }
- })
- self.assertEqual(['MX value "foo.bar.com" missing trailing .'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'MX',
+ 'ttl': 600,
+ 'value': {'preference': 10, 'exchange': 'foo.bar.com'},
+ },
+ )
+ self.assertEqual(
+ ['MX value "foo.bar.com" missing trailing .'], ctx.exception.reasons
+ )
# exchange must be a valid FQDN
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'MX',
- 'ttl': 600,
- 'value': {
- 'preference': 10,
- 'exchange': '100 foo.bar.com.'
- }
- })
- self.assertEqual(['Invalid MX exchange "100 foo.bar.com." is not a '
- 'valid FQDN.'], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'MX',
+ 'ttl': 600,
+ 'value': {'preference': 10, 'exchange': '100 foo.bar.com.'},
+ },
+ )
+ self.assertEqual(
+ ['Invalid MX exchange "100 foo.bar.com." is not a ' 'valid FQDN.'],
+ ctx.exception.reasons,
+ )
# exchange can be a single `.`
- record = Record.new(self.zone, '', {
- 'type': 'MX',
- 'ttl': 600,
- 'value': {
- 'preference': 0,
- 'exchange': '.'
- }
- })
+ record = Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'MX',
+ 'ttl': 600,
+ 'value': {'preference': 0, 'exchange': '.'},
+ },
+ )
self.assertEqual('.', record.values[0].exchange)
def test_NXPTR(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'NAPTR',
- 'ttl': 600,
- 'value': {
- 'order': 10,
- 'preference': 20,
- 'flags': 'S',
- 'service': 'srv',
- 'regexp': '.*',
- 'replacement': '.'
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'NAPTR',
+ 'ttl': 600,
+ 'value': {
+ 'order': 10,
+ 'preference': 20,
+ 'flags': 'S',
+ 'service': 'srv',
+ 'regexp': '.*',
+ 'replacement': '.',
+ },
+ },
+ )
# missing X priority
value = {
@@ -2852,692 +3009,830 @@ class TestRecordValidation(TestCase):
'flags': 'S',
'service': 'srv',
'regexp': '.*',
- 'replacement': '.'
+ 'replacement': '.',
}
- for k in ('order', 'preference', 'flags', 'service', 'regexp',
- 'replacement'):
+ for k in (
+ 'order',
+ 'preference',
+ 'flags',
+ 'service',
+ 'regexp',
+ 'replacement',
+ ):
v = dict(value)
del v[k]
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'NAPTR',
- 'ttl': 600,
- 'value': v
- })
+ Record.new(
+ self.zone, '', {'type': 'NAPTR', 'ttl': 600, 'value': v}
+ )
self.assertEqual([f'missing {k}'], ctx.exception.reasons)
# non-int order
v = dict(value)
v['order'] = 'boo'
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'NAPTR',
- 'ttl': 600,
- 'value': v
- })
+ Record.new(self.zone, '', {'type': 'NAPTR', 'ttl': 600, 'value': v})
self.assertEqual(['invalid order "boo"'], ctx.exception.reasons)
# non-int preference
v = dict(value)
v['preference'] = 'who'
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'NAPTR',
- 'ttl': 600,
- 'value': v
- })
+ Record.new(self.zone, '', {'type': 'NAPTR', 'ttl': 600, 'value': v})
self.assertEqual(['invalid preference "who"'], ctx.exception.reasons)
# unrecognized flags
v = dict(value)
v['flags'] = 'X'
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'NAPTR',
- 'ttl': 600,
- 'value': v
- })
+ Record.new(self.zone, '', {'type': 'NAPTR', 'ttl': 600, 'value': v})
self.assertEqual(['unrecognized flags "X"'], ctx.exception.reasons)
def test_NS(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'NS',
- 'ttl': 600,
- 'values': [
- 'foo.bar.com.',
- '1.2.3.4.'
- ]
- })
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'NS', 'ttl': 600, 'values': ['foo.bar.com.', '1.2.3.4.']},
+ )
# missing value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'NS',
- 'ttl': 600,
- })
+ Record.new(self.zone, '', {'type': 'NS', 'ttl': 600})
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# no trailing .
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'NS',
- 'ttl': 600,
- 'value': 'foo.bar',
- })
- self.assertEqual(['NS value "foo.bar" missing trailing .'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone, '', {'type': 'NS', 'ttl': 600, 'value': 'foo.bar'}
+ )
+ self.assertEqual(
+ ['NS value "foo.bar" missing trailing .'], ctx.exception.reasons
+ )
# exchange must be a valid FQDN
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'NS',
- 'ttl': 600,
- 'value': '100 foo.bar.com.'
- })
- self.assertEqual(['Invalid NS value "100 foo.bar.com." is not a '
- 'valid FQDN.'], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {'type': 'NS', 'ttl': 600, 'value': '100 foo.bar.com.'},
+ )
+ self.assertEqual(
+ ['Invalid NS value "100 foo.bar.com." is not a ' 'valid FQDN.'],
+ ctx.exception.reasons,
+ )
def test_PTR(self):
# doesn't blow up (name & zone here don't make any sense, but not
# important)
- Record.new(self.zone, '', {
- 'type': 'PTR',
- 'ttl': 600,
- 'value': 'foo.bar.com.',
- })
+ Record.new(
+ self.zone, '', {'type': 'PTR', 'ttl': 600, 'value': 'foo.bar.com.'}
+ )
# missing value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'PTR',
- 'ttl': 600,
- })
+ Record.new(self.zone, '', {'type': 'PTR', 'ttl': 600})
self.assertEqual(['missing values'], ctx.exception.reasons)
# not a valid FQDN
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'PTR',
- 'ttl': 600,
- 'value': '_.',
- })
- self.assertEqual(['PTR value "_." is not a valid FQDN'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone, '', {'type': 'PTR', 'ttl': 600, 'value': '_.'}
+ )
+ self.assertEqual(
+ ['PTR value "_." is not a valid FQDN'], ctx.exception.reasons
+ )
# no trailing .
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'PTR',
- 'ttl': 600,
- 'value': 'foo.bar',
- })
- self.assertEqual(['PTR value "foo.bar" missing trailing .'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone, '', {'type': 'PTR', 'ttl': 600, 'value': 'foo.bar'}
+ )
+ self.assertEqual(
+ ['PTR value "foo.bar" missing trailing .'], ctx.exception.reasons
+ )
def test_SSHFP(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'SSHFP',
- 'ttl': 600,
- 'value': {
- 'algorithm': 1,
- 'fingerprint_type': 1,
- 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73'
- }
- })
-
- # missing algorithm
- with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
+ Record.new(
+ self.zone,
+ '',
+ {
'type': 'SSHFP',
'ttl': 600,
'value': {
+ 'algorithm': 1,
'fingerprint_type': 1,
- 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73'
- }
- })
+ 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73',
+ },
+ },
+ )
+
+ # missing algorithm
+ with self.assertRaises(ValidationError) as ctx:
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'SSHFP',
+ 'ttl': 600,
+ 'value': {
+ 'fingerprint_type': 1,
+ 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73',
+ },
+ },
+ )
self.assertEqual(['missing algorithm'], ctx.exception.reasons)
# invalid algorithm
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'SSHFP',
- 'ttl': 600,
- 'value': {
- 'algorithm': 'nope',
- 'fingerprint_type': 2,
- 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73'
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'SSHFP',
+ 'ttl': 600,
+ 'value': {
+ 'algorithm': 'nope',
+ 'fingerprint_type': 2,
+ 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73',
+ },
+ },
+ )
self.assertEqual(['invalid algorithm "nope"'], ctx.exception.reasons)
# unrecognized algorithm
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'SSHFP',
- 'ttl': 600,
- 'value': {
- 'algorithm': 42,
- 'fingerprint_type': 1,
- 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73'
- }
- })
- self.assertEqual(['unrecognized algorithm "42"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'SSHFP',
+ 'ttl': 600,
+ 'value': {
+ 'algorithm': 42,
+ 'fingerprint_type': 1,
+ 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73',
+ },
+ },
+ )
+ self.assertEqual(['unrecognized algorithm "42"'], ctx.exception.reasons)
# missing fingerprint_type
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'SSHFP',
- 'ttl': 600,
- 'value': {
- 'algorithm': 2,
- 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73'
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'SSHFP',
+ 'ttl': 600,
+ 'value': {
+ 'algorithm': 2,
+ 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73',
+ },
+ },
+ )
self.assertEqual(['missing fingerprint_type'], ctx.exception.reasons)
# invalid fingerprint_type
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'SSHFP',
- 'ttl': 600,
- 'value': {
- 'algorithm': 3,
- 'fingerprint_type': 'yeeah',
- 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73'
- }
- })
- self.assertEqual(['invalid fingerprint_type "yeeah"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'SSHFP',
+ 'ttl': 600,
+ 'value': {
+ 'algorithm': 3,
+ 'fingerprint_type': 'yeeah',
+ 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73',
+ },
+ },
+ )
+ self.assertEqual(
+ ['invalid fingerprint_type "yeeah"'], ctx.exception.reasons
+ )
# unrecognized fingerprint_type
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'SSHFP',
- 'ttl': 600,
- 'value': {
- 'algorithm': 1,
- 'fingerprint_type': 42,
- 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73'
- }
- })
- self.assertEqual(['unrecognized fingerprint_type "42"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'SSHFP',
+ 'ttl': 600,
+ 'value': {
+ 'algorithm': 1,
+ 'fingerprint_type': 42,
+ 'fingerprint': 'bf6b6825d2977c511a475bbefb88aad54a92ac73',
+ },
+ },
+ )
+ self.assertEqual(
+ ['unrecognized fingerprint_type "42"'], ctx.exception.reasons
+ )
# missing fingerprint
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'SSHFP',
- 'ttl': 600,
- 'value': {
- 'algorithm': 1,
- 'fingerprint_type': 1,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'SSHFP',
+ 'ttl': 600,
+ 'value': {'algorithm': 1, 'fingerprint_type': 1},
+ },
+ )
self.assertEqual(['missing fingerprint'], ctx.exception.reasons)
def test_SPF(self):
# doesn't blow up (name & zone here don't make any sense, but not
# important)
- Record.new(self.zone, '', {
- 'type': 'SPF',
- 'ttl': 600,
- 'values': [
- 'v=spf1 ip4:192.168.0.1/16-all',
- 'v=spf1 ip4:10.1.2.1/24-all',
- 'this has some\\; semi-colons\\; in it',
- ]
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'SPF',
+ 'ttl': 600,
+ 'values': [
+ 'v=spf1 ip4:192.168.0.1/16-all',
+ 'v=spf1 ip4:10.1.2.1/24-all',
+ 'this has some\\; semi-colons\\; in it',
+ ],
+ },
+ )
# missing value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'SPF',
- 'ttl': 600,
- })
+ Record.new(self.zone, '', {'type': 'SPF', 'ttl': 600})
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# missing escapes
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'SPF',
- 'ttl': 600,
- 'value': 'this has some; semi-colons\\; in it',
- })
- self.assertEqual(['unescaped ; in "this has some; '
- 'semi-colons\\; in it"'], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'SPF',
+ 'ttl': 600,
+ 'value': 'this has some; semi-colons\\; in it',
+ },
+ )
+ self.assertEqual(
+ ['unescaped ; in "this has some; ' 'semi-colons\\; in it"'],
+ ctx.exception.reasons,
+ )
def test_SRV(self):
# doesn't blow up
- Record.new(self.zone, '_srv._tcp', {
- 'type': 'SRV',
- 'ttl': 600,
- 'value': {
- 'priority': 1,
- 'weight': 2,
- 'port': 3,
- 'target': 'foo.bar.baz.'
- }
- })
-
- # permit wildcard entries
- Record.new(self.zone, '*._tcp', {
- 'type': 'SRV',
- 'ttl': 600,
- 'value': {
- 'priority': 1,
- 'weight': 2,
- 'port': 3,
- 'target': 'food.bar.baz.'
- }
- })
-
- # invalid name
- with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, 'neup', {
+ Record.new(
+ self.zone,
+ '_srv._tcp',
+ {
'type': 'SRV',
'ttl': 600,
'value': {
'priority': 1,
'weight': 2,
'port': 3,
- 'target': 'foo.bar.baz.'
- }
- })
- self.assertEqual(['invalid name for SRV record'],
- ctx.exception.reasons)
+ 'target': 'foo.bar.baz.',
+ },
+ },
+ )
- # missing priority
- with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '_srv._tcp', {
+ # permit wildcard entries
+ Record.new(
+ self.zone,
+ '*._tcp',
+ {
'type': 'SRV',
'ttl': 600,
'value': {
+ 'priority': 1,
'weight': 2,
'port': 3,
- 'target': 'foo.bar.baz.'
- }
- })
+ 'target': 'food.bar.baz.',
+ },
+ },
+ )
+
+ # invalid name
+ with self.assertRaises(ValidationError) as ctx:
+ Record.new(
+ self.zone,
+ 'neup',
+ {
+ 'type': 'SRV',
+ 'ttl': 600,
+ 'value': {
+ 'priority': 1,
+ 'weight': 2,
+ 'port': 3,
+ 'target': 'foo.bar.baz.',
+ },
+ },
+ )
+ self.assertEqual(['invalid name for SRV record'], ctx.exception.reasons)
+
+ # missing priority
+ with self.assertRaises(ValidationError) as ctx:
+ Record.new(
+ self.zone,
+ '_srv._tcp',
+ {
+ 'type': 'SRV',
+ 'ttl': 600,
+ 'value': {'weight': 2, 'port': 3, 'target': 'foo.bar.baz.'},
+ },
+ )
self.assertEqual(['missing priority'], ctx.exception.reasons)
# invalid priority
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '_srv._tcp', {
- 'type': 'SRV',
- 'ttl': 600,
- 'value': {
- 'priority': 'foo',
- 'weight': 2,
- 'port': 3,
- 'target': 'foo.bar.baz.'
- }
- })
+ Record.new(
+ self.zone,
+ '_srv._tcp',
+ {
+ 'type': 'SRV',
+ 'ttl': 600,
+ 'value': {
+ 'priority': 'foo',
+ 'weight': 2,
+ 'port': 3,
+ 'target': 'foo.bar.baz.',
+ },
+ },
+ )
self.assertEqual(['invalid priority "foo"'], ctx.exception.reasons)
# missing weight
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '_srv._tcp', {
- 'type': 'SRV',
- 'ttl': 600,
- 'value': {
- 'priority': 1,
- 'port': 3,
- 'target': 'foo.bar.baz.'
- }
- })
+ Record.new(
+ self.zone,
+ '_srv._tcp',
+ {
+ 'type': 'SRV',
+ 'ttl': 600,
+ 'value': {
+ 'priority': 1,
+ 'port': 3,
+ 'target': 'foo.bar.baz.',
+ },
+ },
+ )
self.assertEqual(['missing weight'], ctx.exception.reasons)
# invalid weight
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '_srv._tcp', {
- 'type': 'SRV',
- 'ttl': 600,
- 'value': {
- 'priority': 1,
- 'weight': 'foo',
- 'port': 3,
- 'target': 'foo.bar.baz.'
- }
- })
+ Record.new(
+ self.zone,
+ '_srv._tcp',
+ {
+ 'type': 'SRV',
+ 'ttl': 600,
+ 'value': {
+ 'priority': 1,
+ 'weight': 'foo',
+ 'port': 3,
+ 'target': 'foo.bar.baz.',
+ },
+ },
+ )
self.assertEqual(['invalid weight "foo"'], ctx.exception.reasons)
# missing port
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '_srv._tcp', {
- 'type': 'SRV',
- 'ttl': 600,
- 'value': {
- 'priority': 1,
- 'weight': 2,
- 'target': 'foo.bar.baz.'
- }
- })
+ Record.new(
+ self.zone,
+ '_srv._tcp',
+ {
+ 'type': 'SRV',
+ 'ttl': 600,
+ 'value': {
+ 'priority': 1,
+ 'weight': 2,
+ 'target': 'foo.bar.baz.',
+ },
+ },
+ )
self.assertEqual(['missing port'], ctx.exception.reasons)
# invalid port
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '_srv._tcp', {
- 'type': 'SRV',
- 'ttl': 600,
- 'value': {
- 'priority': 1,
- 'weight': 2,
- 'port': 'foo',
- 'target': 'foo.bar.baz.'
- }
- })
+ Record.new(
+ self.zone,
+ '_srv._tcp',
+ {
+ 'type': 'SRV',
+ 'ttl': 600,
+ 'value': {
+ 'priority': 1,
+ 'weight': 2,
+ 'port': 'foo',
+ 'target': 'foo.bar.baz.',
+ },
+ },
+ )
self.assertEqual(['invalid port "foo"'], ctx.exception.reasons)
# missing target
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '_srv._tcp', {
- 'type': 'SRV',
- 'ttl': 600,
- 'value': {
- 'priority': 1,
- 'weight': 2,
- 'port': 3,
- }
- })
+ Record.new(
+ self.zone,
+ '_srv._tcp',
+ {
+ 'type': 'SRV',
+ 'ttl': 600,
+ 'value': {'priority': 1, 'weight': 2, 'port': 3},
+ },
+ )
self.assertEqual(['missing target'], ctx.exception.reasons)
# invalid target
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '_srv._tcp', {
- 'type': 'SRV',
- 'ttl': 600,
- 'value': {
- 'priority': 1,
- 'weight': 2,
- 'port': 3,
- 'target': 'foo.bar.baz'
- }
- })
- self.assertEqual(['SRV value "foo.bar.baz" missing trailing .'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '_srv._tcp',
+ {
+ 'type': 'SRV',
+ 'ttl': 600,
+ 'value': {
+ 'priority': 1,
+ 'weight': 2,
+ 'port': 3,
+ 'target': 'foo.bar.baz',
+ },
+ },
+ )
+ self.assertEqual(
+ ['SRV value "foo.bar.baz" missing trailing .'],
+ ctx.exception.reasons,
+ )
# target must be a valid FQDN
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '_srv._tcp', {
- 'type': 'SRV',
- 'ttl': 600,
- 'value': {
- 'priority': 1,
- 'weight': 2,
- 'port': 3,
- 'target': '100 foo.bar.com.'
- }
- })
- self.assertEqual(['Invalid SRV target "100 foo.bar.com." is not a '
- 'valid FQDN.'], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '_srv._tcp',
+ {
+ 'type': 'SRV',
+ 'ttl': 600,
+ 'value': {
+ 'priority': 1,
+ 'weight': 2,
+ 'port': 3,
+ 'target': '100 foo.bar.com.',
+ },
+ },
+ )
+ self.assertEqual(
+ ['Invalid SRV target "100 foo.bar.com." is not a ' 'valid FQDN.'],
+ ctx.exception.reasons,
+ )
def test_TLSA(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'certificate_usage': 0,
- 'selector': 0,
- 'matching_type': 0,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- })
- # Multi value, second missing certificate usage
- with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
+ Record.new(
+ self.zone,
+ '',
+ {
'type': 'TLSA',
'ttl': 600,
- 'values': [{
+ 'value': {
'certificate_usage': 0,
'selector': 0,
'matching_type': 0,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }, {
- 'selector': 0,
- 'matching_type': 0,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- ]
- })
- self.assertEqual(['missing certificate_usage'],
- ctx.exception.reasons)
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ },
+ )
+ # Multi value, second missing certificate usage
+ with self.assertRaises(ValidationError) as ctx:
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'values': [
+ {
+ 'certificate_usage': 0,
+ 'selector': 0,
+ 'matching_type': 0,
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ {
+ 'selector': 0,
+ 'matching_type': 0,
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ ],
+ },
+ )
+ self.assertEqual(
+ ['missing certificate_usage'], ctx.exception.reasons
+ )
# missing certificate_association_data
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'certificate_usage': 0,
- 'selector': 0,
- 'matching_type': 0
- }
- })
- self.assertEqual(['missing certificate_association_data'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'value': {
+ 'certificate_usage': 0,
+ 'selector': 0,
+ 'matching_type': 0,
+ },
+ },
+ )
+ self.assertEqual(
+ ['missing certificate_association_data'], ctx.exception.reasons
+ )
# missing certificate_usage
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'selector': 0,
- 'matching_type': 0,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- })
- self.assertEqual(['missing certificate_usage'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'value': {
+ 'selector': 0,
+ 'matching_type': 0,
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ },
+ )
+ self.assertEqual(
+ ['missing certificate_usage'], ctx.exception.reasons
+ )
# False certificate_usage
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'certificate_usage': 4,
- 'selector': 0,
- 'matching_type': 0,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- })
- self.assertEqual('invalid certificate_usage '
- '"{value["certificate_usage"]}"',
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'value': {
+ 'certificate_usage': 4,
+ 'selector': 0,
+ 'matching_type': 0,
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ },
+ )
+ self.assertEqual(
+ 'invalid certificate_usage ' '"{value["certificate_usage"]}"',
+ ctx.exception.reasons,
+ )
# Invalid certificate_usage
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'certificate_usage': 'XYZ',
- 'selector': 0,
- 'matching_type': 0,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- })
- self.assertEqual('invalid certificate_usage '
- '"{value["certificate_usage"]}"',
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'value': {
+ 'certificate_usage': 'XYZ',
+ 'selector': 0,
+ 'matching_type': 0,
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ },
+ )
+ self.assertEqual(
+ 'invalid certificate_usage ' '"{value["certificate_usage"]}"',
+ ctx.exception.reasons,
+ )
# missing selector
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'certificate_usage': 0,
- 'matching_type': 0,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- })
- self.assertEqual(['missing selector'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'value': {
+ 'certificate_usage': 0,
+ 'matching_type': 0,
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ },
+ )
+ self.assertEqual(['missing selector'], ctx.exception.reasons)
# False selector
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'certificate_usage': 0,
- 'selector': 4,
- 'matching_type': 0,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- })
- self.assertEqual('invalid selector '
- '"{value["selector"]}"',
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'value': {
+ 'certificate_usage': 0,
+ 'selector': 4,
+ 'matching_type': 0,
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ },
+ )
+ self.assertEqual(
+ 'invalid selector ' '"{value["selector"]}"',
+ ctx.exception.reasons,
+ )
# Invalid selector
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'certificate_usage': 0,
- 'selector': 'XYZ',
- 'matching_type': 0,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- })
- self.assertEqual('invalid selector '
- '"{value["selector"]}"',
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'value': {
+ 'certificate_usage': 0,
+ 'selector': 'XYZ',
+ 'matching_type': 0,
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ },
+ )
+ self.assertEqual(
+ 'invalid selector ' '"{value["selector"]}"',
+ ctx.exception.reasons,
+ )
# missing matching_type
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'certificate_usage': 0,
- 'selector': 0,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- })
- self.assertEqual(['missing matching_type'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'value': {
+ 'certificate_usage': 0,
+ 'selector': 0,
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ },
+ )
+ self.assertEqual(['missing matching_type'], ctx.exception.reasons)
# False matching_type
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'certificate_usage': 0,
- 'selector': 1,
- 'matching_type': 3,
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- })
- self.assertEqual('invalid matching_type '
- '"{value["matching_type"]}"',
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'value': {
+ 'certificate_usage': 0,
+ 'selector': 1,
+ 'matching_type': 3,
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ },
+ )
+ self.assertEqual(
+ 'invalid matching_type ' '"{value["matching_type"]}"',
+ ctx.exception.reasons,
+ )
# Invalid matching_type
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TLSA',
- 'ttl': 600,
- 'value': {
- 'certificate_usage': 0,
- 'selector': 1,
- 'matching_type': 'XYZ',
- 'certificate_association_data': 'AAAAAAAAAAAAA'
- }
- })
- self.assertEqual('invalid matching_type '
- '"{value["matching_type"]}"',
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TLSA',
+ 'ttl': 600,
+ 'value': {
+ 'certificate_usage': 0,
+ 'selector': 1,
+ 'matching_type': 'XYZ',
+ 'certificate_association_data': 'AAAAAAAAAAAAA',
+ },
+ },
+ )
+ self.assertEqual(
+ 'invalid matching_type ' '"{value["matching_type"]}"',
+ ctx.exception.reasons,
+ )
def test_TXT(self):
# doesn't blow up (name & zone here don't make any sense, but not
# important)
- Record.new(self.zone, '', {
- 'type': 'TXT',
- 'ttl': 600,
- 'values': [
- 'hello world',
- 'this has some\\; semi-colons\\; in it',
- ]
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TXT',
+ 'ttl': 600,
+ 'values': [
+ 'hello world',
+ 'this has some\\; semi-colons\\; in it',
+ ],
+ },
+ )
# missing value
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TXT',
- 'ttl': 600,
- })
+ Record.new(self.zone, '', {'type': 'TXT', 'ttl': 600})
self.assertEqual(['missing value(s)'], ctx.exception.reasons)
# missing escapes
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'TXT',
- 'ttl': 600,
- 'value': 'this has some; semi-colons\\; in it',
- })
- self.assertEqual(['unescaped ; in "this has some; semi-colons\\; '
- 'in it"'], ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TXT',
+ 'ttl': 600,
+ 'value': 'this has some; semi-colons\\; in it',
+ },
+ )
+ self.assertEqual(
+ ['unescaped ; in "this has some; semi-colons\\; ' 'in it"'],
+ ctx.exception.reasons,
+ )
def test_TXT_long_value_chunking(self):
- expected = '"Lorem ipsum dolor sit amet, consectetur adipiscing ' \
- 'elit, sed do eiusmod tempor incididunt ut labore et dolore ' \
- 'magna aliqua. Ut enim ad minim veniam, quis nostrud ' \
- 'exercitation ullamco laboris nisi ut aliquip ex ea commodo ' \
- 'consequat. Duis aute irure dolor i" "n reprehenderit in ' \
- 'voluptate velit esse cillum dolore eu fugiat nulla pariatur. ' \
- 'Excepteur sint occaecat cupidatat non proident, sunt in culpa ' \
+ expected = (
+ '"Lorem ipsum dolor sit amet, consectetur adipiscing '
+ 'elit, sed do eiusmod tempor incididunt ut labore et dolore '
+ 'magna aliqua. Ut enim ad minim veniam, quis nostrud '
+ 'exercitation ullamco laboris nisi ut aliquip ex ea commodo '
+ 'consequat. Duis aute irure dolor i" "n reprehenderit in '
+ 'voluptate velit esse cillum dolore eu fugiat nulla pariatur. '
+ 'Excepteur sint occaecat cupidatat non proident, sunt in culpa '
'qui officia deserunt mollit anim id est laborum."'
+ )
- long_value = 'Lorem ipsum dolor sit amet, consectetur adipiscing ' \
- 'elit, sed do eiusmod tempor incididunt ut labore et dolore ' \
- 'magna aliqua. Ut enim ad minim veniam, quis nostrud ' \
- 'exercitation ullamco laboris nisi ut aliquip ex ea commodo ' \
- 'consequat. Duis aute irure dolor in reprehenderit in ' \
- 'voluptate velit esse cillum dolore eu fugiat nulla ' \
- 'pariatur. Excepteur sint occaecat cupidatat non proident, ' \
- 'sunt in culpa qui officia deserunt mollit anim id est ' \
+ long_value = (
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing '
+ 'elit, sed do eiusmod tempor incididunt ut labore et dolore '
+ 'magna aliqua. Ut enim ad minim veniam, quis nostrud '
+ 'exercitation ullamco laboris nisi ut aliquip ex ea commodo '
+ 'consequat. Duis aute irure dolor in reprehenderit in '
+ 'voluptate velit esse cillum dolore eu fugiat nulla '
+ 'pariatur. Excepteur sint occaecat cupidatat non proident, '
+ 'sunt in culpa qui officia deserunt mollit anim id est '
'laborum.'
+ )
# Single string
- single = Record.new(self.zone, '', {
- 'type': 'TXT',
- 'ttl': 600,
- 'values': [
- 'hello world',
- long_value,
- 'this has some\\; semi-colons\\; in it',
- ]
- })
+ single = Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TXT',
+ 'ttl': 600,
+ 'values': [
+ 'hello world',
+ long_value,
+ 'this has some\\; semi-colons\\; in it',
+ ],
+ },
+ )
self.assertEqual(3, len(single.values))
self.assertEqual(3, len(single.chunked_values))
# Note we are checking that this normalizes the chunking, not that we
# get out what we put in.
self.assertEqual(expected, single.chunked_values[0])
- long_split_value = '"Lorem ipsum dolor sit amet, consectetur ' \
- 'adipiscing elit, sed do eiusmod tempor incididunt ut ' \
- 'labore et dolore magna aliqua. Ut enim ad minim veniam, ' \
- 'quis nostrud exercitation ullamco laboris nisi ut aliquip ' \
- 'ex" " ea commodo consequat. Duis aute irure dolor in ' \
- 'reprehenderit in voluptate velit esse cillum dolore eu ' \
- 'fugiat nulla pariatur. Excepteur sint occaecat cupidatat ' \
- 'non proident, sunt in culpa qui officia deserunt mollit ' \
+ long_split_value = (
+ '"Lorem ipsum dolor sit amet, consectetur '
+ 'adipiscing elit, sed do eiusmod tempor incididunt ut '
+ 'labore et dolore magna aliqua. Ut enim ad minim veniam, '
+ 'quis nostrud exercitation ullamco laboris nisi ut aliquip '
+ 'ex" " ea commodo consequat. Duis aute irure dolor in '
+ 'reprehenderit in voluptate velit esse cillum dolore eu '
+ 'fugiat nulla pariatur. Excepteur sint occaecat cupidatat '
+ 'non proident, sunt in culpa qui officia deserunt mollit '
'anim id est laborum."'
+ )
# Chunked
- chunked = Record.new(self.zone, '', {
- 'type': 'TXT',
- 'ttl': 600,
- 'values': [
- '"hello world"',
- long_split_value,
- '"this has some\\; semi-colons\\; in it"',
- ]
- })
+ chunked = Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'TXT',
+ 'ttl': 600,
+ 'values': [
+ '"hello world"',
+ long_split_value,
+ '"this has some\\; semi-colons\\; in it"',
+ ],
+ },
+ )
self.assertEqual(expected, chunked.chunked_values[0])
# should be single values, no quoting
self.assertEqual(single.values, chunked.values)
@@ -3546,200 +3841,259 @@ class TestRecordValidation(TestCase):
def test_URLFWD(self):
# doesn't blow up
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'target': 'http://foo',
- 'code': 301,
- 'masking': 2,
- 'query': 0,
- }
- })
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'values': [{
- 'path': '/',
- 'target': 'http://foo',
- 'code': 301,
- 'masking': 2,
- 'query': 0,
- }, {
- 'path': '/target',
- 'target': 'http://target',
- 'code': 302,
- 'masking': 2,
- 'query': 0,
- }]
- })
-
- # missing path
- with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
+ Record.new(
+ self.zone,
+ '',
+ {
'type': 'URLFWD',
'ttl': 600,
'value': {
+ 'path': '/',
'target': 'http://foo',
'code': 301,
'masking': 2,
'query': 0,
- }
- })
+ },
+ },
+ )
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'values': [
+ {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'code': 301,
+ 'masking': 2,
+ 'query': 0,
+ },
+ {
+ 'path': '/target',
+ 'target': 'http://target',
+ 'code': 302,
+ 'masking': 2,
+ 'query': 0,
+ },
+ ],
+ },
+ )
+
+ # missing path
+ with self.assertRaises(ValidationError) as ctx:
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'target': 'http://foo',
+ 'code': 301,
+ 'masking': 2,
+ 'query': 0,
+ },
+ },
+ )
self.assertEqual(['missing path'], ctx.exception.reasons)
# missing target
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'code': 301,
- 'masking': 2,
- 'query': 0,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'path': '/',
+ 'code': 301,
+ 'masking': 2,
+ 'query': 0,
+ },
+ },
+ )
self.assertEqual(['missing target'], ctx.exception.reasons)
# missing code
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'target': 'http://foo',
- 'masking': 2,
- 'query': 0,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'masking': 2,
+ 'query': 0,
+ },
+ },
+ )
self.assertEqual(['missing code'], ctx.exception.reasons)
# invalid code
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'target': 'http://foo',
- 'code': 'nope',
- 'masking': 2,
- 'query': 0,
- }
- })
- self.assertEqual(['invalid return code "nope"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'code': 'nope',
+ 'masking': 2,
+ 'query': 0,
+ },
+ },
+ )
+ self.assertEqual(['invalid return code "nope"'], ctx.exception.reasons)
# unrecognized code
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'target': 'http://foo',
- 'code': 3,
- 'masking': 2,
- 'query': 0,
- }
- })
- self.assertEqual(['unrecognized return code "3"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'code': 3,
+ 'masking': 2,
+ 'query': 0,
+ },
+ },
+ )
+ self.assertEqual(
+ ['unrecognized return code "3"'], ctx.exception.reasons
+ )
# missing masking
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'target': 'http://foo',
- 'code': 301,
- 'query': 0,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'code': 301,
+ 'query': 0,
+ },
+ },
+ )
self.assertEqual(['missing masking'], ctx.exception.reasons)
# invalid masking
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'target': 'http://foo',
- 'code': 301,
- 'masking': 'nope',
- 'query': 0,
- }
- })
- self.assertEqual(['invalid masking setting "nope"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'code': 301,
+ 'masking': 'nope',
+ 'query': 0,
+ },
+ },
+ )
+ self.assertEqual(
+ ['invalid masking setting "nope"'], ctx.exception.reasons
+ )
# unrecognized masking
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'target': 'http://foo',
- 'code': 301,
- 'masking': 3,
- 'query': 0,
- }
- })
- self.assertEqual(['unrecognized masking setting "3"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'code': 301,
+ 'masking': 3,
+ 'query': 0,
+ },
+ },
+ )
+ self.assertEqual(
+ ['unrecognized masking setting "3"'], ctx.exception.reasons
+ )
# missing query
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'target': 'http://foo',
- 'code': 301,
- 'masking': 2,
- }
- })
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'code': 301,
+ 'masking': 2,
+ },
+ },
+ )
self.assertEqual(['missing query'], ctx.exception.reasons)
# invalid query
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'target': 'http://foo',
- 'code': 301,
- 'masking': 2,
- 'query': 'nope',
- }
- })
- self.assertEqual(['invalid query setting "nope"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'code': 301,
+ 'masking': 2,
+ 'query': 'nope',
+ },
+ },
+ )
+ self.assertEqual(
+ ['invalid query setting "nope"'], ctx.exception.reasons
+ )
# unrecognized query
with self.assertRaises(ValidationError) as ctx:
- Record.new(self.zone, '', {
- 'type': 'URLFWD',
- 'ttl': 600,
- 'value': {
- 'path': '/',
- 'target': 'http://foo',
- 'code': 301,
- 'masking': 2,
- 'query': 3,
- }
- })
- self.assertEqual(['unrecognized query setting "3"'],
- ctx.exception.reasons)
+ Record.new(
+ self.zone,
+ '',
+ {
+ 'type': 'URLFWD',
+ 'ttl': 600,
+ 'value': {
+ 'path': '/',
+ 'target': 'http://foo',
+ 'code': 301,
+ 'masking': 2,
+ 'query': 3,
+ },
+ },
+ )
+ self.assertEqual(
+ ['unrecognized query setting "3"'], ctx.exception.reasons
+ )
class TestDynamicRecords(TestCase):
@@ -3749,45 +4103,26 @@ class TestDynamicRecords(TestCase):
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'weight': 10,
- 'value': '3.3.3.3',
- }],
- },
+ 'one': {'values': [{'weight': 10, 'value': '3.3.3.3'}]},
'two': {
# Testing out of order value sorting here
- 'values': [{
- 'value': '5.5.5.5',
- }, {
- 'value': '4.4.4.4',
- }],
+ 'values': [{'value': '5.5.5.5'}, {'value': '4.4.4.4'}]
},
'three': {
- 'values': [{
- 'weight': 10,
- 'value': '4.4.4.4',
- }, {
- 'weight': 12,
- 'value': '5.5.5.5',
- }],
+ 'values': [
+ {'weight': 10, 'value': '4.4.4.4'},
+ {'weight': 12, 'value': '5.5.5.5'},
+ ]
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
a = ARecord(self.zone, 'weighted', a_data)
self.assertEqual('A', a._type)
@@ -3799,29 +4134,24 @@ class TestDynamicRecords(TestCase):
pools = dynamic.pools
self.assertTrue(pools)
- self.assertEqual({
- 'value': '3.3.3.3',
- 'weight': 1,
- 'status': 'obey',
- }, pools['one'].data['values'][0])
- self.assertEqual([{
- 'value': '4.4.4.4',
- 'weight': 1,
- 'status': 'obey',
- }, {
- 'value': '5.5.5.5',
- 'weight': 1,
- 'status': 'obey',
- }], pools['two'].data['values'])
- self.assertEqual([{
- 'weight': 10,
- 'value': '4.4.4.4',
- 'status': 'obey',
- }, {
- 'weight': 12,
- 'value': '5.5.5.5',
- 'status': 'obey',
- }], pools['three'].data['values'])
+ self.assertEqual(
+ {'value': '3.3.3.3', 'weight': 1, 'status': 'obey'},
+ pools['one'].data['values'][0],
+ )
+ self.assertEqual(
+ [
+ {'value': '4.4.4.4', 'weight': 1, 'status': 'obey'},
+ {'value': '5.5.5.5', 'weight': 1, 'status': 'obey'},
+ ],
+ pools['two'].data['values'],
+ )
+ self.assertEqual(
+ [
+ {'weight': 10, 'value': '4.4.4.4', 'status': 'obey'},
+ {'weight': 12, 'value': '5.5.5.5', 'status': 'obey'},
+ ],
+ pools['three'].data['values'],
+ )
rules = dynamic.rules
self.assertTrue(rules)
@@ -3847,13 +4177,7 @@ class TestDynamicRecords(TestCase):
2: '2601:642:500:e210:62f8:1dff:feb8:9477',
},
},
- 'rules': [{
- 'pools': [
- 'three',
- 'two',
- 'one',
- ],
- }],
+ 'rules': [{'pools': ['three', 'two', 'one']}],
},
'ttl': 60,
'values': [
@@ -3865,37 +4189,35 @@ class TestDynamicRecords(TestCase):
'dynamic': {
'pools': {
'one': {
- 'values': [{
- 'value': '2601:642:500:e210:62f8:1dff:feb8:9473',
- }],
+ 'values': [
+ {'value': '2601:642:500:e210:62f8:1dff:feb8:9473'}
+ ]
},
'two': {
# Testing out of order value sorting here
- 'values': [{
- 'value': '2601:642:500:e210:62f8:1dff:feb8:9475',
- }, {
- 'value': '2601:642:500:e210:62f8:1dff:feb8:9474',
- }],
+ 'values': [
+ {'value': '2601:642:500:e210:62f8:1dff:feb8:9475'},
+ {'value': '2601:642:500:e210:62f8:1dff:feb8:9474'},
+ ]
},
'three': {
- 'values': [{
- 'weight': 10,
- 'value': '2601:642:500:e210:62f8:1dff:feb8:9476',
- }, {
- 'weight': 12,
- 'value': '2601:642:500:e210:62f8:1dff:feb8:9477',
- }],
+ 'values': [
+ {
+ 'weight': 10,
+ 'value': '2601:642:500:e210:62f8:1dff:feb8:9476',
+ },
+ {
+ 'weight': 12,
+ 'value': '2601:642:500:e210:62f8:1dff:feb8:9477',
+ },
+ ]
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'values': [
@@ -3913,29 +4235,44 @@ class TestDynamicRecords(TestCase):
pools = dynamic.pools
self.assertTrue(pools)
- self.assertEqual({
- 'value': '2601:642:500:e210:62f8:1dff:feb8:9473',
- 'weight': 1,
- 'status': 'obey',
- }, pools['one'].data['values'][0])
- self.assertEqual([{
- 'value': '2601:642:500:e210:62f8:1dff:feb8:9474',
- 'weight': 1,
- 'status': 'obey',
- }, {
- 'value': '2601:642:500:e210:62f8:1dff:feb8:9475',
- 'weight': 1,
- 'status': 'obey',
- }], pools['two'].data['values'])
- self.assertEqual([{
- 'weight': 10,
- 'value': '2601:642:500:e210:62f8:1dff:feb8:9476',
- 'status': 'obey',
- }, {
- 'weight': 12,
- 'value': '2601:642:500:e210:62f8:1dff:feb8:9477',
- 'status': 'obey',
- }], pools['three'].data['values'])
+ self.assertEqual(
+ {
+ 'value': '2601:642:500:e210:62f8:1dff:feb8:9473',
+ 'weight': 1,
+ 'status': 'obey',
+ },
+ pools['one'].data['values'][0],
+ )
+ self.assertEqual(
+ [
+ {
+ 'value': '2601:642:500:e210:62f8:1dff:feb8:9474',
+ 'weight': 1,
+ 'status': 'obey',
+ },
+ {
+ 'value': '2601:642:500:e210:62f8:1dff:feb8:9475',
+ 'weight': 1,
+ 'status': 'obey',
+ },
+ ],
+ pools['two'].data['values'],
+ )
+ self.assertEqual(
+ [
+ {
+ 'weight': 10,
+ 'value': '2601:642:500:e210:62f8:1dff:feb8:9476',
+ 'status': 'obey',
+ },
+ {
+ 'weight': 12,
+ 'value': '2601:642:500:e210:62f8:1dff:feb8:9477',
+ 'status': 'obey',
+ },
+ ],
+ pools['three'].data['values'],
+ )
rules = dynamic.rules
self.assertTrue(rules)
@@ -3945,35 +4282,20 @@ class TestDynamicRecords(TestCase):
cname_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': 'one.cname.target.',
- }],
- },
- 'two': {
- 'values': [{
- 'value': 'two.cname.target.',
- }],
- },
+ 'one': {'values': [{'value': 'one.cname.target.'}]},
+ 'two': {'values': [{'value': 'two.cname.target.'}]},
'three': {
- 'values': [{
- 'weight': 12,
- 'value': 'three-1.cname.target.',
- }, {
- 'weight': 32,
- 'value': 'three-2.cname.target.',
- }]
+ 'values': [
+ {'weight': 12, 'value': 'three-1.cname.target.'},
+ {'weight': 32, 'value': 'three-2.cname.target.'},
+ ]
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'value': 'cname.target.',
@@ -3988,25 +4310,29 @@ class TestDynamicRecords(TestCase):
pools = dynamic.pools
self.assertTrue(pools)
- self.assertEqual({
- 'value': 'one.cname.target.',
- 'weight': 1,
- 'status': 'obey',
- }, pools['one'].data['values'][0])
- self.assertEqual({
- 'value': 'two.cname.target.',
- 'weight': 1,
- 'status': 'obey',
- }, pools['two'].data['values'][0])
- self.assertEqual([{
- 'value': 'three-1.cname.target.',
- 'weight': 12,
- 'status': 'obey',
- }, {
- 'value': 'three-2.cname.target.',
- 'weight': 32,
- 'status': 'obey',
- }], pools['three'].data['values'])
+ self.assertEqual(
+ {'value': 'one.cname.target.', 'weight': 1, 'status': 'obey'},
+ pools['one'].data['values'][0],
+ )
+ self.assertEqual(
+ {'value': 'two.cname.target.', 'weight': 1, 'status': 'obey'},
+ pools['two'].data['values'][0],
+ )
+ self.assertEqual(
+ [
+ {
+ 'value': 'three-1.cname.target.',
+ 'weight': 12,
+ 'status': 'obey',
+ },
+ {
+ 'value': 'three-2.cname.target.',
+ 'weight': 32,
+ 'status': 'obey',
+ },
+ ],
+ pools['three'].data['values'],
+ )
rules = dynamic.rules
self.assertTrue(rules)
@@ -4015,117 +4341,86 @@ class TestDynamicRecords(TestCase):
def test_dynamic_validation(self):
# Missing pools
a_data = {
- 'dynamic': {
- 'rules': [{
- 'pool': 'one',
- }],
- },
+ 'dynamic': {'rules': [{'pool': 'one'}]},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['missing pools', 'rule 1 undefined pool "one"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['missing pools', 'rule 1 undefined pool "one"'],
+ ctx.exception.reasons,
+ )
# Empty pools
a_data = {
- 'dynamic': {
- 'pools': {
- },
- 'rules': [{
- 'pool': 'one',
- }],
- },
+ 'dynamic': {'pools': {}, 'rules': [{'pool': 'one'}]},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['missing pools', 'rule 1 undefined pool "one"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['missing pools', 'rule 1 undefined pool "one"'],
+ ctx.exception.reasons,
+ )
# pools not a dict
a_data = {
- 'dynamic': {
- 'pools': [],
- 'rules': [{
- 'pool': 'one',
- }],
- },
+ 'dynamic': {'pools': [], 'rules': [{'pool': 'one'}]},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['pools must be a dict',
- 'rule 1 undefined pool "one"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['pools must be a dict', 'rule 1 undefined pool "one"'],
+ ctx.exception.reasons,
+ )
# Invalid addresses
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': 'this-aint-right',
- }],
- },
+ 'one': {'values': [{'value': 'this-aint-right'}]},
'two': {
'fallback': 'one',
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': 'nor-is-this',
- }]
+ 'values': [
+ {'value': '4.4.4.4'},
+ {'value': 'nor-is-this'},
+ ],
},
'three': {
'fallback': 'two',
- 'values': [{
- 'weight': 1,
- 'value': '5.5.5.5',
- }, {
- 'weight': 2,
- 'value': 'yet-another-bad-one',
- }],
+ 'values': [
+ {'weight': 1, 'value': '5.5.5.5'},
+ {'weight': 2, 'value': 'yet-another-bad-one'},
+ ],
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual([
- 'invalid IPv4 address "this-aint-right"',
- 'invalid IPv4 address "yet-another-bad-one"',
- 'invalid IPv4 address "nor-is-this"',
- ], ctx.exception.reasons)
+ self.assertEqual(
+ [
+ 'invalid IPv4 address "this-aint-right"',
+ 'invalid IPv4 address "yet-another-bad-one"',
+ 'invalid IPv4 address "nor-is-this"',
+ ],
+ ctx.exception.reasons,
+ )
# missing value(s)
a_data = {
@@ -4133,43 +4428,30 @@ class TestDynamicRecords(TestCase):
'pools': {
'one': {},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
'three': {
- 'values': [{
- 'weight': 1,
- 'value': '6.6.6.6',
- }, {
- 'weight': 2,
- 'value': '7.7.7.7',
- }],
+ 'values': [
+ {'weight': 1, 'value': '6.6.6.6'},
+ {'weight': 2, 'value': '7.7.7.7'},
+ ]
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['pool "one" is missing values'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['pool "one" is missing values'], ctx.exception.reasons
+ )
# pool value not a dict
a_data = {
@@ -4177,43 +4459,28 @@ class TestDynamicRecords(TestCase):
'pools': {
'one': '',
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
'three': {
- 'values': [{
- 'weight': 1,
- 'value': '6.6.6.6',
- }, {
- 'weight': 2,
- 'value': '7.7.7.7',
- }],
+ 'values': [
+ {'weight': 1, 'value': '6.6.6.6'},
+ {'weight': 2, 'value': '7.7.7.7'},
+ ]
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['pool "one" must be a dict'],
- ctx.exception.reasons)
+ self.assertEqual(['pool "one" must be a dict'], ctx.exception.reasons)
# empty pool value
a_data = {
@@ -4221,216 +4488,147 @@ class TestDynamicRecords(TestCase):
'pools': {
'one': {},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
'three': {
- 'values': [{
- 'weight': 1,
- 'value': '6.6.6.6',
- }, {
- 'weight': 2,
- 'value': '7.7.7.7',
- }],
+ 'values': [
+ {'weight': 1, 'value': '6.6.6.6'},
+ {'weight': 2, 'value': '7.7.7.7'},
+ ]
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['pool "one" is missing values'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['pool "one" is missing values'], ctx.exception.reasons
+ )
# invalid int weight
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
'three': {
- 'values': [{
- 'weight': 1,
- 'value': '6.6.6.6',
- }, {
- 'weight': 101,
- 'value': '7.7.7.7',
- }],
+ 'values': [
+ {'weight': 1, 'value': '6.6.6.6'},
+ {'weight': 101, 'value': '7.7.7.7'},
+ ]
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['invalid weight "101" in pool "three" value 2'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['invalid weight "101" in pool "three" value 2'],
+ ctx.exception.reasons,
+ )
# invalid non-int weight
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
'three': {
- 'values': [{
- 'weight': 1,
- 'value': '6.6.6.6',
- }, {
- 'weight': 'foo',
- 'value': '7.7.7.7',
- }],
+ 'values': [
+ {'weight': 1, 'value': '6.6.6.6'},
+ {'weight': 'foo', 'value': '7.7.7.7'},
+ ]
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['invalid weight "foo" in pool "three" value 2'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['invalid weight "foo" in pool "three" value 2'],
+ ctx.exception.reasons,
+ )
# single value with weight!=1
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'weight': 12,
- 'value': '6.6.6.6',
- }],
- },
+ 'one': {'values': [{'weight': 12, 'value': '6.6.6.6'}]}
},
- 'rules': [{
- 'pool': 'one',
- }],
+ 'rules': [{'pool': 'one'}],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['pool "one" has single value with weight!=1'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['pool "one" has single value with weight!=1'],
+ ctx.exception.reasons,
+ )
# invalid fallback
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }],
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
'fallback': 'invalid',
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}],
},
'three': {
'fallback': 'two',
- 'values': [{
- 'weight': 1,
- 'value': '6.6.6.6',
- }, {
- 'weight': 5,
- 'value': '7.7.7.7',
- }],
+ 'values': [
+ {'weight': 1, 'value': '6.6.6.6'},
+ {'weight': 5, 'value': '7.7.7.7'},
+ ],
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['undefined fallback "invalid" for pool "two"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['undefined fallback "invalid" for pool "two"'],
+ ctx.exception.reasons,
+ )
# fallback loop
a_data = {
@@ -4438,53 +4636,40 @@ class TestDynamicRecords(TestCase):
'pools': {
'one': {
'fallback': 'three',
- 'values': [{
- 'value': '3.3.3.3',
- }],
+ 'values': [{'value': '3.3.3.3'}],
},
'two': {
'fallback': 'one',
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}],
},
'three': {
'fallback': 'two',
- 'values': [{
- 'weight': 1,
- 'value': '6.6.6.6',
- }, {
- 'weight': 5,
- 'value': '7.7.7.7',
- }],
+ 'values': [
+ {'weight': 1, 'value': '6.6.6.6'},
+ {'weight': 5, 'value': '7.7.7.7'},
+ ],
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual([
- 'loop in pool fallbacks: one -> three -> two',
- 'loop in pool fallbacks: three -> two -> one',
- 'loop in pool fallbacks: two -> one -> three'
- ], ctx.exception.reasons)
+ self.assertEqual(
+ [
+ 'loop in pool fallbacks: one -> three -> two',
+ 'loop in pool fallbacks: three -> two -> one',
+ 'loop in pool fallbacks: two -> one -> three',
+ ],
+ ctx.exception.reasons,
+ )
# multiple pool problems
a_data = {
@@ -4492,438 +4677,276 @@ class TestDynamicRecords(TestCase):
'pools': {
'one': '',
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': 'blip',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': 'blip'}]
},
'three': {
- 'values': [{
- 'weight': 1,
- }, {
- 'weight': 5000,
- 'value': '7.7.7.7',
- }],
+ 'values': [
+ {'weight': 1},
+ {'weight': 5000, 'value': '7.7.7.7'},
+ ]
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual([
- 'pool "one" must be a dict',
- 'missing value in pool "three" value 1',
- 'invalid weight "5000" in pool "three" value 2',
- 'invalid IPv4 address "blip"',
- ], ctx.exception.reasons)
+ self.assertEqual(
+ [
+ 'pool "one" must be a dict',
+ 'missing value in pool "three" value 1',
+ 'invalid weight "5000" in pool "three" value 2',
+ 'invalid IPv4 address "blip"',
+ ],
+ ctx.exception.reasons,
+ )
# missing rules, and unused pools
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
- },
+ }
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual([
- 'missing rules',
- 'unused pools: "one", "two"',
- ], ctx.exception.reasons)
+ self.assertEqual(
+ ['missing rules', 'unused pools: "one", "two"'],
+ ctx.exception.reasons,
+ )
# empty rules
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
'rules': [],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual([
- 'missing rules',
- 'unused pools: "one", "two"',
- ], ctx.exception.reasons)
+ self.assertEqual(
+ ['missing rules', 'unused pools: "one", "two"'],
+ ctx.exception.reasons,
+ )
# rules not a list/tuple
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
'rules': {},
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual([
- 'rules must be a list',
- 'unused pools: "one", "two"',
- ], ctx.exception.reasons)
+ self.assertEqual(
+ ['rules must be a list', 'unused pools: "one", "two"'],
+ ctx.exception.reasons,
+ )
# rule without pool
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }],
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
- 'rules': [{
- 'geos': ['NA-US-CA'],
- }, {
- 'pool': 'one',
- }],
+ 'rules': [{'geos': ['NA-US-CA']}, {'pool': 'one'}],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual([
- 'rule 1 missing pool',
- 'unused pools: "two"',
- ], ctx.exception.reasons)
+ self.assertEqual(
+ ['rule 1 missing pool', 'unused pools: "two"'],
+ ctx.exception.reasons,
+ )
# rule with non-string pools
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
- 'rules': [{
- 'geos': ['NA-US-CA'],
- 'pool': [],
- }, {
- 'pool': 'one',
- }],
+ 'rules': [{'geos': ['NA-US-CA'], 'pool': []}, {'pool': 'one'}],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual([
- 'rule 1 invalid pool "[]"',
- 'unused pools: "two"',
- ], ctx.exception.reasons)
+ self.assertEqual(
+ ['rule 1 invalid pool "[]"', 'unused pools: "two"'],
+ ctx.exception.reasons,
+ )
# rule references non-existent pool
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
- 'rules': [{
- 'geos': ['NA-US-CA'],
- 'pool': 'non-existent',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['NA-US-CA'], 'pool': 'non-existent'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual([
- "rule 1 undefined pool \"non-existent\"",
- 'unused pools: "two"',
- ], ctx.exception.reasons)
+ self.assertEqual(
+ ["rule 1 undefined pool \"non-existent\"", 'unused pools: "two"'],
+ ctx.exception.reasons,
+ )
# rule with invalid geos
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
- 'rules': [{
- 'geos': 'NA-US-CA',
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [{'geos': 'NA-US-CA', 'pool': 'two'}, {'pool': 'one'}],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['rule 1 geos must be a list'],
- ctx.exception.reasons)
+ self.assertEqual(['rule 1 geos must be a list'], ctx.exception.reasons)
# rule with invalid geo
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
- 'rules': [{
- 'geos': ['invalid'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['invalid'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['rule 1 unknown continent code "invalid"'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['rule 1 unknown continent code "invalid"'], ctx.exception.reasons
+ )
# multiple default rules
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
- 'rules': [{
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [{'pool': 'two'}, {'pool': 'one'}],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['rule 2 duplicate default'],
- ctx.exception.reasons)
+ self.assertEqual(['rule 2 duplicate default'], ctx.exception.reasons)
# repeated pool in rules
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
- 'rules': [{
- 'geos': ['EU'],
- 'pool': 'two',
- }, {
- 'geos': ['AF'],
- 'pool': 'one',
- }, {
- 'geos': ['OC'],
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['EU'], 'pool': 'two'},
+ {'geos': ['AF'], 'pool': 'one'},
+ {'geos': ['OC'], 'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['rule 3 invalid, target pool "one" reused'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['rule 3 invalid, target pool "one" reused'], ctx.exception.reasons
+ )
# Repeated pool is OK if later one is a default
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
- 'rules': [{
- 'geos': ['EU-GB'],
- 'pool': 'one',
- }, {
- 'geos': ['EU'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [
+ {'geos': ['EU-GB'], 'pool': 'one'},
+ {'geos': ['EU'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
# This should be valid, no exception
Record.new(self.zone, 'bad', a_data)
@@ -4932,16 +4955,9 @@ class TestDynamicRecords(TestCase):
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '2.2.2.2',
- 'status': 'none',
- }],
- },
+ 'one': {'values': [{'value': '2.2.2.2', 'status': 'none'}]}
},
- 'rules': [{
- 'pool': 'one',
- }],
+ 'rules': [{'pool': 'one'}],
},
'ttl': 60,
'type': 'A',
@@ -4955,136 +4971,98 @@ class TestDynamicRecords(TestCase):
# Missing pools
a_data = {
'dynamic': {
- 'rules': [{
- 'geos': ['EU'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [{'geos': ['EU'], 'pool': 'two'}, {'pool': 'one'}]
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
a = Record.new(self.zone, 'bad', a_data, lenient=True)
- self.assertEqual({
- 'pools': {},
- 'rules': a_data['dynamic']['rules'],
- }, a._data()['dynamic'])
+ self.assertEqual(
+ {'pools': {}, 'rules': a_data['dynamic']['rules']},
+ a._data()['dynamic'],
+ )
# Missing rule
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- 'weight': 2,
- }]
+ 'values': [
+ {'value': '4.4.4.4'},
+ {'value': '5.5.5.5', 'weight': 2},
+ ]
},
- },
+ }
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
a = Record.new(self.zone, 'bad', a_data, lenient=True)
- self.assertEqual({
- 'pools': {
- 'one': {
- 'fallback': None,
- 'values': [{
- 'value': '3.3.3.3',
- 'weight': 1,
- 'status': 'obey',
- }]
- },
- 'two': {
- 'fallback': None,
- 'values': [{
- 'value': '4.4.4.4',
- 'weight': 1,
- 'status': 'obey',
- }, {
- 'value': '5.5.5.5',
- 'weight': 2,
- 'status': 'obey',
- }]
+ self.assertEqual(
+ {
+ 'pools': {
+ 'one': {
+ 'fallback': None,
+ 'values': [
+ {'value': '3.3.3.3', 'weight': 1, 'status': 'obey'}
+ ],
+ },
+ 'two': {
+ 'fallback': None,
+ 'values': [
+ {'value': '4.4.4.4', 'weight': 1, 'status': 'obey'},
+ {'value': '5.5.5.5', 'weight': 2, 'status': 'obey'},
+ ],
+ },
},
+ 'rules': [],
},
- 'rules': [],
- }, a._data()['dynamic'])
+ a._data()['dynamic'],
+ )
# rule without pool
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- 'weight': 2,
- }]
+ 'values': [
+ {'value': '4.4.4.4'},
+ {'value': '5.5.5.5', 'weight': 2},
+ ]
},
},
- 'rules': [{
- 'geos': ['EU'],
- 'pool': 'two',
- }, {
- }],
+ 'rules': [{'geos': ['EU'], 'pool': 'two'}, {}],
},
'ttl': 60,
'type': 'A',
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
a = Record.new(self.zone, 'bad', a_data, lenient=True)
- self.assertEqual({
- 'pools': {
- 'one': {
- 'fallback': None,
- 'values': [{
- 'value': '3.3.3.3',
- 'weight': 1,
- 'status': 'obey',
- }]
- },
- 'two': {
- 'fallback': None,
- 'values': [{
- 'value': '4.4.4.4',
- 'weight': 1,
- 'status': 'obey',
- }, {
- 'value': '5.5.5.5',
- 'weight': 2,
- 'status': 'obey',
- }]
+ self.assertEqual(
+ {
+ 'pools': {
+ 'one': {
+ 'fallback': None,
+ 'values': [
+ {'value': '3.3.3.3', 'weight': 1, 'status': 'obey'}
+ ],
+ },
+ 'two': {
+ 'fallback': None,
+ 'values': [
+ {'value': '4.4.4.4', 'weight': 1, 'status': 'obey'},
+ {'value': '5.5.5.5', 'weight': 2, 'status': 'obey'},
+ ],
+ },
},
+ 'rules': a_data['dynamic']['rules'],
},
- 'rules': a_data['dynamic']['rules'],
- }, a._data()['dynamic'])
+ a._data()['dynamic'],
+ )
def test_dynamic_changes(self):
simple = SimpleProvider()
@@ -5093,31 +5071,15 @@ class TestDynamicRecords(TestCase):
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
- 'rules': [{
- 'geos': ['EU'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [{'geos': ['EU'], 'pool': 'two'}, {'pool': 'one'}],
},
'ttl': 60,
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
a = ARecord(self.zone, 'weighted', a_data)
dup = ARecord(self.zone, 'weighted', a_data)
@@ -5125,63 +5087,33 @@ class TestDynamicRecords(TestCase):
b_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- 'weight': 2,
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [
+ {'value': '4.4.4.4', 'weight': 2},
+ {'value': '5.5.5.5'},
+ ]
},
},
- 'rules': [{
- 'geos': ['EU'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [{'geos': ['EU'], 'pool': 'two'}, {'pool': 'one'}],
},
'ttl': 60,
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
b = ARecord(self.zone, 'weighted', b_data)
c_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }]
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
- 'values': [{
- 'value': '4.4.4.4',
- }, {
- 'value': '5.5.5.5',
- }]
+ 'values': [{'value': '4.4.4.4'}, {'value': '5.5.5.5'}]
},
},
- 'rules': [{
- 'geos': ['NA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
+ 'rules': [{'geos': ['NA'], 'pool': 'two'}, {'pool': 'one'}],
},
'ttl': 60,
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
c = ARecord(self.zone, 'weighted', c_data)
@@ -5219,88 +5151,50 @@ class TestDynamicRecords(TestCase):
a_data = {
'dynamic': {
'pools': {
- 'one': {
- 'values': [{
- 'value': '3.3.3.3',
- }],
- },
+ 'one': {'values': [{'value': '3.3.3.3'}]},
'two': {
# Testing out of order value sorting here
- 'values': [{
- 'value': '5.5.5.5',
- }, {
- 'value': '4.4.4.4',
- }],
+ 'values': [{'value': '5.5.5.5'}, {'value': '4.4.4.4'}]
},
'three': {
- 'values': [{
- 'weight': 10,
- 'value': '4.4.4.4',
- }, {
- 'weight': 12,
- 'value': '5.5.5.5',
- }],
+ 'values': [
+ {'weight': 10, 'value': '4.4.4.4'},
+ {'weight': 12, 'value': '5.5.5.5'},
+ ]
},
},
- 'rules': [{
- 'geos': ['AF', 'EU'],
- 'pool': 'three',
- }, {
- 'geos': ['NA-US-CA'],
- 'pool': 'two',
- }, {
- 'pool': 'one',
- }],
- },
- 'geo': {
- 'NA': ['1.2.3.5'],
- 'NA-US': ['1.2.3.5', '1.2.3.6']
+ 'rules': [
+ {'geos': ['AF', 'EU'], 'pool': 'three'},
+ {'geos': ['NA-US-CA'], 'pool': 'two'},
+ {'pool': 'one'},
+ ],
},
+ 'geo': {'NA': ['1.2.3.5'], 'NA-US': ['1.2.3.5', '1.2.3.6']},
'type': 'A',
'ttl': 60,
- 'values': [
- '1.1.1.1',
- '2.2.2.2',
- ],
+ 'values': ['1.1.1.1', '2.2.2.2'],
}
with self.assertRaises(ValidationError) as ctx:
Record.new(self.zone, 'bad', a_data)
- self.assertEqual(['"dynamic" record with "geo" content'],
- ctx.exception.reasons)
+ self.assertEqual(
+ ['"dynamic" record with "geo" content'], ctx.exception.reasons
+ )
def test_dynamic_eqs(self):
- pool_one = _DynamicPool('one', {
- 'values': [{
- 'value': '1.2.3.4',
- }],
- })
- pool_two = _DynamicPool('two', {
- 'values': [{
- 'value': '1.2.3.5',
- }],
- })
+ pool_one = _DynamicPool('one', {'values': [{'value': '1.2.3.4'}]})
+ pool_two = _DynamicPool('two', {'values': [{'value': '1.2.3.5'}]})
self.assertEqual(pool_one, pool_one)
self.assertNotEqual(pool_one, pool_two)
self.assertNotEqual(pool_one, 42)
- pools = {
- 'one': pool_one,
- 'two': pool_two,
- }
- rule_one = _DynamicRule(0, {
- 'pool': 'one',
- })
- rule_two = _DynamicRule(1, {
- 'pool': 'two',
- })
+ pools = {'one': pool_one, 'two': pool_two}
+ rule_one = _DynamicRule(0, {'pool': 'one'})
+ rule_two = _DynamicRule(1, {'pool': 'two'})
self.assertEqual(rule_one, rule_one)
self.assertNotEqual(rule_one, rule_two)
self.assertNotEqual(rule_one, 42)
- rules = [
- rule_one,
- rule_two,
- ]
+ rules = [rule_one, rule_two]
dynamic = _Dynamic(pools, rules)
other = _Dynamic({}, [])
@@ -5311,26 +5205,30 @@ class TestDynamicRecords(TestCase):
class TestChanges(TestCase):
zone = Zone('unit.tests.', [])
- record_a_1 = Record.new(zone, '1', {
- 'type': 'A',
- 'ttl': 30,
- 'value': '1.2.3.4',
- })
- record_a_2 = Record.new(zone, '2', {
- 'type': 'A',
- 'ttl': 30,
- 'value': '1.2.3.4',
- })
- record_aaaa_1 = Record.new(zone, '1', {
- 'type': 'AAAA',
- 'ttl': 30,
- 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
- })
- record_aaaa_2 = Record.new(zone, '2', {
- 'type': 'AAAA',
- 'ttl': 30,
- 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
- })
+ record_a_1 = Record.new(
+ zone, '1', {'type': 'A', 'ttl': 30, 'value': '1.2.3.4'}
+ )
+ record_a_2 = Record.new(
+ zone, '2', {'type': 'A', 'ttl': 30, 'value': '1.2.3.4'}
+ )
+ record_aaaa_1 = Record.new(
+ zone,
+ '1',
+ {
+ 'type': 'AAAA',
+ 'ttl': 30,
+ 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
+ },
+ )
+ record_aaaa_2 = Record.new(
+ zone,
+ '2',
+ {
+ 'type': 'AAAA',
+ 'ttl': 30,
+ 'value': '2601:644:500:e210:62f8:1dff:feb8:947a',
+ },
+ )
def test_sort_same_change_type(self):
# expect things to be ordered by name and type since all the change
@@ -5341,12 +5239,15 @@ class TestChanges(TestCase):
Create(self.record_a_1),
Create(self.record_aaaa_2),
]
- self.assertEqual([
- Create(self.record_a_1),
- Create(self.record_aaaa_1),
- Create(self.record_a_2),
- Create(self.record_aaaa_2),
- ], sorted(changes))
+ self.assertEqual(
+ [
+ Create(self.record_a_1),
+ Create(self.record_aaaa_1),
+ Create(self.record_a_2),
+ Create(self.record_aaaa_2),
+ ],
+ sorted(changes),
+ )
def test_sort_same_different_type(self):
# this time the change type is the deciding factor, deletes come before
@@ -5366,17 +5267,20 @@ class TestChanges(TestCase):
Create(self.record_a_2),
Delete(self.record_a_2),
]
- self.assertEqual([
- Delete(self.record_a_1),
- Delete(self.record_aaaa_1),
- Delete(self.record_a_2),
- Delete(self.record_aaaa_2),
- Create(self.record_a_1),
- Create(self.record_aaaa_1),
- Create(self.record_a_2),
- Create(self.record_aaaa_2),
- Update(self.record_a_1, self.record_a_1),
- Update(self.record_aaaa_1, self.record_aaaa_1),
- Update(self.record_a_2, self.record_a_2),
- Update(self.record_aaaa_2, self.record_aaaa_2),
- ], sorted(changes))
+ self.assertEqual(
+ [
+ Delete(self.record_a_1),
+ Delete(self.record_aaaa_1),
+ Delete(self.record_a_2),
+ Delete(self.record_aaaa_2),
+ Create(self.record_a_1),
+ Create(self.record_aaaa_1),
+ Create(self.record_a_2),
+ Create(self.record_aaaa_2),
+ Update(self.record_a_1, self.record_a_1),
+ Update(self.record_aaaa_1, self.record_aaaa_1),
+ Update(self.record_a_2, self.record_a_2),
+ Update(self.record_aaaa_2, self.record_aaaa_2),
+ ],
+ sorted(changes),
+ )
diff --git a/tests/test_octodns_record_geo.py b/tests/test_octodns_record_geo.py
index 06f1609..16745ac 100644
--- a/tests/test_octodns_record_geo.py
+++ b/tests/test_octodns_record_geo.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
@@ -11,7 +15,6 @@ from octodns.record.geo import GeoCodes
class TestRecordGeoCodes(TestCase):
-
def test_validate(self):
prefix = 'xyz '
@@ -21,53 +24,81 @@ class TestRecordGeoCodes(TestCase):
self.assertEqual([], GeoCodes.validate('NA-US-OR', prefix))
# Just plain bad
- self.assertEqual(['xyz invalid geo code "XX-YY-ZZ-AA"'],
- GeoCodes.validate('XX-YY-ZZ-AA', prefix))
- self.assertEqual(['xyz unknown continent code "X-Y-Z"'],
- GeoCodes.validate('X-Y-Z', prefix))
- self.assertEqual(['xyz unknown continent code "XXX-Y-Z"'],
- GeoCodes.validate('XXX-Y-Z', prefix))
+ self.assertEqual(
+ ['xyz invalid geo code "XX-YY-ZZ-AA"'],
+ GeoCodes.validate('XX-YY-ZZ-AA', prefix),
+ )
+ self.assertEqual(
+ ['xyz unknown continent code "X-Y-Z"'],
+ GeoCodes.validate('X-Y-Z', prefix),
+ )
+ self.assertEqual(
+ ['xyz unknown continent code "XXX-Y-Z"'],
+ GeoCodes.validate('XXX-Y-Z', prefix),
+ )
# Bad continent
- self.assertEqual(['xyz unknown continent code "XX"'],
- GeoCodes.validate('XX', prefix))
+ self.assertEqual(
+ ['xyz unknown continent code "XX"'], GeoCodes.validate('XX', prefix)
+ )
# Bad continent good country
- self.assertEqual(['xyz unknown continent code "XX-US"'],
- GeoCodes.validate('XX-US', prefix))
+ self.assertEqual(
+ ['xyz unknown continent code "XX-US"'],
+ GeoCodes.validate('XX-US', prefix),
+ )
# Bad continent good country and province
- self.assertEqual(['xyz unknown continent code "XX-US-OR"'],
- GeoCodes.validate('XX-US-OR', prefix))
+ self.assertEqual(
+ ['xyz unknown continent code "XX-US-OR"'],
+ GeoCodes.validate('XX-US-OR', prefix),
+ )
# Bad country, good continent
- self.assertEqual(['xyz unknown country code "NA-XX"'],
- GeoCodes.validate('NA-XX', prefix))
+ self.assertEqual(
+ ['xyz unknown country code "NA-XX"'],
+ GeoCodes.validate('NA-XX', prefix),
+ )
# Bad country, good continent and state
- self.assertEqual(['xyz unknown country code "NA-XX-OR"'],
- GeoCodes.validate('NA-XX-OR', prefix))
+ self.assertEqual(
+ ['xyz unknown country code "NA-XX-OR"'],
+ GeoCodes.validate('NA-XX-OR', prefix),
+ )
# Good country, good continent, but bad match
- self.assertEqual(['xyz unknown country code "NA-GB"'],
- GeoCodes.validate('NA-GB', prefix))
+ self.assertEqual(
+ ['xyz unknown country code "NA-GB"'],
+ GeoCodes.validate('NA-GB', prefix),
+ )
# Bad province code, good continent and country
- self.assertEqual(['xyz unknown province code "NA-US-XX"'],
- GeoCodes.validate('NA-US-XX', prefix))
+ self.assertEqual(
+ ['xyz unknown province code "NA-US-XX"'],
+ GeoCodes.validate('NA-US-XX', prefix),
+ )
def test_parse(self):
- self.assertEqual({
- 'continent_code': 'NA',
- 'country_code': None,
- 'province_code': None,
- }, GeoCodes.parse('NA'))
- self.assertEqual({
- 'continent_code': 'NA',
- 'country_code': 'US',
- 'province_code': None,
- }, GeoCodes.parse('NA-US'))
- self.assertEqual({
- 'continent_code': 'NA',
- 'country_code': 'US',
- 'province_code': 'CA',
- }, GeoCodes.parse('NA-US-CA'))
+ self.assertEqual(
+ {
+ 'continent_code': 'NA',
+ 'country_code': None,
+ 'province_code': None,
+ },
+ GeoCodes.parse('NA'),
+ )
+ self.assertEqual(
+ {
+ 'continent_code': 'NA',
+ 'country_code': 'US',
+ 'province_code': None,
+ },
+ GeoCodes.parse('NA-US'),
+ )
+ self.assertEqual(
+ {
+ 'continent_code': 'NA',
+ 'country_code': 'US',
+ 'province_code': 'CA',
+ },
+ GeoCodes.parse('NA-US-CA'),
+ )
def test_country_to_code(self):
self.assertEqual('NA-US', GeoCodes.country_to_code('US'))
diff --git a/tests/test_octodns_source_axfr.py b/tests/test_octodns_source_axfr.py
index bb548b1..356491a 100644
--- a/tests/test_octodns_source_axfr.py
+++ b/tests/test_octodns_source_axfr.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
import dns.zone
from dns.exception import DNSException
@@ -13,8 +17,12 @@ from shutil import copyfile
from unittest import TestCase
from unittest.mock import patch
-from octodns.source.axfr import AxfrSource, AxfrSourceZoneTransferFailed, \
- ZoneFileSource, ZoneFileSourceLoadFailure
+from octodns.source.axfr import (
+ AxfrSource,
+ AxfrSourceZoneTransferFailed,
+ ZoneFileSource,
+ ZoneFileSourceLoadFailure,
+)
from octodns.zone import Zone
from octodns.record import ValidationError
@@ -22,17 +30,21 @@ from octodns.record import ValidationError
class TestAxfrSource(TestCase):
source = AxfrSource('test', 'localhost')
- forward_zonefile = dns.zone.from_file('./tests/zones/unit.tests.tst',
- 'unit.tests', relativize=False)
+ forward_zonefile = dns.zone.from_file(
+ './tests/zones/unit.tests.tst', 'unit.tests', relativize=False
+ )
+
+ reverse_zonefile = dns.zone.from_file(
+ './tests/zones/2.0.192.in-addr.arpa.',
+ '2.0.192.in-addr.arpa',
+ relativize=False,
+ )
@patch('dns.zone.from_xfr')
- def test_populate(self, from_xfr_mock):
+ def test_populate_forward(self, from_xfr_mock):
got = Zone('unit.tests.', [])
- from_xfr_mock.side_effect = [
- self.forward_zonefile,
- DNSException
- ]
+ from_xfr_mock.side_effect = [self.forward_zonefile, DNSException]
self.source.populate(got)
self.assertEqual(16, len(got.records))
@@ -40,8 +52,16 @@ class TestAxfrSource(TestCase):
with self.assertRaises(AxfrSourceZoneTransferFailed) as ctx:
zone = Zone('unit.tests.', [])
self.source.populate(zone)
- self.assertEqual('Unable to Perform Zone Transfer',
- str(ctx.exception))
+ self.assertEqual('Unable to Perform Zone Transfer', str(ctx.exception))
+
+ @patch('dns.zone.from_xfr')
+ def test_populate_reverse(self, from_xfr_mock):
+ got = Zone('2.0.192.in-addr.arpa.', [])
+
+ from_xfr_mock.side_effect = [self.reverse_zonefile]
+
+ self.source.populate(got)
+ self.assertEqual(4, len(got.records))
class TestZoneFileSource(TestCase):
@@ -65,8 +85,10 @@ class TestZoneFileSource(TestCase):
# It did so we need to skip this test, that means windows won't
# have full code coverage, but skipping the test is going out of
# our way enough for a os-specific/oddball case.
- self.skipTest('Unable to create unit.tests. (ending with .) so '
- 'skipping default filename testing.')
+ self.skipTest(
+ 'Unable to create unit.tests. (ending with .) so '
+ 'skipping default filename testing.'
+ )
source = ZoneFileSource('test', './tests/zones')
# Load zonefiles without a specified file extension
@@ -97,16 +119,19 @@ class TestZoneFileSource(TestCase):
with self.assertRaises(ZoneFileSourceLoadFailure) as ctx:
zone = Zone('invalid.zone.', [])
self.source.populate(zone)
- self.assertEqual('The DNS zone has no NS RRset at its origin.',
- str(ctx.exception))
+ self.assertEqual(
+ 'The DNS zone has no NS RRset at its origin.', str(ctx.exception)
+ )
# Records are not to RFC (lenient=False)
with self.assertRaises(ValidationError) as ctx:
zone = Zone('invalid.records.', [])
self.source.populate(zone)
- self.assertEqual('Invalid record _invalid.invalid.records.\n'
- ' - invalid name for SRV record',
- str(ctx.exception))
+ self.assertEqual(
+ 'Invalid record _invalid.invalid.records.\n'
+ ' - invalid name for SRV record',
+ str(ctx.exception),
+ )
# Records are not to RFC, but load anyhow (lenient=True)
invalid = Zone('invalid.records.', [])
diff --git a/tests/test_octodns_source_envvar.py b/tests/test_octodns_source_envvar.py
index 775b541..cb40618 100644
--- a/tests/test_octodns_source_envvar.py
+++ b/tests/test_octodns_source_envvar.py
@@ -7,7 +7,6 @@ from octodns.zone import Zone
class TestEnvVarSource(TestCase):
-
def test_read_variable(self):
envvar = 'OCTODNS_TEST_ENVIRONMENT_VARIABLE'
source = EnvVarSource('testid', envvar, 'recordname', ttl=120)
diff --git a/tests/test_octodns_source_tinydns.py b/tests/test_octodns_source_tinydns.py
index bfc2cf1..140ae42 100644
--- a/tests/test_octodns_source_tinydns.py
+++ b/tests/test_octodns_source_tinydns.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
@@ -24,103 +28,96 @@ class TestTinyDnsFileSource(TestCase):
expected = Zone('example.com.', [])
for name, data in (
- ('', {
- 'type': 'A',
- 'ttl': 30,
- 'values': ['10.2.3.4', '10.2.3.5'],
- }),
- ('', {
- 'type': 'NS',
- 'ttl': 3600,
- 'values': ['ns1.ns.com.', 'ns2.ns.com.'],
- }),
- ('sub', {
- 'type': 'NS',
- 'ttl': 30,
- 'values': ['ns3.ns.com.', 'ns4.ns.com.'],
- }),
- ('www', {
- 'type': 'A',
- 'ttl': 3600,
- 'value': '10.2.3.6',
- }),
- ('cname', {
- 'type': 'CNAME',
- 'ttl': 3600,
- 'value': 'www.example.com.',
- }),
- ('some-host-abc123', {
- 'type': 'A',
- 'ttl': 1800,
- 'value': '10.2.3.7',
- }),
- ('has-dup-def123', {
- 'type': 'A',
- 'ttl': 3600,
- 'value': '10.2.3.8',
- }),
- ('www.sub', {
- 'type': 'A',
- 'ttl': 3600,
- 'value': '1.2.3.4',
- }),
- ('has-dup-def456', {
- 'type': 'A',
- 'ttl': 3600,
- 'value': '10.2.3.8',
- }),
- ('', {
- 'type': 'MX',
- 'ttl': 3600,
- 'values': [{
- 'preference': 10,
- 'exchange': 'smtp-1-host.example.com.',
- }, {
- 'preference': 20,
- 'exchange': 'smtp-2-host.example.com.',
- }]
- }),
- ('smtp', {
- 'type': 'MX',
- 'ttl': 1800,
- 'values': [{
- 'preference': 30,
- 'exchange': 'smtp-1-host.example.com.',
- }, {
- 'preference': 40,
- 'exchange': 'smtp-2-host.example.com.',
- }]
- }),
- ('', {
- 'type': 'TXT',
- 'ttl': 300,
- 'value': 'test TXT',
- }),
- ('colon', {
- 'type': 'TXT',
- 'ttl': 300,
- 'value': 'test : TXT',
- }),
- ('nottl', {
- 'type': 'TXT',
- 'ttl': 3600,
- 'value': 'nottl test TXT',
- }),
- ('ipv6-3', {
- 'type': 'AAAA',
- 'ttl': 300,
- 'value': '2a02:1348:017c:d5d0:0024:19ff:fef3:5742',
- }),
- ('ipv6-6', {
- 'type': 'AAAA',
- 'ttl': 3600,
- 'value': '2a02:1348:017c:d5d0:0024:19ff:fef3:5743',
- }),
- ('semicolon', {
- 'type': 'TXT',
- 'ttl': 300,
- 'value': 'v=DKIM1\\; k=rsa\\; p=blah',
- }),
+ ('', {'type': 'A', 'ttl': 30, 'values': ['10.2.3.4', '10.2.3.5']}),
+ (
+ '',
+ {
+ 'type': 'NS',
+ 'ttl': 3600,
+ 'values': ['ns1.ns.com.', 'ns2.ns.com.'],
+ },
+ ),
+ (
+ 'sub',
+ {
+ 'type': 'NS',
+ 'ttl': 30,
+ 'values': ['ns3.ns.com.', 'ns4.ns.com.'],
+ },
+ ),
+ ('www', {'type': 'A', 'ttl': 3600, 'value': '10.2.3.6'}),
+ (
+ 'cname',
+ {'type': 'CNAME', 'ttl': 3600, 'value': 'www.example.com.'},
+ ),
+ (
+ 'some-host-abc123',
+ {'type': 'A', 'ttl': 1800, 'value': '10.2.3.7'},
+ ),
+ ('has-dup-def123', {'type': 'A', 'ttl': 3600, 'value': '10.2.3.8'}),
+ ('www.sub', {'type': 'A', 'ttl': 3600, 'value': '1.2.3.4'}),
+ ('has-dup-def456', {'type': 'A', 'ttl': 3600, 'value': '10.2.3.8'}),
+ (
+ '',
+ {
+ 'type': 'MX',
+ 'ttl': 3600,
+ 'values': [
+ {
+ 'preference': 10,
+ 'exchange': 'smtp-1-host.example.com.',
+ },
+ {
+ 'preference': 20,
+ 'exchange': 'smtp-2-host.example.com.',
+ },
+ ],
+ },
+ ),
+ (
+ 'smtp',
+ {
+ 'type': 'MX',
+ 'ttl': 1800,
+ 'values': [
+ {
+ 'preference': 30,
+ 'exchange': 'smtp-1-host.example.com.',
+ },
+ {
+ 'preference': 40,
+ 'exchange': 'smtp-2-host.example.com.',
+ },
+ ],
+ },
+ ),
+ ('', {'type': 'TXT', 'ttl': 300, 'value': 'test TXT'}),
+ ('colon', {'type': 'TXT', 'ttl': 300, 'value': 'test : TXT'}),
+ ('nottl', {'type': 'TXT', 'ttl': 3600, 'value': 'nottl test TXT'}),
+ (
+ 'ipv6-3',
+ {
+ 'type': 'AAAA',
+ 'ttl': 300,
+ 'value': '2a02:1348:017c:d5d0:0024:19ff:fef3:5742',
+ },
+ ),
+ (
+ 'ipv6-6',
+ {
+ 'type': 'AAAA',
+ 'ttl': 3600,
+ 'value': '2a02:1348:017c:d5d0:0024:19ff:fef3:5743',
+ },
+ ),
+ (
+ 'semicolon',
+ {
+ 'type': 'TXT',
+ 'ttl': 300,
+ 'value': 'v=DKIM1\\; k=rsa\\; p=blah',
+ },
+ ),
):
record = Record.new(expected, name, data)
expected.add_record(record)
@@ -135,11 +132,7 @@ class TestTinyDnsFileSource(TestCase):
expected = Zone('asdf.subtest.com.', [])
for name, data in (
- ('a3', {
- 'type': 'A',
- 'ttl': 3600,
- 'values': ['10.2.3.7'],
- }),
+ ('a3', {'type': 'A', 'ttl': 3600, 'values': ['10.2.3.7']}),
):
record = Record.new(expected, name, data)
expected.add_record(record)
@@ -154,16 +147,8 @@ class TestTinyDnsFileSource(TestCase):
expected = Zone('sub-asdf.subtest.com.', [])
for name, data in (
- ('a1', {
- 'type': 'A',
- 'ttl': 3600,
- 'values': ['10.2.3.5'],
- }),
- ('a2', {
- 'type': 'A',
- 'ttl': 3600,
- 'values': ['10.2.3.6'],
- }),
+ ('a1', {'type': 'A', 'ttl': 3600, 'values': ['10.2.3.5']}),
+ ('a2', {'type': 'A', 'ttl': 3600, 'values': ['10.2.3.6']}),
):
record = Record.new(expected, name, data)
expected.add_record(record)
@@ -178,26 +163,24 @@ class TestTinyDnsFileSource(TestCase):
expected = Zone('3.2.10.in-addr.arpa.', [])
for name, data in (
- ('10', {
- 'type': 'PTR',
- 'ttl': 3600,
- 'value': 'a-ptr.example.com.'
- }),
- ('11', {
- 'type': 'PTR',
- 'ttl': 30,
- 'value': 'a-ptr-2.example.com.'
- }),
- ('8', {
- 'type': 'PTR',
- 'ttl': 3600,
- 'value': 'has-dup-def123.example.com.'
- }),
- ('7', {
- 'type': 'PTR',
- 'ttl': 1800,
- 'value': 'some-host-abc123.example.com.'
- }),
+ ('10', {'type': 'PTR', 'ttl': 3600, 'value': 'a-ptr.example.com.'}),
+ ('11', {'type': 'PTR', 'ttl': 30, 'value': 'a-ptr-2.example.com.'}),
+ (
+ '8',
+ {
+ 'type': 'PTR',
+ 'ttl': 3600,
+ 'value': 'has-dup-def123.example.com.',
+ },
+ ),
+ (
+ '7',
+ {
+ 'type': 'PTR',
+ 'ttl': 1800,
+ 'value': 'some-host-abc123.example.com.',
+ },
+ ),
):
record = Record.new(expected, name, data)
expected.add_record(record)
diff --git a/tests/test_octodns_yaml.py b/tests/test_octodns_yaml.py
index 91adffc..58b4aae 100644
--- a/tests/test_octodns_yaml.py
+++ b/tests/test_octodns_yaml.py
@@ -2,8 +2,12 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from io import StringIO
from unittest import TestCase
@@ -13,58 +17,54 @@ from octodns.yaml import safe_dump, safe_load
class TestYaml(TestCase):
-
def test_stuff(self):
- self.assertEqual({
- 1: 'a',
- 2: 'b',
- '3': 'c',
- 10: 'd',
- '11': 'e',
- }, safe_load('''
+ self.assertEqual(
+ {1: 'a', 2: 'b', '3': 'c', 10: 'd', '11': 'e'},
+ safe_load(
+ '''
1: a
2: b
'3': c
10: d
'11': e
-'''))
+'''
+ ),
+ )
- self.assertEqual({
- '*.1.2': 'a',
- '*.2.2': 'b',
- '*.10.1': 'c',
- '*.11.2': 'd',
- }, safe_load('''
+ self.assertEqual(
+ {'*.1.2': 'a', '*.2.2': 'b', '*.10.1': 'c', '*.11.2': 'd'},
+ safe_load(
+ '''
'*.1.2': 'a'
'*.2.2': 'b'
'*.10.1': 'c'
'*.11.2': 'd'
-'''))
+'''
+ ),
+ )
with self.assertRaises(ConstructorError) as ctx:
- safe_load('''
+ safe_load(
+ '''
'*.2.2': 'b'
'*.1.2': 'a'
'*.11.2': 'd'
'*.10.1': 'c'
-''')
- self.assertTrue('keys out of order: expected *.1.2 got *.2.2 at' in
- ctx.exception.problem)
+'''
+ )
+ self.assertTrue(
+ 'keys out of order: expected *.1.2 got *.2.2 at'
+ in ctx.exception.problem
+ )
buf = StringIO()
- safe_dump({
- '*.1.1': 42,
- '*.11.1': 43,
- '*.2.1': 44,
- }, buf)
- self.assertEqual("---\n'*.1.1': 42\n'*.2.1': 44\n'*.11.1': 43\n",
- buf.getvalue())
+ safe_dump({'*.1.1': 42, '*.11.1': 43, '*.2.1': 44}, buf)
+ self.assertEqual(
+ "---\n'*.1.1': 42\n'*.2.1': 44\n'*.11.1': 43\n", buf.getvalue()
+ )
# hex sorting isn't ideal, not treated as hex, this make sure we don't
# change the behavior
buf = StringIO()
- safe_dump({
- '45a03129': 42,
- '45a0392a': 43,
- }, buf)
+ safe_dump({'45a03129': 42, '45a0392a': 43}, buf)
self.assertEqual("---\n45a0392a: 43\n45a03129: 42\n", buf.getvalue())
diff --git a/tests/test_octodns_zone.py b/tests/test_octodns_zone.py
index 9385984..b884397 100644
--- a/tests/test_octodns_zone.py
+++ b/tests/test_octodns_zone.py
@@ -2,21 +2,35 @@
#
#
-from __future__ import absolute_import, division, print_function, \
- unicode_literals
+from __future__ import (
+ absolute_import,
+ division,
+ print_function,
+ unicode_literals,
+)
from unittest import TestCase
-from octodns.record import ARecord, AaaaRecord, Create, Delete, NsRecord, \
- Record, Update
-from octodns.zone import DuplicateRecordException, InvalidNodeException, \
- SubzoneRecordException, Zone
+from octodns.record import (
+ ARecord,
+ AaaaRecord,
+ Create,
+ Delete,
+ NsRecord,
+ Record,
+ Update,
+)
+from octodns.zone import (
+ DuplicateRecordException,
+ InvalidNodeException,
+ SubzoneRecordException,
+ Zone,
+)
from helpers import SimpleProvider
class TestZone(TestCase):
-
def test_lowering(self):
zone = Zone('UniT.TEsTs.', [])
self.assertEqual('unit.tests.', zone.name)
@@ -47,8 +61,9 @@ class TestZone(TestCase):
# Can't add record with same name & type
with self.assertRaises(DuplicateRecordException) as ctx:
zone.add_record(a)
- self.assertEqual('Duplicate record a.unit.tests., type A',
- str(ctx.exception))
+ self.assertEqual(
+ 'Duplicate record a.unit.tests., type A', str(ctx.exception)
+ )
self.assertEqual(zone.records, set([a]))
# can add duplicate with replace=True
@@ -108,7 +123,6 @@ class TestZone(TestCase):
update.__repr__()
def test_unsupporting(self):
-
class NoAaaaProvider(object):
id = 'no-aaaa'
SUPPORTS_GEO = False
@@ -144,21 +158,21 @@ class TestZone(TestCase):
# NS for exactly the sub is allowed
zone = Zone('unit.tests.', set(['sub', 'barred']))
- record = Record.new(zone, 'sub', {
- 'ttl': 3600,
- 'type': 'NS',
- 'values': ['1.2.3.4.', '2.3.4.5.'],
- })
+ record = Record.new(
+ zone,
+ 'sub',
+ {'ttl': 3600, 'type': 'NS', 'values': ['1.2.3.4.', '2.3.4.5.']},
+ )
zone.add_record(record)
self.assertEqual(set([record]), zone.records)
# non-NS for exactly the sub is rejected
zone = Zone('unit.tests.', set(['sub', 'barred']))
- record = Record.new(zone, 'sub', {
- 'ttl': 3600,
- 'type': 'A',
- 'values': ['1.2.3.4', '2.3.4.5'],
- })
+ record = Record.new(
+ zone,
+ 'sub',
+ {'ttl': 3600, 'type': 'A', 'values': ['1.2.3.4', '2.3.4.5']},
+ )
with self.assertRaises(SubzoneRecordException) as ctx:
zone.add_record(record)
self.assertTrue('not of type NS', str(ctx.exception))
@@ -168,11 +182,11 @@ class TestZone(TestCase):
# NS for something below the sub is rejected
zone = Zone('unit.tests.', set(['sub', 'barred']))
- record = Record.new(zone, 'foo.sub', {
- 'ttl': 3600,
- 'type': 'NS',
- 'values': ['1.2.3.4.', '2.3.4.5.'],
- })
+ record = Record.new(
+ zone,
+ 'foo.sub',
+ {'ttl': 3600, 'type': 'NS', 'values': ['1.2.3.4.', '2.3.4.5.']},
+ )
with self.assertRaises(SubzoneRecordException) as ctx:
zone.add_record(record)
self.assertTrue('under a managed sub-zone', str(ctx.exception))
@@ -182,11 +196,11 @@ class TestZone(TestCase):
# A for something below the sub is rejected
zone = Zone('unit.tests.', set(['sub', 'barred']))
- record = Record.new(zone, 'foo.bar.sub', {
- 'ttl': 3600,
- 'type': 'A',
- 'values': ['1.2.3.4', '2.3.4.5'],
- })
+ record = Record.new(
+ zone,
+ 'foo.bar.sub',
+ {'ttl': 3600, 'type': 'A', 'values': ['1.2.3.4', '2.3.4.5']},
+ )
with self.assertRaises(SubzoneRecordException) as ctx:
zone.add_record(record)
self.assertTrue('under a managed sub-zone', str(ctx.exception))
@@ -199,21 +213,21 @@ class TestZone(TestCase):
zone_ignored = Zone('unit.tests.', [])
zone_missing = Zone('unit.tests.', [])
- normal = Record.new(zone_normal, 'www', {
- 'ttl': 60,
- 'type': 'A',
- 'value': '9.9.9.9',
- })
+ normal = Record.new(
+ zone_normal, 'www', {'ttl': 60, 'type': 'A', 'value': '9.9.9.9'}
+ )
zone_normal.add_record(normal)
- ignored = Record.new(zone_ignored, 'www', {
- 'octodns': {
- 'ignored': True
+ ignored = Record.new(
+ zone_ignored,
+ 'www',
+ {
+ 'octodns': {'ignored': True},
+ 'ttl': 60,
+ 'type': 'A',
+ 'value': '9.9.9.9',
},
- 'ttl': 60,
- 'type': 'A',
- 'value': '9.9.9.9',
- })
+ )
zone_ignored.add_record(ignored)
provider = SimpleProvider()
@@ -229,16 +243,12 @@ class TestZone(TestCase):
def test_cname_coexisting(self):
zone = Zone('unit.tests.', [])
- a = Record.new(zone, 'www', {
- 'ttl': 60,
- 'type': 'A',
- 'value': '9.9.9.9',
- })
- cname = Record.new(zone, 'www', {
- 'ttl': 60,
- 'type': 'CNAME',
- 'value': 'foo.bar.com.',
- })
+ a = Record.new(
+ zone, 'www', {'ttl': 60, 'type': 'A', 'value': '9.9.9.9'}
+ )
+ cname = Record.new(
+ zone, 'www', {'ttl': 60, 'type': 'CNAME', 'value': 'foo.bar.com.'}
+ )
# add cname to a
zone.add_record(a)
@@ -262,21 +272,21 @@ class TestZone(TestCase):
zone_excluded = Zone('unit.tests.', [])
zone_missing = Zone('unit.tests.', [])
- normal = Record.new(zone_normal, 'www', {
- 'ttl': 60,
- 'type': 'A',
- 'value': '9.9.9.9',
- })
+ normal = Record.new(
+ zone_normal, 'www', {'ttl': 60, 'type': 'A', 'value': '9.9.9.9'}
+ )
zone_normal.add_record(normal)
- excluded = Record.new(zone_excluded, 'www', {
- 'octodns': {
- 'excluded': ['test']
+ excluded = Record.new(
+ zone_excluded,
+ 'www',
+ {
+ 'octodns': {'excluded': ['test']},
+ 'ttl': 60,
+ 'type': 'A',
+ 'value': '9.9.9.9',
},
- 'ttl': 60,
- 'type': 'A',
- 'value': '9.9.9.9',
- })
+ )
zone_excluded.add_record(excluded)
provider = SimpleProvider()
@@ -295,21 +305,21 @@ class TestZone(TestCase):
zone_included = Zone('unit.tests.', [])
zone_missing = Zone('unit.tests.', [])
- normal = Record.new(zone_normal, 'www', {
- 'ttl': 60,
- 'type': 'A',
- 'value': '9.9.9.9',
- })
+ normal = Record.new(
+ zone_normal, 'www', {'ttl': 60, 'type': 'A', 'value': '9.9.9.9'}
+ )
zone_normal.add_record(normal)
- included = Record.new(zone_included, 'www', {
- 'octodns': {
- 'included': ['test']
+ included = Record.new(
+ zone_included,
+ 'www',
+ {
+ 'octodns': {'included': ['test']},
+ 'ttl': 60,
+ 'type': 'A',
+ 'value': '9.9.9.9',
},
- 'ttl': 60,
- 'type': 'A',
- 'value': '9.9.9.9',
- })
+ )
zone_included.add_record(included)
provider = SimpleProvider()
@@ -328,21 +338,21 @@ class TestZone(TestCase):
zone_included = Zone('unit.tests.', [])
zone_missing = Zone('unit.tests.', [])
- normal = Record.new(zone_normal, 'www', {
- 'ttl': 60,
- 'type': 'A',
- 'value': '9.9.9.9',
- })
+ normal = Record.new(
+ zone_normal, 'www', {'ttl': 60, 'type': 'A', 'value': '9.9.9.9'}
+ )
zone_normal.add_record(normal)
- included = Record.new(zone_included, 'www', {
- 'octodns': {
- 'included': ['not-here']
+ included = Record.new(
+ zone_included,
+ 'www',
+ {
+ 'octodns': {'included': ['not-here']},
+ 'ttl': 60,
+ 'type': 'A',
+ 'value': '9.9.9.9',
},
- 'ttl': 60,
- 'type': 'A',
- 'value': '9.9.9.9',
- })
+ )
zone_included.add_record(included)
provider = SimpleProvider()
@@ -420,18 +430,20 @@ class TestZone(TestCase):
# No root NS yet
self.assertFalse(zone.root_ns)
- non_root_ns = NsRecord(zone, 'sub', {'ttl': 42, 'values': (
- 'ns1.unit.tests.',
- 'ns2.unit.tests.',
- )})
+ non_root_ns = NsRecord(
+ zone,
+ 'sub',
+ {'ttl': 42, 'values': ('ns1.unit.tests.', 'ns2.unit.tests.')},
+ )
zone.add_record(non_root_ns)
# No root NS yet b/c this was a sub
self.assertFalse(zone.root_ns)
- root_ns = NsRecord(zone, '', {'ttl': 42, 'values': (
- 'ns3.unit.tests.',
- 'ns4.unit.tests.',
- )})
+ root_ns = NsRecord(
+ zone,
+ '',
+ {'ttl': 42, 'values': ('ns3.unit.tests.', 'ns4.unit.tests.')},
+ )
zone.add_record(root_ns)
# Now we have a root NS
self.assertEqual(root_ns, zone.root_ns)
diff --git a/tests/zones/2.0.192.in-addr.arpa. b/tests/zones/2.0.192.in-addr.arpa.
new file mode 100644
index 0000000..baced8a
--- /dev/null
+++ b/tests/zones/2.0.192.in-addr.arpa.
@@ -0,0 +1,18 @@
+$ORIGIN 2.0.192.in-addr.arpa.
+@ 3600 IN SOA ns1.unit.tests. root.unit.tests. (
+ 2018071501 ; Serial
+ 3600 ; Refresh (1 hour)
+ 600 ; Retry (10 minutes)
+ 604800 ; Expire (1 week)
+ 3600 ; NXDOMAIN ttl (1 hour)
+ )
+
+; NS Records
+@ 3600 IN NS ns1.unit.tests.
+@ 3600 IN NS ns2.unit.tests.
+
+; PTR Records
+1 IN PTR foo-1.unit.tests.
+2 IN PTR foo-2.unit.tests.
+3 IN PTR foo-3.unit.tests.
+3 IN PTR foo-4.unit.tests.
|