]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
chore: reformat all Python files with ruff 16477/head
authorPieter Lexis <pieter.lexis@powerdns.com>
Fri, 13 Mar 2026 14:06:43 +0000 (15:06 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Fri, 13 Mar 2026 14:06:43 +0000 (15:06 +0100)
250 files changed:
.github/scripts/clang-tidy-diff.py
.github/scripts/clang-tidy.py
.github/scripts/git-filter.py
.github/scripts/normalize_paths_in_coverage.py
build-scripts/changelog-from-pr.py
build-scripts/cherry-pick-pr.py
build-scripts/docker/repo-test/generate-repo-files.py
build-scripts/test-sources-sorted.py
builder-support/helpers/generate-sbom-dnf.py
builder-support/helpers/update-rust-library-version.py
contrib/DNSDistLogActionReader.py
contrib/ProtobufLogger.py
contrib/assert-equal-DNSMessage/eqdnsmessage.py
contrib/xdp-logging.py
contrib/xdp.py
dockerdata/startup.py
docs/conf.py
docs/depfile.py
docs/generate-docs.py
docs/generate-man-pages.py
modules/remotebackend/pdns_unittest.py
modules/remotebackend/regression-tests/backend.py
modules/remotebackend/regression-tests/dnsbackend.py
modules/remotebackend/regression-tests/http-backend.py
modules/remotebackend/regression-tests/pipe-backend.py
modules/remotebackend/regression-tests/unix-backend.py
modules/remotebackend/regression-tests/zeromq-backend.py
modules/remotebackend/unittest_http.py
modules/remotebackend/unittest_json.py
modules/remotebackend/unittest_post.py
modules/remotebackend/unittest_zeromq.py
pdns/dnsdistdist/dnsdist-rules-generator.py
pdns/dnsdistdist/dnsdist-rust-lib/dnsdist-settings-generator.py
pdns/dnsdistdist/dnsdist-settings-documentation-generator.py
pdns/dnsdistdist/docs/conf.py
pdns/keyroller/pdns-keyroller-ctl.py
pdns/keyroller/pdns-keyroller.py
pdns/keyroller/pdnsapi/api.py
pdns/keyroller/pdnsapi/cryptokey.py
pdns/keyroller/pdnsapi/metadata.py
pdns/keyroller/pdnsapi/zone.py
pdns/keyroller/pdnskeyroller/__init__.py
pdns/keyroller/pdnskeyroller/config.py
pdns/keyroller/pdnskeyroller/daemon.py
pdns/keyroller/pdnskeyroller/domainconfig.py
pdns/keyroller/pdnskeyroller/domainstate.py
pdns/keyroller/pdnskeyroller/keyroll.py
pdns/keyroller/pdnskeyroller/keyrollerdomain.py
pdns/keyroller/pdnskeyroller/prepublishkeyroll.py
pdns/keyroller/pdnskeyroller/util.py
pdns/keyroller/setup.py
pdns/recursordist/docs/conf.py
pdns/recursordist/make-ext-symlinks.py
pdns/recursordist/metrics.py
pdns/recursordist/metrics_table.py
pdns/recursordist/rec-rust-lib/generate.py
pdns/recursordist/rec-rust-lib/table.py
regression-tests.api/runtests.py
regression-tests.api/test_Basics.py
regression-tests.api/test_Cache.py
regression-tests.api/test_Discovery.py
regression-tests.api/test_RecursorConfig.py
regression-tests.api/test_RecursorOTConditions.py
regression-tests.api/test_Servers.py
regression-tests.api/test_TSIG.py
regression-tests.api/test_Views.py
regression-tests.api/test_Zones.py
regression-tests.api/test_cryptokeys.py
regression-tests.api/test_helper.py
regression-tests.auth-py/authtests.py
regression-tests.auth-py/clientsubnetoption.py
regression-tests.auth-py/test_ALIAS.py
regression-tests.auth-py/test_AnyBind.py
regression-tests.auth-py/test_AuthSignal.py
regression-tests.auth-py/test_Carbon.py
regression-tests.auth-py/test_Cookies.py
regression-tests.auth-py/test_DirectDNSKEYSignature.py
regression-tests.auth-py/test_GSSTSIG.py
regression-tests.auth-py/test_IXFR.py
regression-tests.auth-py/test_LuaRecords.py
regression-tests.auth-py/test_LuaRecordsLMDB.py
regression-tests.auth-py/test_ProxyProtocol.py
regression-tests.auth-py/test_ResolveAcrossZones.py
regression-tests.auth-py/test_SVCB.py
regression-tests.auth-py/test_XFRIncomplete.py
regression-tests.auth-py/test_acl.py
regression-tests.common/proxyprotocol.py
regression-tests.dnsdist/clientsubnetoption.py
regression-tests.dnsdist/cookiesoption.py
regression-tests.dnsdist/dnscrypt.py
regression-tests.dnsdist/dnsdistDynBlockTests.py
regression-tests.dnsdist/dnsdistdohtests.py
regression-tests.dnsdist/dnsdisttests.py
regression-tests.dnsdist/doh3client.py
regression-tests.dnsdist/doqclient.py
regression-tests.dnsdist/proxyprotocolutils.py
regression-tests.dnsdist/quictests.py
regression-tests.dnsdist/randompaddingoption.py
regression-tests.dnsdist/test_API.py
regression-tests.dnsdist/test_AXFR.py
regression-tests.dnsdist/test_Advanced.py
regression-tests.dnsdist/test_Async.py
regression-tests.dnsdist/test_BackendDiscovery.py
regression-tests.dnsdist/test_Basics.py
regression-tests.dnsdist/test_BrokenAnswer.py
regression-tests.dnsdist/test_CDB.py
regression-tests.dnsdist/test_CacheHitResponses.py
regression-tests.dnsdist/test_CacheInsertedResponses.py
regression-tests.dnsdist/test_CacheMissActions.py
regression-tests.dnsdist/test_CachePadding.py
regression-tests.dnsdist/test_Caching.py
regression-tests.dnsdist/test_Carbon.py
regression-tests.dnsdist/test_CheckConfig.py
regression-tests.dnsdist/test_ConfigurationUpdates.py
regression-tests.dnsdist/test_Console.py
regression-tests.dnsdist/test_DNSCrypt.py
regression-tests.dnsdist/test_DNSParser.py
regression-tests.dnsdist/test_DOH.py
regression-tests.dnsdist/test_DOH3.py
regression-tests.dnsdist/test_DOQ.py
regression-tests.dnsdist/test_Deprecated.py
regression-tests.dnsdist/test_Dnstap.py
regression-tests.dnsdist/test_DynBlocks.py
regression-tests.dnsdist/test_DynBlocksEBPF.py
regression-tests.dnsdist/test_DynBlocksGroup.py
regression-tests.dnsdist/test_DynBlocksRatio.py
regression-tests.dnsdist/test_DynBlocksResponseBytes.py
regression-tests.dnsdist/test_DynBlocksServFail.py
regression-tests.dnsdist/test_EBPF.py
regression-tests.dnsdist/test_EDE.py
regression-tests.dnsdist/test_EDNSOptions.py
regression-tests.dnsdist/test_EDNSSelfGenerated.py
regression-tests.dnsdist/test_EdnsClientSubnet.py
regression-tests.dnsdist/test_HealthChecks.py
regression-tests.dnsdist/test_IncomingInterface.py
regression-tests.dnsdist/test_IncomingProtocol.py
regression-tests.dnsdist/test_LMDB.py
regression-tests.dnsdist/test_Lua.py
regression-tests.dnsdist/test_LuaFFI.py
regression-tests.dnsdist/test_Metrics.py
regression-tests.dnsdist/test_NetworkBindings.py
regression-tests.dnsdist/test_OCSP.py
regression-tests.dnsdist/test_OOOR.py
regression-tests.dnsdist/test_OpenTelemetryTracing.py
regression-tests.dnsdist/test_OutgoingDOH.py
regression-tests.dnsdist/test_OutgoingTLS.py
regression-tests.dnsdist/test_PoolManagement.py
regression-tests.dnsdist/test_Prometheus.py
regression-tests.dnsdist/test_Protobuf.py
regression-tests.dnsdist/test_ProxyProtocol.py
regression-tests.dnsdist/test_RE2.py
regression-tests.dnsdist/test_Randomized.py
regression-tests.dnsdist/test_RecordsCount.py
regression-tests.dnsdist/test_Responses.py
regression-tests.dnsdist/test_RestartQuery.py
regression-tests.dnsdist/test_Routing.py
regression-tests.dnsdist/test_RulesActions.py
regression-tests.dnsdist/test_SNI.py
regression-tests.dnsdist/test_SNMP.py
regression-tests.dnsdist/test_SVCB.py
regression-tests.dnsdist/test_SelfAnsweredResponses.py
regression-tests.dnsdist/test_Size.py
regression-tests.dnsdist/test_Spoofing.py
regression-tests.dnsdist/test_StructuredLogging.py
regression-tests.dnsdist/test_TCPFastOpen.py
regression-tests.dnsdist/test_TCPKeepAlive.py
regression-tests.dnsdist/test_TCPLimits.py
regression-tests.dnsdist/test_TCPOnly.py
regression-tests.dnsdist/test_TCPShort.py
regression-tests.dnsdist/test_TLS.py
regression-tests.dnsdist/test_TLSSessionResumption.py
regression-tests.dnsdist/test_Tags.py
regression-tests.dnsdist/test_TeeAction.py
regression-tests.dnsdist/test_TimedIPSet.py
regression-tests.dnsdist/test_TimeoutResponse.py
regression-tests.dnsdist/test_Trailing.py
regression-tests.dnsdist/test_Yaml.py
regression-tests.ixfrdist/ixfrdisttests.py
regression-tests.ixfrdist/test_CaseSensitiveTXT.py
regression-tests.ixfrdist/test_IXFR.py
regression-tests.ixfrdist/test_Stats.py
regression-tests.nobackend/edns1/test-edns.py
regression-tests.nobackend/negcache-tests-dotted-cname/pipe.py
regression-tests.recursor-dnssec/basicDNSSEC.py
regression-tests.recursor-dnssec/clientsubnetoption.py
regression-tests.recursor-dnssec/conftest.py
regression-tests.recursor-dnssec/extendederrors.py
regression-tests.recursor-dnssec/paddingoption.py
regression-tests.recursor-dnssec/printlogs.py
regression-tests.recursor-dnssec/recursortests.py
regression-tests.recursor-dnssec/test_API.py
regression-tests.recursor-dnssec/test_Additionals.py
regression-tests.recursor-dnssec/test_AggressiveNSECCache.py
regression-tests.recursor-dnssec/test_AnyBind.py
regression-tests.recursor-dnssec/test_Carbon.py
regression-tests.recursor-dnssec/test_Chain.py
regression-tests.recursor-dnssec/test_Cookies.py
regression-tests.recursor-dnssec/test_DNS64.py
regression-tests.recursor-dnssec/test_DoT.py
regression-tests.recursor-dnssec/test_ECS.py
regression-tests.recursor-dnssec/test_EDNS.py
regression-tests.recursor-dnssec/test_EDNSBufferSize.py
regression-tests.recursor-dnssec/test_EDNSPadding.py
regression-tests.recursor-dnssec/test_Expired.py
regression-tests.recursor-dnssec/test_ExtendedErrors.py
regression-tests.recursor-dnssec/test_FWCatz.py
regression-tests.recursor-dnssec/test_Flags.py
regression-tests.recursor-dnssec/test_ForwardOverDoT.py
regression-tests.recursor-dnssec/test_Interop.py
regression-tests.recursor-dnssec/test_KeepOpenTCP.py
regression-tests.recursor-dnssec/test_LockedCache.py
regression-tests.recursor-dnssec/test_Lua.py
regression-tests.recursor-dnssec/test_Malformed.py
regression-tests.recursor-dnssec/test_NTA.py
regression-tests.recursor-dnssec/test_NamedForward.py
regression-tests.recursor-dnssec/test_NoDS.py
regression-tests.recursor-dnssec/test_NoDSYAML.py
regression-tests.recursor-dnssec/test_NotYetValid.py
regression-tests.recursor-dnssec/test_Notify.py
regression-tests.recursor-dnssec/test_OOOTCP.py
regression-tests.recursor-dnssec/test_PacketCache.py
regression-tests.recursor-dnssec/test_Prometheus.py
regression-tests.recursor-dnssec/test_Protobuf.py
regression-tests.recursor-dnssec/test_ProxyByTable.py
regression-tests.recursor-dnssec/test_ProxyProtocol.py
regression-tests.recursor-dnssec/test_RDFlag.py
regression-tests.recursor-dnssec/test_RPZ.py
regression-tests.recursor-dnssec/test_RPZIncomplete.py
regression-tests.recursor-dnssec/test_ReadTrustAnchorsFromFile.py
regression-tests.recursor-dnssec/test_RecDnstap.py
regression-tests.recursor-dnssec/test_RootNXTrust.py
regression-tests.recursor-dnssec/test_RoutingTag.py
regression-tests.recursor-dnssec/test_SNMP.py
regression-tests.recursor-dnssec/test_ServerNames.py
regression-tests.recursor-dnssec/test_Simple.py
regression-tests.recursor-dnssec/test_SimpleCookies.py
regression-tests.recursor-dnssec/test_SimpleTCP.py
regression-tests.recursor-dnssec/test_SimpleYAML.py
regression-tests.recursor-dnssec/test_Sortlist.py
regression-tests.recursor-dnssec/test_TTL.py
regression-tests.recursor-dnssec/test_TraceFail.py
regression-tests.recursor-dnssec/test_TrustAnchors.py
regression-tests.recursor-dnssec/test_WellKnown.py
regression-tests.recursor-dnssec/test_ZTC.py
regression-tests.recursor-dnssec/test_basicNSEC.py
regression-tests.recursor-dnssec/test_basicNSEC3.py
regression-tests/bulktest-report.py
regression-tests/bulktest-to-json.py
regression-tests/tkey.py
tasks.py

index f00d5cf5602107ad7f7ab2983ce6b377610b4a7c..54ce7b2ac624064105175dc0eccde4551ef8ed0f 100755 (executable)
@@ -1,12 +1,12 @@
 #!/usr/bin/env python3
 #
-#===- clang-tidy-diff.py - ClangTidy Diff Checker -----------*- python -*--===#
+# ===- clang-tidy-diff.py - ClangTidy Diff Checker -----------*- python -*--===#
 #
 # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 # See https://llvm.org/LICENSE.txt for license information.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 #
-#===-----------------------------------------------------------------------===#
+# ===-----------------------------------------------------------------------===#
 
 r"""
 ClangTidy Diff Checker
@@ -39,11 +39,11 @@ import traceback
 from pathlib import Path
 
 try:
-  import yaml
+    import yaml
 except ImportError:
-  yaml = None
+    yaml = None
 
-is_py2 = sys.version[0] == '2'
+is_py2 = sys.version[0] == "2"
 
 if is_py2:
     import Queue as queue
@@ -52,232 +52,231 @@ else:
 
 
 def run_tidy(task_queue, lock, timeout):
-  watchdog = None
-  while True:
-    command = task_queue.get()
-    try:
-      proc = subprocess.Popen(command,
-                              stdout=subprocess.PIPE,
-                              stderr=subprocess.PIPE)
-
-      if timeout is not None:
-        watchdog = threading.Timer(timeout, proc.kill)
-        watchdog.start()
-
-      stdout, stderr = proc.communicate()
-
-      with lock:
-        sys.stdout.write(stdout.decode('utf-8') + '\n')
-        sys.stdout.flush()
-        if stderr:
-          sys.stderr.write(stderr.decode('utf-8') + '\n')
-          sys.stderr.flush()
-    except Exception as e:
-      with lock:
-        sys.stderr.write('Failed: ' + str(e) + ': '.join(command) + '\n')
-    finally:
-      with lock:
-        if not (timeout is None or watchdog is None):
-          if not watchdog.is_alive():
-              sys.stderr.write('Terminated by timeout: ' +
-                               ' '.join(command) + '\n')
-          watchdog.cancel()
-      task_queue.task_done()
+    watchdog = None
+    while True:
+        command = task_queue.get()
+        try:
+            proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+            if timeout is not None:
+                watchdog = threading.Timer(timeout, proc.kill)
+                watchdog.start()
+
+            stdout, stderr = proc.communicate()
+
+            with lock:
+                sys.stdout.write(stdout.decode("utf-8") + "\n")
+                sys.stdout.flush()
+                if stderr:
+                    sys.stderr.write(stderr.decode("utf-8") + "\n")
+                    sys.stderr.flush()
+        except Exception as e:
+            with lock:
+                sys.stderr.write("Failed: " + str(e) + ": ".join(command) + "\n")
+        finally:
+            with lock:
+                if not (timeout is None or watchdog is None):
+                    if not watchdog.is_alive():
+                        sys.stderr.write("Terminated by timeout: " + " ".join(command) + "\n")
+                    watchdog.cancel()
+            task_queue.task_done()
 
 
 def start_workers(max_tasks, tidy_caller, task_queue, lock, timeout):
-  for _ in range(max_tasks):
-    t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
-    t.daemon = True
-    t.start()
+    for _ in range(max_tasks):
+        t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout))
+        t.daemon = True
+        t.start()
 
 
 def merge_replacement_files(tmpdir, mergefile):
-  """Merge all replacement files in a directory into a single file"""
-  # The fixes suggested by clang-tidy >= 4.0.0 are given under
-  # the top level key 'Diagnostics' in the output yaml files
-  mergekey = "Diagnostics"
-  merged = []
-  for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')):
-    with open(replacefile, 'r') as f:
-      content = yaml.safe_load(f)
-    if not content:
-      continue # Skip empty files.
-    merged.extend(content.get(mergekey, []))
-
-  if merged:
-    # MainSourceFile: The key is required by the definition inside
-    # include/clang/Tooling/ReplacementsYaml.h, but the value
-    # is actually never used inside clang-apply-replacements,
-    # so we set it to '' here.
-    output = {'MainSourceFile': '', mergekey: merged}
-    with open(mergefile, 'w') as out:
-      yaml.safe_dump(output, out)
-  else:
-    # Empty the file:
-    open(mergefile, 'w').close()
+    """Merge all replacement files in a directory into a single file"""
+    # The fixes suggested by clang-tidy >= 4.0.0 are given under
+    # the top level key 'Diagnostics' in the output yaml files
+    mergekey = "Diagnostics"
+    merged = []
+    for replacefile in glob.iglob(os.path.join(tmpdir, "*.yaml")):
+        with open(replacefile, "r") as f:
+            content = yaml.safe_load(f)
+        if not content:
+            continue  # Skip empty files.
+        merged.extend(content.get(mergekey, []))
+
+    if merged:
+        # MainSourceFile: The key is required by the definition inside
+        # include/clang/Tooling/ReplacementsYaml.h, but the value
+        # is actually never used inside clang-apply-replacements,
+        # so we set it to '' here.
+        output = {"MainSourceFile": "", mergekey: merged}
+        with open(mergefile, "w") as out:
+            yaml.safe_dump(output, out)
+    else:
+        # Empty the file:
+        open(mergefile, "w").close()
 
 
 def main():
-  parser = argparse.ArgumentParser(description=
-                                   'Run clang-tidy against changed files, and '
-                                   'output diagnostics only for modified '
-                                   'lines.')
-  parser.add_argument('-clang-tidy-binary', metavar='PATH',
-                      default='clang-tidy',
-                      help='path to clang-tidy binary')
-  parser.add_argument('-p', metavar='NUM', default=0,
-                      help='strip the smallest prefix containing P slashes')
-  parser.add_argument('-regex', metavar='PATTERN', default=None,
-                      help='custom pattern selecting file paths to check '
-                      '(case sensitive, overrides -iregex)')
-  parser.add_argument('-iregex', metavar='PATTERN', default=
-                      r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)',
-                      help='custom pattern selecting file paths to check '
-                      '(case insensitive, overridden by -regex)')
-  parser.add_argument('-j', type=int, default=1,
-                      help='number of tidy instances to be run in parallel.')
-  parser.add_argument('-timeout', type=int, default=None,
-                      help='timeout per each file in seconds.')
-  parser.add_argument('-fix', action='store_true', default=False,
-                      help='apply suggested fixes')
-  parser.add_argument('-checks',
-                      help='checks filter, when not specified, use clang-tidy '
-                      'default',
-                      default='')
-  parser.add_argument('-use-color', action='store_true',
-                      help='Use colors in output')
-  parser.add_argument('-path', dest='build_path',
-                      help='Path used to read a compile command database.')
-  if yaml:
-    parser.add_argument('-export-fixes', metavar='FILE', dest='export_fixes',
-                        help='Create a yaml file to store suggested fixes in, '
-                        'which can be applied with clang-apply-replacements.')
-  parser.add_argument('-extra-arg', dest='extra_arg',
-                      action='append', default=[],
-                      help='Additional argument to append to the compiler '
-                      'command line.')
-  parser.add_argument('-extra-arg-before', dest='extra_arg_before',
-                      action='append', default=[],
-                      help='Additional argument to prepend to the compiler '
-                      'command line.')
-  parser.add_argument('-quiet', action='store_true', default=False,
-                      help='Run clang-tidy in quiet mode')
-  parser.add_argument('-load', dest='plugins',
-                      action='append', default=[],
-                      help='Load the specified plugin in clang-tidy.')
-
-  clang_tidy_args = []
-  argv = sys.argv[1:]
-  if '--' in argv:
-    clang_tidy_args.extend(argv[argv.index('--'):])
-    argv = argv[:argv.index('--')]
-
-  args = parser.parse_args(argv)
-
-  # Extract changed lines for each file.
-  filename = None
-  lines_by_file = {}
-  for line in sys.stdin:
-    match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
-    if match:
-      filename = match.group(2)
-    if filename is None:
-      continue
-
-    if args.regex is not None:
-      if not re.match('^%s$' % args.regex, filename):
-        continue
-    else:
-      if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
-        continue
-
-    match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
-    if match:
-      start_line = int(match.group(1))
-      line_count = 1
-      if match.group(3):
-        line_count = int(match.group(3))
-      if line_count == 0:
-        continue
-      end_line = start_line + line_count - 1
-      lines_by_file.setdefault(filename, []).append([start_line, end_line])
-
-  if not any(lines_by_file):
-    print("No relevant changes found.")
-    sys.exit(0)
-
-  max_task_count = args.j
-  if max_task_count == 0:
-      max_task_count = multiprocessing.cpu_count()
-  max_task_count = min(len(lines_by_file), max_task_count)
-
-  tmpdir = None
-  if yaml and args.export_fixes:
-    tmpdir = tempfile.mkdtemp()
-
-  # Tasks for clang-tidy.
-  task_queue = queue.Queue(max_task_count)
-  # A lock for console output.
-  lock = threading.Lock()
-
-  # Run a pool of clang-tidy workers.
-  start_workers(max_task_count, run_tidy, task_queue, lock, args.timeout)
-
-  # Form the common args list.
-  common_clang_tidy_args = []
-  if args.fix:
-    common_clang_tidy_args.append('-fix')
-  if args.checks != '':
-    common_clang_tidy_args.append('-checks=' + args.checks)
-  if args.quiet:
-    common_clang_tidy_args.append('-quiet')
-  if args.build_path is not None:
-    common_clang_tidy_args.append('-p=%s' % args.build_path)
-  if args.use_color:
-    common_clang_tidy_args.append('--use-color')
-  for arg in args.extra_arg:
-    common_clang_tidy_args.append('-extra-arg=%s' % arg)
-  for arg in args.extra_arg_before:
-    common_clang_tidy_args.append('-extra-arg-before=%s' % arg)
-  for plugin in args.plugins:
-    common_clang_tidy_args.append('-load=%s' % plugin)
-
-  for name in lines_by_file:
-    line_filter_json = json.dumps(
-      # clang-tidy only supports filenames in -line-filter, not paths
-      [{"name": Path(name).name, "lines": lines_by_file[name]}],
-      separators=(',', ':'))
-
-    # Run clang-tidy on files containing changes.
-    command = [args.clang_tidy_binary]
-    command.append('-line-filter=' + line_filter_json)
+    parser = argparse.ArgumentParser(
+        description="Run clang-tidy against changed files, and output diagnostics only for modified lines."
+    )
+    parser.add_argument("-clang-tidy-binary", metavar="PATH", default="clang-tidy", help="path to clang-tidy binary")
+    parser.add_argument("-p", metavar="NUM", default=0, help="strip the smallest prefix containing P slashes")
+    parser.add_argument(
+        "-regex",
+        metavar="PATTERN",
+        default=None,
+        help="custom pattern selecting file paths to check (case sensitive, overrides -iregex)",
+    )
+    parser.add_argument(
+        "-iregex",
+        metavar="PATTERN",
+        default=r".*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)",
+        help="custom pattern selecting file paths to check (case insensitive, overridden by -regex)",
+    )
+    parser.add_argument("-j", type=int, default=1, help="number of tidy instances to be run in parallel.")
+    parser.add_argument("-timeout", type=int, default=None, help="timeout per each file in seconds.")
+    parser.add_argument("-fix", action="store_true", default=False, help="apply suggested fixes")
+    parser.add_argument("-checks", help="checks filter, when not specified, use clang-tidy default", default="")
+    parser.add_argument("-use-color", action="store_true", help="Use colors in output")
+    parser.add_argument("-path", dest="build_path", help="Path used to read a compile command database.")
+    if yaml:
+        parser.add_argument(
+            "-export-fixes",
+            metavar="FILE",
+            dest="export_fixes",
+            help="Create a yaml file to store suggested fixes in, which can be applied with clang-apply-replacements.",
+        )
+    parser.add_argument(
+        "-extra-arg",
+        dest="extra_arg",
+        action="append",
+        default=[],
+        help="Additional argument to append to the compiler command line.",
+    )
+    parser.add_argument(
+        "-extra-arg-before",
+        dest="extra_arg_before",
+        action="append",
+        default=[],
+        help="Additional argument to prepend to the compiler command line.",
+    )
+    parser.add_argument("-quiet", action="store_true", default=False, help="Run clang-tidy in quiet mode")
+    parser.add_argument(
+        "-load", dest="plugins", action="append", default=[], help="Load the specified plugin in clang-tidy."
+    )
+
+    clang_tidy_args = []
+    argv = sys.argv[1:]
+    if "--" in argv:
+        clang_tidy_args.extend(argv[argv.index("--") :])
+        argv = argv[: argv.index("--")]
+
+    args = parser.parse_args(argv)
+
+    # Extract changed lines for each file.
+    filename = None
+    lines_by_file = {}
+    for line in sys.stdin:
+        match = re.search('^\+\+\+\ "?(.*?/){%s}([^ \t\n"]*)' % args.p, line)
+        if match:
+            filename = match.group(2)
+        if filename is None:
+            continue
+
+        if args.regex is not None:
+            if not re.match("^%s$" % args.regex, filename):
+                continue
+        else:
+            if not re.match("^%s$" % args.iregex, filename, re.IGNORECASE):
+                continue
+
+        match = re.search("^@@.*\+(\d+)(,(\d+))?", line)
+        if match:
+            start_line = int(match.group(1))
+            line_count = 1
+            if match.group(3):
+                line_count = int(match.group(3))
+            if line_count == 0:
+                continue
+            end_line = start_line + line_count - 1
+            lines_by_file.setdefault(filename, []).append([start_line, end_line])
+
+    if not any(lines_by_file):
+        print("No relevant changes found.")
+        sys.exit(0)
+
+    max_task_count = args.j
+    if max_task_count == 0:
+        max_task_count = multiprocessing.cpu_count()
+    max_task_count = min(len(lines_by_file), max_task_count)
+
+    tmpdir = None
+    if yaml and args.export_fixes:
+        tmpdir = tempfile.mkdtemp()
+
+    # Tasks for clang-tidy.
+    task_queue = queue.Queue(max_task_count)
+    # A lock for console output.
+    lock = threading.Lock()
+
+    # Run a pool of clang-tidy workers.
+    start_workers(max_task_count, run_tidy, task_queue, lock, args.timeout)
+
+    # Form the common args list.
+    common_clang_tidy_args = []
+    if args.fix:
+        common_clang_tidy_args.append("-fix")
+    if args.checks != "":
+        common_clang_tidy_args.append("-checks=" + args.checks)
+    if args.quiet:
+        common_clang_tidy_args.append("-quiet")
+    if args.build_path is not None:
+        common_clang_tidy_args.append("-p=%s" % args.build_path)
+    if args.use_color:
+        common_clang_tidy_args.append("--use-color")
+    for arg in args.extra_arg:
+        common_clang_tidy_args.append("-extra-arg=%s" % arg)
+    for arg in args.extra_arg_before:
+        common_clang_tidy_args.append("-extra-arg-before=%s" % arg)
+    for plugin in args.plugins:
+        common_clang_tidy_args.append("-load=%s" % plugin)
+
+    for name in lines_by_file:
+        line_filter_json = json.dumps(
+            # clang-tidy only supports filenames in -line-filter, not paths
+            [{"name": Path(name).name, "lines": lines_by_file[name]}],
+            separators=(",", ":"),
+        )
+
+        # Run clang-tidy on files containing changes.
+        command = [args.clang_tidy_binary]
+        command.append("-line-filter=" + line_filter_json)
+        if yaml and args.export_fixes:
+            # Get a temporary file. We immediately close the handle so clang-tidy can
+            # overwrite it.
+            (handle, tmp_name) = tempfile.mkstemp(suffix=".yaml", dir=tmpdir)
+            os.close(handle)
+            command.append("-export-fixes=" + tmp_name)
+        command.extend(common_clang_tidy_args)
+        command.append(name)
+        command.extend(clang_tidy_args)
+
+        task_queue.put(command)
+
+    # Wait for all threads to be done.
+    task_queue.join()
+
     if yaml and args.export_fixes:
-      # Get a temporary file. We immediately close the handle so clang-tidy can
-      # overwrite it.
-      (handle, tmp_name) = tempfile.mkstemp(suffix='.yaml', dir=tmpdir)
-      os.close(handle)
-      command.append('-export-fixes=' + tmp_name)
-    command.extend(common_clang_tidy_args)
-    command.append(name)
-    command.extend(clang_tidy_args)
-
-    task_queue.put(command)
-
-  # Wait for all threads to be done.
-  task_queue.join()
-
-  if yaml and args.export_fixes:
-    print('Writing fixes to ' + args.export_fixes + ' ...')
-    try:
-      merge_replacement_files(tmpdir, args.export_fixes)
-    except Exception:
-      sys.stderr.write('Error exporting fixes.\n')
-      traceback.print_exc()
-
-  if tmpdir:
-    shutil.rmtree(tmpdir)
-
-
-if __name__ == '__main__':
-  main()
+        print("Writing fixes to " + args.export_fixes + " ...")
+        try:
+            merge_replacement_files(tmpdir, args.export_fixes)
+        except Exception:
+            sys.stderr.write("Error exporting fixes.\n")
+            traceback.print_exc()
+
+    if tmpdir:
+        shutil.rmtree(tmpdir)
+
+
+if __name__ == "__main__":
+    main()
index b6ea649ba3c2f2557054b1eddfdd67e19556713d..c788e51ce692cbb9ded1b8882fd3157c922961ff 100755 (executable)
@@ -17,9 +17,7 @@ import helpers
 
 def create_argument_parser():
     """Create command-line argument parser."""
-    parser = argparse.ArgumentParser(
-        description="Convert clang-tidy output to Github Actions"
-    )
+    parser = argparse.ArgumentParser(description="Convert clang-tidy output to Github Actions")
     parser.add_argument(
         "--fixes-file",
         type=str,
@@ -68,11 +66,7 @@ def main():
 
         full_filename = filename
         full_filename = Path(full_filename)
-        full_filename = (
-            full_filename.as_posix()
-            if full_filename.is_absolute()
-            else os.path.join(directory, filename)
-        )
+        full_filename = full_filename.as_posix() if full_filename.is_absolute() else os.path.join(directory, filename)
 
         try:
             file_contents = helpers.load_file(full_filename)
index 46f605795ea4fd54f23b7066a9358e63dce763f2..bb2bddeca2676d38db4779e5f4238983348cbdeb 100755 (executable)
@@ -18,9 +18,7 @@ import unidiff
 
 def create_argument_parser():
     """Create command-line argument parser."""
-    parser = argparse.ArgumentParser(
-        description="Filter git diff files that are not in the product"
-    )
+    parser = argparse.ArgumentParser(description="Filter git diff files that are not in the product")
     parser.add_argument(
         "--product",
         type=str,
index 95092c1e0805039f3d45eb2be52b7be365069a7d..68535a53cf05a2d3c421016be6f3b3f5a6b4a1d3 100755 (executable)
@@ -6,24 +6,27 @@ from pathlib import Path
 
 DEBUG = False
 
+
 def debug_print(string):
     if DEBUG:
         print(string)
 
+
 def get_relative_to_product_source_dir(product, target):
-    if product == 'auth':
+    if product == "auth":
         # authoritative or tool
         return target
-    if product == 'recursor':
-        return os.path.join('pdns', 'recursordist', target)
-    if product == 'dnsdist':
-        return os.path.join('pdns', 'dnsdistdist', target)
+    if product == "recursor":
+        return os.path.join("pdns", "recursordist", target)
+    if product == "dnsdist":
+        return os.path.join("pdns", "dnsdistdist", target)
     return None
 
+
 def remove_meson_dist_path(product, target):
     # target looks like this: /tmp/dnsdist-meson-dist-build/meson-dist/dnsdist-0.0.0-git1/xsk.hh
     path = Path(target)
-    index = path.parts.index('meson-dist')
+    index = path.parts.index("meson-dist")
     # skip up to meson-dist and the directory below that,
     # so we now have: xsk.hh
     relevant = str(path.relative_to(path.parents[len(path.parts) - (index + 3)]))
@@ -34,20 +37,20 @@ def remove_dist_dir_path(repositoryRoot, version, target):
     # get rid of the distdir path, to get file paths as they are in the repository
     # if we are building from meson, it might look like this:
     # /__w/pdns/pdns/pdns/dnsdistdist/dnsdist-0.0.0-git1/config.h
-    if f'pdns-{version}' in target:
+    if f"pdns-{version}" in target:
         # authoritative or tool
-        authPath = os.path.join(repositoryRoot, f'pdns-{version}')
+        authPath = os.path.join(repositoryRoot, f"pdns-{version}")
         relativeToAuth = os.path.relpath(target, authPath)
-        target = get_relative_to_product_source_dir('auth', relativeToAuth)
+        target = get_relative_to_product_source_dir("auth", relativeToAuth)
         return target
-    if f'pdns-recursor-{version}' in target:
-        recPath = os.path.join(repositoryRoot, 'pdns', 'recursordist', f'pdns-recursor-{version}')
+    if f"pdns-recursor-{version}" in target:
+        recPath = os.path.join(repositoryRoot, "pdns", "recursordist", f"pdns-recursor-{version}")
         relativeToRec = os.path.relpath(target, recPath)
-        return get_relative_to_product_source_dir('recursor', relativeToRec)
-    if f'dnsdist-{version}' in target:
-        distPath = os.path.join(repositoryRoot, 'pdns', 'dnsdistdist', f'dnsdist-{version}')
+        return get_relative_to_product_source_dir("recursor", relativeToRec)
+    if f"dnsdist-{version}" in target:
+        distPath = os.path.join(repositoryRoot, "pdns", "dnsdistdist", f"dnsdist-{version}")
         relativeToDist = os.path.relpath(target, distPath)
-        target = get_relative_to_product_source_dir('dnsdist', relativeToDist)
+        target = get_relative_to_product_source_dir("dnsdist", relativeToDist)
         return target
 
     # let's assume we already have a full path to the repository, like
@@ -56,20 +59,21 @@ def remove_dist_dir_path(repositoryRoot, version, target):
     relativeToDist = os.path.relpath(target, distPath)
     return relativeToDist
 
+
 def process():
     repositoryRoot = os.path.realpath(sys.argv[1])
     product = sys.argv[2]
     version = sys.argv[3]
     inputFile = sys.argv[4]
     outputFile = sys.argv[5]
-    with open(inputFile, mode='r', encoding='utf-8') as inputFilePtr:
-        with open(outputFile, mode='w', encoding='utf-8') as outputFilePtr:
+    with open(inputFile, mode="r", encoding="utf-8") as inputFilePtr:
+        with open(outputFile, mode="w", encoding="utf-8") as outputFilePtr:
             for line in inputFilePtr:
-                if not line.startswith('SF:'):
+                if not line.startswith("SF:"):
                     outputFilePtr.write(line)
                     continue
 
-                parts = line.split(':')
+                parts = line.split(":")
                 if len(parts) != 2:
                     outputFilePtr.write(line)
                     continue
@@ -77,30 +81,31 @@ def process():
                 source_file = parts[1].rstrip()
                 # get rid of symbolic links
                 target = os.path.realpath(source_file)
-                debug_print(f'- Got source_file={source_file}, target={target}')
+                debug_print(f"- Got source_file={source_file}, target={target}")
 
-                if '/meson-dist/' in target:
+                if "/meson-dist/" in target:
                     # this is a file that comes from a meson dist tarball
                     target = remove_meson_dist_path(product, target)
-                    debug_print(f'meson-dist -> target={target}')
+                    debug_print(f"meson-dist -> target={target}")
                 else:
                     target = remove_dist_dir_path(repositoryRoot, version, target)
-                    debug_print(f'dist dir -> target={target}')
+                    debug_print(f"dist dir -> target={target}")
 
                 if target is None:
                     continue
 
                 # we need to properly map symbolic links
                 fullPath = os.path.join(repositoryRoot, target)
-                debug_print(f'fullPath is {fullPath}')
+                debug_print(f"fullPath is {fullPath}")
                 if os.path.islink(fullPath):
                     # get the link target
                     realPath = os.path.realpath(fullPath)
                     # and make it relative again
                     target = os.path.relpath(realPath, repositoryRoot)
 
-                debug_print(f'=> final target is {target}')
+                debug_print(f"=> final target is {target}")
                 outputFilePtr.write(f"SF:{target}\n")
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     process()
index 5c44b703ef767949c6bb75aee1f24dbcf2bbc28b..e6206421c1aeb964caa4a34fc742db1d501eaa8b 100755 (executable)
@@ -7,19 +7,18 @@ import re
 import getpass
 
 argp = argparse.ArgumentParser()
-argp.add_argument('--oneline', action='store_true',
-                  help='Make one-lined changelog entries (for 4.0 and older)')
-argp.add_argument('--username',
-                  help='Use the specified username for Basic Authentication to the GitHub API, allowing a higher rate limit')
-argp.add_argument('--access_token',
-                  help='Use API access token instead of username & password combination')
-argp.add_argument('pullrequest', metavar='PULL_REQUEST', nargs='+',
-                  help='Make changelogs for these Pull Request #\'s')
+argp.add_argument("--oneline", action="store_true", help="Make one-lined changelog entries (for 4.0 and older)")
+argp.add_argument(
+    "--username",
+    help="Use the specified username for Basic Authentication to the GitHub API, allowing a higher rate limit",
+)
+argp.add_argument("--access_token", help="Use API access token instead of username & password combination")
+argp.add_argument("pullrequest", metavar="PULL_REQUEST", nargs="+", help="Make changelogs for these Pull Request #'s")
 arguments = argp.parse_args()
 
-ticket_regex = re.compile(r'(?:[Cc]loses|[Ff]ixes)? #(\d+)')
+ticket_regex = re.compile(r"(?:[Cc]loses|[Ff]ixes)? #(\d+)")
 
-out = ''
+out = ""
 httpAuth = None
 if arguments.username:
     password = getpass.getpass("GitHub password for '" + arguments.username + "': ")
@@ -30,62 +29,61 @@ if arguments.username:
 access_token = arguments.access_token
 
 for pr in sorted(arguments.pullrequest):
-    if pr[0] == '#':
+    if pr[0] == "#":
         pr = pr[1:]
     try:
         if access_token:
-            res = requests.get('https://api.github.com/repos/PowerDNS/pdns/pulls/'
-                               '{}'.format(pr),
-                               headers={'Authorization': 'token ' + access_token})
+            res = requests.get(
+                "https://api.github.com/repos/PowerDNS/pdns/pulls/{}".format(pr),
+                headers={"Authorization": "token " + access_token},
+            )
         else:
-            res = requests.get('https://api.github.com/repos/PowerDNS/pdns/pulls/'
-                               '{}'.format(pr), auth=httpAuth)
+            res = requests.get("https://api.github.com/repos/PowerDNS/pdns/pulls/{}".format(pr), auth=httpAuth)
         pr_info = res.json()
     except (requests.exceptions.HTTPError, ValueError) as e:
         print(e)
         sys.exit(1)
 
     if arguments.oneline:
-        out += '- `#{pr} <{url}>`__: {title}'.format(
-            pr=pr, url=pr_info['html_url'], title=pr_info['title']
-        )
+        out += "- `#{pr} <{url}>`__: {title}".format(pr=pr, url=pr_info["html_url"], title=pr_info["title"])
     else:
-        out += '  .. change::\n' + \
-               '    :tags: XXXXXX\n' + \
-               '    :pullreq: {}\n'.format(pr)
-        body = pr_info.get('body', None)
-        if pr_info.get('message', None) and not body:
+        out += "  .. change::\n" + "    :tags: XXXXXX\n" + "    :pullreq: {}\n".format(pr)
+        body = pr_info.get("body", None)
+        if pr_info.get("message", None) and not body:
             # A bit blunt but better than we had.
-            print('{}'.format(pr_info['message']))
+            print("{}".format(pr_info["message"]))
             sys.exit(1)
         elif body:
             tickets = re.findall(ticket_regex, body)
             if len(tickets):
-                out += '    :tickets: {}\n'.format(', '.join(tickets))
-        out += '\n    {}'.format(pr_info['title'][0].capitalize() + pr_info['title'][1:])
+                out += "    :tickets: {}\n".format(", ".join(tickets))
+        out += "\n    {}".format(pr_info["title"][0].capitalize() + pr_info["title"][1:])
 
-    if pr_info['user']['login'].lower() not in ['habbie',
-                                                'rgacogne',
-                                                'aerique',
-                                                'chbruyand',
-                                                'omoerbeek',
-                                                'miodvallat']:
+    if pr_info["user"]["login"].lower() not in [
+        "habbie",
+        "rgacogne",
+        "aerique",
+        "chbruyand",
+        "omoerbeek",
+        "miodvallat",
+    ]:
         try:
             if access_token:
-                user_info = requests.get(pr_info['user']['url'],
-                                         headers={'Authorization': 'token ' + access_token}).json()
+                user_info = requests.get(
+                    pr_info["user"]["url"], headers={"Authorization": "token " + access_token}
+                ).json()
             else:
-                user_info = requests.get(pr_info['user']['url'], auth=httpAuth).json()
+                user_info = requests.get(pr_info["user"]["url"], auth=httpAuth).json()
         except (requests.exceptions.HTTPError, ValueError) as e:
             print(e)
             sys.exit(1)
-        if 'name' in user_info:
-            out += ' ({})'.format(user_info['name'])
+        if "name" in user_info:
+            out += " ({})".format(user_info["name"])
         else:
-            out += ' (@{})'.format(user_info['login'])
-    out += '\n'
+            out += " (@{})".format(user_info["login"])
+    out += "\n"
 
     if not arguments.oneline:
-        out += '\n'
+        out += "\n"
 
 print(out)
index 40c125e519aba6a06ac3bd4d388150bb8a13df42..9ff0633c9223f386394f99ba73d0a2b8282a23e5 100755 (executable)
@@ -8,9 +8,8 @@ import argparse
 
 def get_commits(pr):
     try:
-        res = requests.get('https://api.github.com/repos/PowerDNS/pdns/pulls/'
-                           '{}/commits'.format(pr)).json()
-        return [c['sha'] for c in res]
+        res = requests.get("https://api.github.com/repos/PowerDNS/pdns/pulls/{}/commits".format(pr)).json()
+        return [c["sha"] for c in res]
     except (ValueError, requests.exceptions.HTTPError) as e:
         print(e)
         sys.exit(1)
@@ -27,33 +26,46 @@ def run_command(cmd):
 a = argparse.ArgumentParser()
 action = a.add_mutually_exclusive_group(required=True)
 action.add_argument(
-    '-b', '--backport-unto', metavar='REF', nargs=1, help='Backport, using '
-    'cherry-pick, all commits from PULL_REQUEST onto REF. This is done on a '
+    "-b",
+    "--backport-unto",
+    metavar="REF",
+    nargs=1,
+    help="Backport, using "
+    "cherry-pick, all commits from PULL_REQUEST onto REF. This is done on a "
     'branch called "backport-PULL_REQUEST-to-basename(REF)". When the cherry-pick fails, solve '
-    'the conflict as usual and run "git cherry-pick --continue --allow-empty"')
+    'the conflict as usual and run "git cherry-pick --continue --allow-empty"',
+)
 action.add_argument(
-    '-m', '--merge-into', metavar='REF', nargs=1, help='Take the backport-'
-    'PULL_REQUEST branch and merge it into REF')
-a.add_argument(
-    'pull_request', metavar='PULL_REQUEST', type=int,
-    help='The PR number to backport')
+    "-m", "--merge-into", metavar="REF", nargs=1, help="Take the backport-PULL_REQUEST branch and merge it into REF"
+)
+a.add_argument("pull_request", metavar="PULL_REQUEST", type=int, help="The PR number to backport")
 
 args = a.parse_args()
 
 if args.backport_unto:
-    command = ['git', 'checkout', '-b',
-               'backport-{}-to-{}'.format(args.pull_request, args.backport_unto[0].split('/')[-1]), args.backport_unto[0]]
+    command = [
+        "git",
+        "checkout",
+        "-b",
+        "backport-{}-to-{}".format(args.pull_request, args.backport_unto[0].split("/")[-1]),
+        args.backport_unto[0],
+    ]
     run_command(command)
 
     commits = get_commits(args.pull_request)
-    command = ['git', 'cherry-pick', '-x', '--allow-empty'] + commits
+    command = ["git", "cherry-pick", "-x", "--allow-empty"] + commits
     run_command(command)
 
 if args.merge_into:
-    command = ['git', 'checkout', args.merge_into[0]]
+    command = ["git", "checkout", args.merge_into[0]]
     run_command(command)
 
-    command = ['git', 'merge', '--no-ff',
-               'backport-{}-to-{}'.format(args.pull_request, args.merge_into[0].split('/')[-1]), '-m',
-               'Backport #{}'.format(args.pull_request)]
+    command = [
+        "git",
+        "merge",
+        "--no-ff",
+        "backport-{}-to-{}".format(args.pull_request, args.merge_into[0].split("/")[-1]),
+        "-m",
+        "Backport #{}".format(args.pull_request),
+    ]
     run_command(command)
index e5336d7d882808434eff53d9d2eb332e5e1cbc22..96f7080bf612b8c98e67a4cf8adf08b4e886ca03 100755 (executable)
@@ -25,199 +25,276 @@ from jinja2 import Environment, FileSystemLoader
 
 # Globals
 
-g_version = '1.0.4'
+g_version = "1.0.4"
 
 g_verbose = False
 
-g_env = Environment(
-    loader=FileSystemLoader('templates/')
-)
+g_env = Environment(loader=FileSystemLoader("templates/"))
 
-g_dockerfile = 'Dockerfile.'
+g_dockerfile = "Dockerfile."
 g_run_output = False
 
 
 # Init Functions
 
+
 def init_argparser():
-    parser = argparse.ArgumentParser(description='Generate Docker files to ' +
-                                                 'test PowerDNS repositories.')
-    parser.add_argument('release', metavar='RELEASE',
-                        choices=[# Authoritative Server
-                                 'auth-48', 'auth-49', 'auth-50',
-                                 'auth-master',
-                                 # Recursor
-                                 'rec-48', 'rec-49', 'rec-50', 'rec-51', 'rec-52', 'rec-53',
-                                 'rec-54', 'rec-master',
-                                 # DNSDist
-                                 'dnsdist-17', 'dnsdist-18', 'dnsdist-19', 'dnsdist-20',
-                                 'dnsdist-21', 'dnsdist-master'],
-                        help='the release to generate Docker files for: ' +
-                             '%(choices)s')
-    parser.add_argument('--run-output', action='store_true',
-                        help='always show output from running a container')
-    parser.add_argument('--test', action='store_true',
-                        help='test the release')
-    parser.add_argument('--test-aarch64', action='store_true',
-                        help='test the release for ARM64')
-    parser.add_argument('--verbose', action='store_true',
-                        help='verbose output')
-    parser.add_argument('--version', action='store_true',
-                        help='print version')
+    parser = argparse.ArgumentParser(description="Generate Docker files to " + "test PowerDNS repositories.")
+    parser.add_argument(
+        "release",
+        metavar="RELEASE",
+        choices=[  # Authoritative Server
+            "auth-48",
+            "auth-49",
+            "auth-50",
+            "auth-master",
+            # Recursor
+            "rec-48",
+            "rec-49",
+            "rec-50",
+            "rec-51",
+            "rec-52",
+            "rec-53",
+            "rec-54",
+            "rec-master",
+            # DNSDist
+            "dnsdist-17",
+            "dnsdist-18",
+            "dnsdist-19",
+            "dnsdist-20",
+            "dnsdist-21",
+            "dnsdist-master",
+        ],
+        help="the release to generate Docker files for: " + "%(choices)s",
+    )
+    parser.add_argument("--run-output", action="store_true", help="always show output from running a container")
+    parser.add_argument("--test", action="store_true", help="test the release")
+    parser.add_argument("--test-aarch64", action="store_true", help="test the release for ARM64")
+    parser.add_argument("--verbose", action="store_true", help="verbose output")
+    parser.add_argument("--version", action="store_true", help="print version")
     return parser
 
 
 # Release File Functions
 
-def write_dockerfile (os, os_version, release):
-    tpl = g_env.get_template('Dockerfile-{}.jinja2'.format(os))
 
-    if os == 'raspbian':
-        os_image = 'resin/rpi-raspbian'
-    elif os == 'el':
-        os_image = 'oraclelinux'
+def write_dockerfile(os, os_version, release):
+    tpl = g_env.get_template("Dockerfile-{}.jinja2".format(os))
+
+    if os == "raspbian":
+        os_image = "resin/rpi-raspbian"
+    elif os == "el":
+        os_image = "oraclelinux"
     else:
         os_image = os
 
-    if release.startswith('auth-'):
-        if os in ('el'):
-            pkg = 'pdns'
+    if release.startswith("auth-"):
+        if os in ("el"):
+            pkg = "pdns"
         else:
-            pkg = 'pdns-server'
-        cmd = 'pdns_server'
-    elif release.startswith('rec-'):
-        pkg = 'pdns-recursor'
-        cmd = 'pdns_recursor'
-    elif release.startswith('dnsdist-'):
-        pkg = 'dnsdist'
-        cmd = 'dnsdist'
-
-    with open('{}{}.{}-{}'.format(g_dockerfile, release, os, os_version), 'w') as f:
+            pkg = "pdns-server"
+        cmd = "pdns_server"
+    elif release.startswith("rec-"):
+        pkg = "pdns-recursor"
+        cmd = "pdns_recursor"
+    elif release.startswith("dnsdist-"):
+        pkg = "dnsdist"
+        cmd = "dnsdist"
+
+    with open("{}{}.{}-{}".format(g_dockerfile, release, os, os_version), "w") as f:
         # This comment was in the template for the `--nobest` part but that makes
         # the template look even more different than the final output, so:
         #
         # > When should the logic be in the code and when in the template? :shrug:
         # > I prefer it to be in the code but I also do not want to add extra vars
         # > and logic to the code unless necessary.
-        f.write(tpl.render({ "os": os,
-                            "os_image": os_image,
-                            "os_version": os_version,
-                            "release": release,
-                            "cmd": cmd,
-                            "pkg": pkg }))
+        f.write(
+            tpl.render(
+                {"os": os, "os_image": os_image, "os_version": os_version, "release": release, "cmd": cmd, "pkg": pkg}
+            )
+        )
 
 
-def write_list_file (os, os_version, release):
-    tpl = g_env.get_template('pdns-list.jinja2')
+def write_list_file(os, os_version, release):
+    tpl = g_env.get_template("pdns-list.jinja2")
 
-    with open('pdns.list.{}.{}-{}'.format(release, os, os_version), 'w') as f:
-        f.write(tpl.render({ "os": os,
-                            "os_version": os_version,
-                            "release": release }))
+    with open("pdns.list.{}.{}-{}".format(release, os, os_version), "w") as f:
+        f.write(tpl.render({"os": os, "os_version": os_version, "release": release}))
 
 
-def write_pkg_pin_file (release):
-    tpl = g_env.get_template('pkg-pin.jinja2')
+def write_pkg_pin_file(release):
+    tpl = g_env.get_template("pkg-pin.jinja2")
 
-    if release.startswith('auth-') or  release.startswith('rec-'):
-        pkg = 'pdns-'
-    elif release.startswith('dnsdist-'):
-        pkg = 'dnsdist'
+    if release.startswith("auth-") or release.startswith("rec-"):
+        pkg = "pdns-"
+    elif release.startswith("dnsdist-"):
+        pkg = "dnsdist"
 
-    with open('pkg-pin', 'w') as f:
-       f.write(tpl.render({ "pkg": pkg }))
+    with open("pkg-pin", "w") as f:
+        f.write(tpl.render({"pkg": pkg}))
 
 
-def write_release_files (release):
+def write_release_files(release):
     if g_verbose:
         print("Writing release files...")
 
-    if release in ['auth-48', 'auth-49', 'auth-50', 'auth-master',
-                   'rec-48', 'rec-49', 'rec-50', 'rec-51', 'rec-52', 'rec-53',
-                   'rec-54', 'rec-master',
-                   'dnsdist-17', 'dnsdist-18', 'dnsdist-19', 'dnsdist-20',
-                   'dnsdist-21', 'dnsdist-master']:
+    if release in [
+        "auth-48",
+        "auth-49",
+        "auth-50",
+        "auth-master",
+        "rec-48",
+        "rec-49",
+        "rec-50",
+        "rec-51",
+        "rec-52",
+        "rec-53",
+        "rec-54",
+        "rec-master",
+        "dnsdist-17",
+        "dnsdist-18",
+        "dnsdist-19",
+        "dnsdist-20",
+        "dnsdist-21",
+        "dnsdist-master",
+    ]:
         write_pkg_pin_file(release)
-        write_dockerfile('el', '8', release)
-        write_dockerfile('el', '9', release)
-        write_dockerfile('debian', 'bullseye', release)
-        write_list_file('debian', 'bullseye', release)
-        if not release in ['auth-50', 'rec-54', 'rec-53', 'dnsdist-20', 'dnsdist-21']:
-            write_dockerfile('ubuntu', 'focal', release)
-            write_list_file('ubuntu', 'focal', release)
-        write_dockerfile('ubuntu', 'jammy', release)
-        write_list_file('ubuntu', 'jammy', release)
-
-    if release in ['auth-50', 'auth-master',
-                   'rec-53', 'rec-54', 'rec-master',
-                   'dnsdist-20', 'dnsdist-21', 'dnsdist-master']:
-        write_dockerfile('el', '10', release)
-
-    if release in ['auth-48', 'auth-49', 'auth-50', 'auth-master',
-                   'rec-48', 'rec-49', 'rec-50', 'rec-51', 'rec-52', 'rec-53',
-                   'rec-54', 'rec-master',
-                   'dnsdist-19', 'dnsdist-20', 'dnsdist-21', 'dnsdist-master']:
-        write_dockerfile('debian', 'bookworm', release)
-        write_list_file('debian', 'bookworm', release)
-
-    if release in ['auth-49', 'auth-50', 'auth-master',
-                   'rec-53', 'rec-54', 'rec-master',
-                   'dnsdist-20', 'dnsdist-21', 'dnsdist-master']:
-        write_dockerfile('debian', 'trixie', release)
-        write_list_file('debian', 'trixie', release)
-
-    if release in ['auth-49', 'auth-50', 'auth-master',
-                   'rec-50', 'rec-51', 'rec-52', 'rec-53', 'rec-54', 'rec-master',
-                   'dnsdist-19', 'dnsdist-20', 'dnsdist-21', 'dnsdist-master']:
-        write_dockerfile('ubuntu', 'noble', release)
-        write_list_file('ubuntu', 'noble', release)
+        write_dockerfile("el", "8", release)
+        write_dockerfile("el", "9", release)
+        write_dockerfile("debian", "bullseye", release)
+        write_list_file("debian", "bullseye", release)
+        if not release in ["auth-50", "rec-54", "rec-53", "dnsdist-20", "dnsdist-21"]:
+            write_dockerfile("ubuntu", "focal", release)
+            write_list_file("ubuntu", "focal", release)
+        write_dockerfile("ubuntu", "jammy", release)
+        write_list_file("ubuntu", "jammy", release)
+
+    if release in [
+        "auth-50",
+        "auth-master",
+        "rec-53",
+        "rec-54",
+        "rec-master",
+        "dnsdist-20",
+        "dnsdist-21",
+        "dnsdist-master",
+    ]:
+        write_dockerfile("el", "10", release)
+
+    if release in [
+        "auth-48",
+        "auth-49",
+        "auth-50",
+        "auth-master",
+        "rec-48",
+        "rec-49",
+        "rec-50",
+        "rec-51",
+        "rec-52",
+        "rec-53",
+        "rec-54",
+        "rec-master",
+        "dnsdist-19",
+        "dnsdist-20",
+        "dnsdist-21",
+        "dnsdist-master",
+    ]:
+        write_dockerfile("debian", "bookworm", release)
+        write_list_file("debian", "bookworm", release)
+
+    if release in [
+        "auth-49",
+        "auth-50",
+        "auth-master",
+        "rec-53",
+        "rec-54",
+        "rec-master",
+        "dnsdist-20",
+        "dnsdist-21",
+        "dnsdist-master",
+    ]:
+        write_dockerfile("debian", "trixie", release)
+        write_list_file("debian", "trixie", release)
+
+    if release in [
+        "auth-49",
+        "auth-50",
+        "auth-master",
+        "rec-50",
+        "rec-51",
+        "rec-52",
+        "rec-53",
+        "rec-54",
+        "rec-master",
+        "dnsdist-19",
+        "dnsdist-20",
+        "dnsdist-21",
+        "dnsdist-master",
+    ]:
+        write_dockerfile("ubuntu", "noble", release)
+        write_list_file("ubuntu", "noble", release)
+
 
 # Test Release Functions
 
-def build (dockerfile, arch='x86_64'):
+
+def build(dockerfile, arch="x86_64"):
     # Maybe create `determine_tag` function.
     if len(str(dockerfile)) <= len(g_dockerfile):
-        print('Unable to determine tag for {}'.format(dockerfile))
+        print("Unable to determine tag for {}".format(dockerfile))
         return (None, None)
-    tag = str(dockerfile)[len(g_dockerfile):]
-    print('Building Docker image using {}...'.format(dockerfile))
+    tag = str(dockerfile)[len(g_dockerfile) :]
+    print("Building Docker image using {}...".format(dockerfile))
     if g_verbose:
-        print('  - tag = {}'.format(tag))
-    if arch == 'x86_64':
-        cp = subprocess.run(['docker', 'build', '--no-cache', '--pull',
-                             '--file', dockerfile, '--tag', tag, '.'],
-                            capture_output=not(g_verbose))
+        print("  - tag = {}".format(tag))
+    if arch == "x86_64":
+        cp = subprocess.run(
+            ["docker", "build", "--no-cache", "--pull", "--file", dockerfile, "--tag", tag, "."],
+            capture_output=not (g_verbose),
+        )
     # not very subtle
-    elif arch == 'aarch64':
-        cp = subprocess.run(['docker', 'build', '--platform', 'linux/arm64/v8',
-                             '--no-cache', '--pull', '--file', dockerfile,
-                             '--tag', tag, '.'],
-                            capture_output=not(g_verbose))
+    elif arch == "aarch64":
+        cp = subprocess.run(
+            [
+                "docker",
+                "build",
+                "--platform",
+                "linux/arm64/v8",
+                "--no-cache",
+                "--pull",
+                "--file",
+                dockerfile,
+                "--tag",
+                tag,
+                ".",
+            ],
+            capture_output=not (g_verbose),
+        )
     # FIXME write failed output to log
     if cp.returncode != 0:
-        print('Error building {}: {}'.format(tag, repr(cp.returncode)))
-        return ( tag, cp.returncode )
-    return ( tag, cp.returncode )
+        print("Error building {}: {}".format(tag, repr(cp.returncode)))
+        return (tag, cp.returncode)
+    return (tag, cp.returncode)
 
 
-def run (tag, arch='x86_64'):
+def run(tag, arch="x86_64"):
     if g_run_output:
         capture_run_output = False
     else:
-        capture_run_output = not(g_verbose)
-    print('Running Docker container tagged {}...'.format(tag))
-    if arch == 'x86_64':
-        cp = subprocess.run(['docker', 'run', tag],
-                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        capture_run_output = not (g_verbose)
+    print("Running Docker container tagged {}...".format(tag))
+    if arch == "x86_64":
+        cp = subprocess.run(["docker", "run", tag], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
     # not very subtle
-    elif arch == 'aarch64':
-        cp = subprocess.run(['docker', 'run', '--platform', 'linux/arm64/v8',
-                             tag],
-                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-    _version = re.search(r'(PowerDNS Authoritative Server|PowerDNS Recursor|' +
-                        r'dnsdist) (\d+\.\d+\.\d+(-\w+)?[^ ]*)',
-                        cp.stdout.decode())
-    _features = re.search(r'[Ff]eatures: (.*)', cp.stdout.decode())
+    elif arch == "aarch64":
+        cp = subprocess.run(
+            ["docker", "run", "--platform", "linux/arm64/v8", tag], stdout=subprocess.PIPE, stderr=subprocess.STDOUT
+        )
+    _version = re.search(
+        r"(PowerDNS Authoritative Server|PowerDNS Recursor|" + r"dnsdist) (\d+\.\d+\.\d+(-\w+)?[^ ]*)",
+        cp.stdout.decode(),
+    )
+    _features = re.search(r"[Ff]eatures: (.*)", cp.stdout.decode())
 
     version = features = None
     if _version:
@@ -231,43 +308,54 @@ def run (tag, arch='x86_64'):
     # for some reason 99 is returned on  `cmd --version` :shrug:
     if cp.returncode != 0 and cp.returncode != 99:
         # FIXME write failed output to log
-        print('Error running {}: {}'.format(tag, repr(cp.returncode)))
+        print("Error running {}: {}".format(tag, repr(cp.returncode)))
 
     return cp.returncode, version, features
 
 
-def collect_dockerfiles (release):
+def collect_dockerfiles(release):
     if g_verbose:
-        print('Collecting release files for {}...'.format(release))
-    p = Path('.')
-    files = list(p.glob('{}{}.*'.format(g_dockerfile, release)))
+        print("Collecting release files for {}...".format(release))
+    p = Path(".")
+    files = list(p.glob("{}{}.*".format(g_dockerfile, release)))
     if g_verbose:
         for file in files:
-            print('  - {}'.format(file))
+            print("  - {}".format(file))
     return files
 
 
-def test_release (release, arch='x86_64'):
+def test_release(release, arch="x86_64"):
     # sorted because we want determinism
     dockerfiles = sorted(collect_dockerfiles(release))
     failed_builds = []
     failed_runs = []
     returned_versions = []
-    print('=== testing {} ({}) ==='.format(release, arch))
+    print("=== testing {} ({}) ===".format(release, arch))
     for df in dockerfiles:
-        if arch == 'aarch64' and not release in ['auth-50', 'auth-49',
-                                                 'rec-49', 'rec-50', 'rec-51', 'rec-52', 'rec-53', 'rec-54', 'rec-master',
-                                                 'dnsdist-19', 'dnsdist-20', 'dnsdist-21', 'dnsdist-master']:
+        if arch == "aarch64" and not release in [
+            "auth-50",
+            "auth-49",
+            "rec-49",
+            "rec-50",
+            "rec-51",
+            "rec-52",
+            "rec-53",
+            "rec-54",
+            "rec-master",
+            "dnsdist-19",
+            "dnsdist-20",
+            "dnsdist-21",
+            "dnsdist-master",
+        ]:
             continue
         if g_verbose:
-            print('--- {} ---'.format(df))
+            print("--- {} ---".format(df))
         (tag, returncode) = build(df, arch)
         if returncode != 0:
-            print('Skipping running {} due to build error: {}'
-                  .format(df, returncode))
+            print("Skipping running {} due to build error: {}".format(df, returncode))
             failed_builds.append((str(df), returncode))
         elif tag is None:
-            print('Skipping running {} due to undetermined tag.'.format(df))
+            print("Skipping running {} due to undetermined tag.".format(df))
             failed_builds.append((str(df), returncode))
         else:
             (returncode, return_version, return_features) = run(tag, arch)
@@ -277,21 +365,21 @@ def test_release (release, arch='x86_64'):
                 failed_runs.append((tag, returncode))
             if return_version:
                 returned_versions.append((tag, return_version, return_features))
-    print('Test done.')
+    print("Test done.")
     if len(failed_builds) > 0:
-        print('- failed builds:')
+        print("- failed builds:")
         for fb in failed_builds:
-            print('    - {}'.format(fb))
+            print("    - {}".format(fb))
     if len(failed_runs) > 0:
-        print('- failed runs:')
+        print("- failed runs:")
         for fr in failed_runs:
-            print('    - {}'.format(fr))
+            print("    - {}".format(fr))
     if len(returned_versions) > 0:
-        print('- returned versions:')
+        print("- returned versions:")
         for rv in returned_versions:
-            print('    - {}: {} ({})'.format(rv[0], rv[1], rv[2]))
+            print("    - {}: {} ({})".format(rv[0], rv[1], rv[2]))
     else:
-        print('- ERROR: no returned versions (unsupported product?)')
+        print("- ERROR: no returned versions (unsupported product?)")
 
 
 # Main Program
@@ -300,7 +388,7 @@ parser = init_argparser()
 args = parser.parse_args()
 
 if args.version:
-    print('generate-repo-files v' + g_version)
+    print("generate-repo-files v" + g_version)
     sys.exit(0)
 
 if args.verbose:
@@ -315,4 +403,4 @@ if args.test:
     test_release(args.release)
 
 if args.test_aarch64:
-    test_release(args.release, 'aarch64')
+    test_release(args.release, "aarch64")
index 8476dfb894349af4401b2fffbced9c5e7e78d0cc..214aae7a38409021cd4619a4d304c4b4244e98af 100755 (executable)
@@ -3,7 +3,7 @@
 import re
 import sys
 
-REGEX = re.compile(r'(?s)[a-z0-9][a-z0-9_]+_SOURCES ?= ?\\.*?^$', re.MULTILINE)
+REGEX = re.compile(r"(?s)[a-z0-9][a-z0-9_]+_SOURCES ?= ?\\.*?^$", re.MULTILINE)
 
 
 def test_sources(fname) -> int:
@@ -15,14 +15,13 @@ def test_sources(fname) -> int:
     ret = 0
     for match in matches:
         lines = match.split(" \\\n\t")
-        elem = lines[0].rstrip(' =')
+        elem = lines[0].rstrip(" =")
         lines = lines[1:]
         sorted_lines = sorted(lines)
 
         if sorted_lines != lines:
             ret = 1
-            print(f'Source files for {elem} in {fname} is not sorted properly'
-                  .format(elem=elem, fname=fname))
+            print(f"Source files for {elem} in {fname} is not sorted properly".format(elem=elem, fname=fname))
     return ret
 
 
index 8915d148868274f77d97a7fd139d322e1a865df2..713e39a45c640c3a80f019bc4af97a16ae63936b 100755 (executable)
@@ -3,6 +3,7 @@
 This script uses dnf to generate a Software Bill of Materials
 (SBOM) in CycloneDX JSON format.
 """
+
 import datetime
 import json
 import os
@@ -11,77 +12,84 @@ import uuid
 
 import dnf
 
+
 def licenseToSPDXIdentifier(licenseName):
     licenseMap = {
-        'BSD': 'BSD-3-Clause',
-        'GPLv2': 'GPL-2.0-only',
-        'GPLv2+': 'GPL-2.0-or-later',
-        'LGPLv2+': 'LGPL-2.0-or-later',
-        'MIT': 'MIT',
-        'OpenLDAP': 'OLDAP-2.8',
-        }
+        "BSD": "BSD-3-Clause",
+        "GPLv2": "GPL-2.0-only",
+        "GPLv2+": "GPL-2.0-or-later",
+        "LGPLv2+": "LGPL-2.0-or-later",
+        "MIT": "MIT",
+        "OpenLDAP": "OLDAP-2.8",
+    }
     if licenseName in licenseMap:
         return licenseMap[licenseName]
     return None
 
+
 def getPackageDatabase():
     with dnf.Base() as db:
         conf = db.conf
-        conf.installroot = '/'
-        conf.substitutions.update_from_etc('/')
+        conf.installroot = "/"
+        conf.substitutions.update_from_etc("/")
         db.read_all_repos()
 
-        db.fill_sack(load_system_repo='auto', load_available_repos=True)
+        db.fill_sack(load_system_repo="auto", load_available_repos=True)
         query = db.sack.query()
         return query.installed()
 
+
 def getPURL(pkg):
     # from https://github.com/package-url/purl-spec/blob/main/types-doc/rpm-definition.md
     # pkg:rpm/<namespace>/<name>@<version>?<qualifiers>#<subpath>
     name = pkg.name
     version = pkg.version
-    if hasattr(pkg, 'cargo'):
-        return f'pkg:cargo/{name}@{version}'
+    if hasattr(pkg, "cargo"):
+        return f"pkg:cargo/{name}@{version}"
 
     vendor = pkg.vendor.lower()
-    if vendor == 'oracle america':
-        vendor = 'oracle'
-    elif vendor == 'rocky enterprise software foundation':
-        vendor = 'rocky'
-    elif vendor == 'fedora project':
-        vendor = 'fedora'
+    if vendor == "oracle america":
+        vendor = "oracle"
+    elif vendor == "rocky enterprise software foundation":
+        vendor = "rocky"
+    elif vendor == "fedora project":
+        vendor = "fedora"
 
     if pkg.release:
-        version += '-' + pkg.release
-    qualifiers = ''
-    if hasattr(pkg, 'arch'):
+        version += "-" + pkg.release
+    qualifiers = ""
+    if hasattr(pkg, "arch"):
         if len(qualifiers) != 0:
-            qualifiers += '&'
-        qualifiers += 'arch=' + pkg.arch
+            qualifiers += "&"
+        qualifiers += "arch=" + pkg.arch
     if pkg.epoch != 0:
         if len(qualifiers) != 0:
-            qualifiers += '&'
-        qualifiers += 'epoch=' + str(pkg.epoch)
-    return f'pkg:rpm/{vendor}/{name}@{version}?{qualifiers}'
+            qualifiers += "&"
+        qualifiers += "epoch=" + str(pkg.epoch)
+    return f"pkg:rpm/{vendor}/{name}@{version}?{qualifiers}"
+
 
 def getPackageInformations(pkgDB, packageName):
     matches = pkgDB.filter(name=packageName).run()
     if len(matches) == 0:
-        print(f'-> Package {packageName} not found')
+        print(f"-> Package {packageName} not found")
         return None
     return matches[0]
 
+
 def getPackageVersion(pkg):
     if pkg.release:
-        version = (pkg.version if pkg.epoch == 0 else str(pkg.epoch) + ':' + pkg.version) + '-' + pkg.release
+        version = (pkg.version if pkg.epoch == 0 else str(pkg.epoch) + ":" + pkg.version) + "-" + pkg.release
     else:
-        version = (pkg.version if pkg.epoch == 0 else str(pkg.epoch) + ':' + pkg.version)
-    if hasattr(pkg, 'arch'):
-        version += '.' + pkg.arch
+        version = pkg.version if pkg.epoch == 0 else str(pkg.epoch) + ":" + pkg.version
+    if hasattr(pkg, "arch"):
+        version += "." + pkg.arch
     return version
 
+
 def getLibraryBOMReference(pkg):
-    return 'lib:' + pkg.name + '_' + getPackageVersion(pkg)
+    return "lib:" + pkg.name + "_" + getPackageVersion(pkg)
+
 
 def addDependencyToSBOM(sbom, pkg, seen_deps):
     version = getPackageVersion(pkg)
@@ -91,40 +99,41 @@ def addDependencyToSBOM(sbom, pkg, seen_deps):
 
     seen_deps[bom_ref] = True
 
-    component = { 'name': pkg.name, 'bom-ref': bom_ref, 'type': 'library', 'version': version}
-
-    if hasattr(pkg, 'vendor') and pkg.vendor is not None:
-        component['supplier'] = {'name': pkg.vendor}
-    if hasattr(pkg, 'publisher') and pkg.publisher is not None:
-        component['publisher'] = pkg.publisher
-    if hasattr(pkg, 'author') and pkg.author is not None:
-        component['author'] = pkg.author
-    if hasattr(pkg, 'purl'):
-        component['purl'] = pkg.purl
-    if hasattr(pkg, 'externalReferences'):
-        component['externalReferences'] = pkg.externalReferences
+    component = {"name": pkg.name, "bom-ref": bom_ref, "type": "library", "version": version}
+
+    if hasattr(pkg, "vendor") and pkg.vendor is not None:
+        component["supplier"] = {"name": pkg.vendor}
+    if hasattr(pkg, "publisher") and pkg.publisher is not None:
+        component["publisher"] = pkg.publisher
+    if hasattr(pkg, "author") and pkg.author is not None:
+        component["author"] = pkg.author
+    if hasattr(pkg, "purl"):
+        component["purl"] = pkg.purl
+    if hasattr(pkg, "externalReferences"):
+        component["externalReferences"] = pkg.externalReferences
     spdx_license = licenseToSPDXIdentifier(pkg.license)
     if spdx_license is None:
-        component['licenses'] = [{'license': {'name': pkg.license}}]
+        component["licenses"] = [{"license": {"name": pkg.license}}]
     else:
-        component['licenses'] = [{'license': {'id': spdx_license}}]
-    if hasattr(pkg, 'sha256') and pkg.sha256 is not None:
-        component['hashes'] = [{'alg': 'SHA-256', 'content': pkg.sha256}]
-    component['purl'] = getPURL(pkg)
+        component["licenses"] = [{"license": {"id": spdx_license}}]
+    if hasattr(pkg, "sha256") and pkg.sha256 is not None:
+        component["hashes"] = [{"alg": "SHA-256", "content": pkg.sha256}]
+    component["purl"] = getPURL(pkg)
 
-    sbom['components'].append(component)
+    sbom["components"].append(component)
     return True
 
+
 def processDependencies(pkg_db, sbom, appInfos, depRelations, seen_deps):
     for require in appInfos.requires:
-        if hasattr(require, 'name'):
-            depName = require.name.split('(')[0]
+        if hasattr(require, "name"):
+            depName = require.name.split("(")[0]
             depSpec = require.name
         else:
             # hawkey.Reldep, el-8
-            depName = str(require).split('(', maxsplit=1)[0]
+            depName = str(require).split("(", maxsplit=1)[0]
             depSpec = require
-        if depName in ['/bin/sh', 'config', 'ld-linux-x86-64.so.2', 'rpmlib', 'rtld']:
+        if depName in ["/bin/sh", "config", "ld-linux-x86-64.so.2", "rpmlib", "rtld"]:
             continue
         if depName in seen_deps:
             continue
@@ -135,16 +144,17 @@ def processDependencies(pkg_db, sbom, appInfos, depRelations, seen_deps):
             flags = []
             matches = pkg_db.filter(*flags, provides__glob=[depSpec]).run()
             if len(matches) == 0:
-                print(f'Unable to find a match for {depName}')
+                print(f"Unable to find a match for {depName}")
                 continue
         if len(matches) > 1:
-            print(f'Got {len(matches)} matches for {depName}')
+            print(f"Got {len(matches)} matches for {depName}")
 
         dep = matches[0]
         depRef = getLibraryBOMReference(dep)
 
         if addDependencyToSBOM(sbom, dep, seen_deps):
-            depRelations['pkg:' + appInfos.name].append(depRef)
+            depRelations["pkg:" + appInfos.name].append(depRef)
+
 
 class StaticLibDep:
     def __init__(self, name, version, description, purl, external_refs, author, license_, sha256):
@@ -166,106 +176,143 @@ class StaticLibDep:
             self.sha256 = sha256
         self.cargo = True
 
+
 def mergeLibSBOM(sbom, appInfos, lib_sbom_path, depRelations, seen_deps):
     with open(lib_sbom_path, encoding="utf-8") as fd:
         lib_sbom_data = json.load(fd)
-        component = lib_sbom_data['metadata']['component']
-        main_component_name = component['name']
-        pkg = StaticLibDep(main_component_name, component['version'], component['description'], component.get('purl'), component.get('externalReferences') or [], component.get('author') or None, component['licenses'][0]['expression'], component['hashes'][0]['content'] if 'hashes' in component else None)
+        component = lib_sbom_data["metadata"]["component"]
+        main_component_name = component["name"]
+        pkg = StaticLibDep(
+            main_component_name,
+            component["version"],
+            component["description"],
+            component.get("purl"),
+            component.get("externalReferences") or [],
+            component.get("author") or None,
+            component["licenses"][0]["expression"],
+            component["hashes"][0]["content"] if "hashes" in component else None,
+        )
 
         addDependencyToSBOM(sbom, pkg, seen_deps)
-        depRef = 'lib:' + pkg.name
-        depRelations['pkg:' + appInfos.name].append(depRef)
+        depRef = "lib:" + pkg.name
+        depRelations["pkg:" + appInfos.name].append(depRef)
 
-        sub_components = lib_sbom_data['components']
+        sub_components = lib_sbom_data["components"]
         for component in sub_components:
-            pkg = StaticLibDep(component['name'], component['version'], None, component.get('purl'), component.get('externalReferences') or [], component.get('author') or None, component['licenses'][0]['expression'], component['hashes'][0]['content'] if 'hashes' in component else None)
+            pkg = StaticLibDep(
+                component["name"],
+                component["version"],
+                None,
+                component.get("purl"),
+                component.get("externalReferences") or [],
+                component.get("author") or None,
+                component["licenses"][0]["expression"],
+                component["hashes"][0]["content"] if "hashes" in component else None,
+            )
 
             addDependencyToSBOM(sbom, pkg, seen_deps)
             depRef = getLibraryBOMReference(pkg)
-            if not 'lib:' + main_component_name in depRelations:
-                depRelations['lib:' + main_component_name] = []
-            depRelations['lib:' + main_component_name].append(depRef)
+            if not "lib:" + main_component_name in depRelations:
+                depRelations["lib:" + main_component_name] = []
+            depRelations["lib:" + main_component_name].append(depRef)
+
 
 def addAdditionalLibraryToSBOM(depFile, sbom, appInfos, depRelations, seen_deps):
     with open(depFile, encoding="utf-8") as depDataFile:
         depData = json.load(depDataFile)
-        pkg = StaticLibDep(os.path.splitext(os.path.basename(depFile))[0], depData['version'], None, None, [], None, depData.get('license') or None, None)
-        pkg.supplier = 'PowerDNS.COM BV'
-        if 'publisher' in depData:
-            pkg.publisher = depData['publisher']
-        if 'SHA256SUM' in depData:
-            pkg.sha256 = depData['SHA256SUM']
-        elif 'SHA256SUM_x86_64' in depData:
-            pkg.sha256 = depData['SHA256SUM_x86_64']
-        if 'cargo-based' in depData:
-            pkg.cargo = depData['cargo-based']
-
-        depRef = 'lib:' + pkg.name
+        pkg = StaticLibDep(
+            os.path.splitext(os.path.basename(depFile))[0],
+            depData["version"],
+            None,
+            None,
+            [],
+            None,
+            depData.get("license") or None,
+            None,
+        )
+        pkg.supplier = "PowerDNS.COM BV"
+        if "publisher" in depData:
+            pkg.publisher = depData["publisher"]
+        if "SHA256SUM" in depData:
+            pkg.sha256 = depData["SHA256SUM"]
+        elif "SHA256SUM_x86_64" in depData:
+            pkg.sha256 = depData["SHA256SUM_x86_64"]
+        if "cargo-based" in depData:
+            pkg.cargo = depData["cargo-based"]
+
+        depRef = "lib:" + pkg.name
         addDependencyToSBOM(sbom, pkg, seen_deps)
-        depRelations['pkg:' + appInfos.name].append(depRef)
+        depRelations["pkg:" + appInfos.name].append(depRef)
+
 
 def processAdditionalDependencies(sbom, appInfos, additionalDeps, depRelations, seen_deps):
     for additionalDepFile in additionalDeps:
-        if additionalDepFile.endswith('cdx.json'):
+        if additionalDepFile.endswith("cdx.json"):
             mergeLibSBOM(sbom, appInfos, additionalDepFile, depRelations, seen_deps)
         else:
             addAdditionalLibraryToSBOM(additionalDepFile, sbom, appInfos, depRelations, seen_deps)
 
+
 def generateSBOM(packageName, additionalDeps):
-    sbom = { 'bomFormat': 'CycloneDX', 'specVersion': '1.5', 'version': 1 }
-    sbom['serialNumber'] = 'urn:uuid:' + str(uuid.uuid4())
+    sbom = {"bomFormat": "CycloneDX", "specVersion": "1.5", "version": 1}
+    sbom["serialNumber"] = "urn:uuid:" + str(uuid.uuid4())
     depRelations = {}
 
     pkg_db = getPackageDatabase()
     appName = packageName
     appInfos = getPackageInformations(pkg_db, packageName)
-    component = { 'name': appName, 'bom-ref': 'pkg:' + appName, 'type': 'application'}
+    component = {"name": appName, "bom-ref": "pkg:" + appName, "type": "application"}
 
     version = appInfos.version
-    qualifiers = ''
+    qualifiers = ""
     if appInfos.release:
-        version += '-' + appInfos.release
+        version += "-" + appInfos.release
     version_without_epoch_or_arch = version
 
-    if hasattr(appInfos, 'arch'):
-        version += '.' + appInfos.arch
+    if hasattr(appInfos, "arch"):
+        version += "." + appInfos.arch
         if len(qualifiers) != 0:
-            qualifiers += '&'
-        qualifiers += 'arch=' + appInfos.arch
+            qualifiers += "&"
+        qualifiers += "arch=" + appInfos.arch
 
     if appInfos.epoch != 0:
-        version = str(appInfos.epoch) + ':' + version
+        version = str(appInfos.epoch) + ":" + version
         if len(qualifiers) != 0:
-            qualifiers += '&'
-        qualifiers += 'epoch=' + str(appInfos.epoch)
+            qualifiers += "&"
+        qualifiers += "epoch=" + str(appInfos.epoch)
 
-    component['version'] = version
+    component["version"] = version
 
-    component['supplier'] = {'name': appInfos.vendor if appInfos.vendor != '<NULL>' else 'PowerDNS.COM BV', 'url': ['https://www.powerdns.com']}
-    component['licenses'] = [{'license': {'id': licenseToSPDXIdentifier(appInfos.license)}}]
-    component['purl'] = f'pkg:rpm/powerdns/{appName}@{version_without_epoch_or_arch}?{qualifiers}'
+    component["supplier"] = {
+        "name": appInfos.vendor if appInfos.vendor != "<NULL>" else "PowerDNS.COM BV",
+        "url": ["https://www.powerdns.com"],
+    }
+    component["licenses"] = [{"license": {"id": licenseToSPDXIdentifier(appInfos.license)}}]
+    component["purl"] = f"pkg:rpm/powerdns/{appName}@{version_without_epoch_or_arch}?{qualifiers}"
 
-    depRelations['pkg:' + appName] = []
+    depRelations["pkg:" + appName] = []
 
-    sbom['metadata'] = { 'timestamp': datetime.datetime.now(tz=datetime.timezone.utc).isoformat(),
-                         'authors': [{'name': 'PowerDNS.COM BV'}],
-                         'component': component }
-    sbom['components'] = []
-    sbom['dependencies'] = []
+    sbom["metadata"] = {
+        "timestamp": datetime.datetime.now(tz=datetime.timezone.utc).isoformat(),
+        "authors": [{"name": "PowerDNS.COM BV"}],
+        "component": component,
+    }
+    sbom["components"] = []
+    sbom["dependencies"] = []
 
     seen_deps = {}
     processDependencies(pkg_db, sbom, appInfos, depRelations, seen_deps)
     processAdditionalDependencies(sbom, appInfos, additionalDeps, depRelations, seen_deps)
 
     for pkg, deps in depRelations.items():
-        sbom['dependencies'].append({'ref': pkg, 'dependsOn': deps})
+        sbom["dependencies"].append({"ref": pkg, "dependsOn": deps})
 
     return sbom
 
+
 if __name__ == "__main__":
     if len(sys.argv) < 3:
-        sys.exit(f'Usage: {sys.argv[0]} <output file> <package> [static dependencies ...]')
+        sys.exit(f"Usage: {sys.argv[0]} <output file> <package> [static dependencies ...]")
 
     staticDeps = []
     if len(sys.argv) > 3:
index b8b0a0af953e571bf37435be854082e7038e689e..1c1957b2fcb6033259362a385589f15b787b73b0 100755 (executable)
@@ -6,9 +6,10 @@ import sys
 import tempfile
 import re
 
+
 def main():
     if len(sys.argv) != 4:
-        print(f'Usage: {sys.argv[0]} <path/to/Cargo.toml> <package name> <version to set>')
+        print(f"Usage: {sys.argv[0]} <path/to/Cargo.toml> <package name> <version to set>")
         sys.exit(1)
 
     file_name = sys.argv[1]
@@ -16,20 +17,21 @@ def main():
     version = sys.argv[3]
 
     # convert the version so that it conforms to Rust rules: x.x.x-whatever
-    version = re.sub(r'([0-9]+\.[0-9]+\.[0-9]+)\.', r'\1-', version)
-    with tempfile.NamedTemporaryFile(mode='w+t', encoding='utf-8', delete=False) as generated_fp:
-        with open(file_name, 'r', encoding='utf-8') as cargo_file:
+    version = re.sub(r"([0-9]+\.[0-9]+\.[0-9]+)\.", r"\1-", version)
+    with tempfile.NamedTemporaryFile(mode="w+t", encoding="utf-8", delete=False) as generated_fp:
+        with open(file_name, "r", encoding="utf-8") as cargo_file:
             in_rust_package_section = False
             for line in cargo_file:
-                if line.startswith('['):
+                if line.startswith("["):
                     in_rust_package_section = False
                 elif line == f'name = "{package_name}"\n':
                     in_rust_package_section = True
                 elif in_rust_package_section and line.startswith("version ="):
-                    generated_fp.write(f"version = \"{version}\"\n")
+                    generated_fp.write(f'version = "{version}"\n')
                     continue
                 generated_fp.write(line)
     shutil.move(generated_fp.name, file_name)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     main()
index 8bdd4ecebd8394191245f8832b19a2572dd44775..9af88ef834c6f5b85dce5ba790312f1105e91717 100644 (file)
@@ -4,6 +4,7 @@ import socket
 import struct
 import sys
 
+
 def readRecord(fp, withTimestamp):
 
     if withTimestamp:
@@ -17,14 +18,14 @@ def readRecord(fp, withTimestamp):
         return False
 
     queryID = struct.unpack("!H", data)[0]
-    qname = ''
+    qname = ""
     while True:
         labelLen = struct.unpack("B", fp.read(1))[0]
         if labelLen == 0:
             break
         label = fp.read(labelLen)
-        if qname != '':
-            qname = qname + '.'
+        if qname != "":
+            qname = qname + "."
         qname = qname + label.decode()
 
     qtype = struct.unpack("H", fp.read(2))[0]
@@ -35,26 +36,28 @@ def readRecord(fp, withTimestamp):
     elif addrType == socket.AF_INET6:
         addr = socket.inet_ntop(socket.AF_INET6, fp.read(16))
     else:
-        print('Unsupported address type %d, skipping this record' % (int(addrType)))
+        print("Unsupported address type %d, skipping this record" % (int(addrType)))
         return False
     port = struct.unpack("!H", fp.read(2))[0]
 
     if withTimestamp:
-        print('[%u.%u] Packet from %s:%d for %s %s with id %d' % (tv_sec, tv_nsec, addr, port, qname, qtype, queryID))
+        print("[%u.%u] Packet from %s:%d for %s %s with id %d" % (tv_sec, tv_nsec, addr, port, qname, qtype, queryID))
     else:
-        print('Packet from %s:%d for %s %s with id %d' % (addr, port, qname, qtype, queryID))
+        print("Packet from %s:%d for %s %s with id %d" % (addr, port, qname, qtype, queryID))
 
     return True
 
+
 def readLogFile(filename, withTimestamps):
-    with open(filename, mode='rb') as fp:
+    with open(filename, mode="rb") as fp:
         while True:
             if not readRecord(fp, withTimestamps):
                 break
 
+
 if __name__ == "__main__":
-    if len(sys.argv) != 2 and (len(sys.argv) != 3 or sys.argv[2] != 'with-timestamps'):
-        sys.exit('Usage: %s <path to log file> [with-timestamps]' % (sys.argv[0]))
+    if len(sys.argv) != 2 and (len(sys.argv) != 3 or sys.argv[2] != "with-timestamps"):
+        sys.exit("Usage: %s <path to log file> [with-timestamps]" % (sys.argv[0]))
 
     readLogFile(sys.argv[1], len(sys.argv) == 3)
 
index d5cf23a9f3140bce28c986a840e7cbae5892fde2..f62870fa114d80d220a1bf632ec7fb85a0bd2323 100644 (file)
@@ -26,25 +26,25 @@ import google.protobuf.message
 try:
     import google.protobuf.json_format
     import opentelemetry.proto.trace.v1.trace_pb2
+
     opentelemetryAvailable = True
 except Exception:
     opentelemetryAvailable = False
 
 
 class PDNSPBConnHandler(object):
-
     def __init__(self, conn, oturl, printjson):
         self._conn = conn
         self._oturl = oturl
         self._printjson = printjson
 
     messageTypeToStringMap = {
-        dnsmessage_pb2.PBDNSMessage.UNKNOWN: 'Unknown',
-        dnsmessage_pb2.PBDNSMessage.QNAME: 'QName',
-        dnsmessage_pb2.PBDNSMessage.CLIENTIP: 'Client IP',
-        dnsmessage_pb2.PBDNSMessage.RESPONSEIP: 'Response IP',
-        dnsmessage_pb2.PBDNSMessage.NSDNAME: 'NS DName',
-        dnsmessage_pb2.PBDNSMessage.NSIP: 'NS IP',
+        dnsmessage_pb2.PBDNSMessage.UNKNOWN: "Unknown",
+        dnsmessage_pb2.PBDNSMessage.QNAME: "QName",
+        dnsmessage_pb2.PBDNSMessage.CLIENTIP: "Client IP",
+        dnsmessage_pb2.PBDNSMessage.RESPONSEIP: "Response IP",
+        dnsmessage_pb2.PBDNSMessage.NSDNAME: "NS DName",
+        dnsmessage_pb2.PBDNSMessage.NSIP: "NS IP",
     }
 
     def run(self):
@@ -54,7 +54,7 @@ class PDNSPBConnHandler(object):
                 break
 
             (datalen,) = struct.unpack("!H", data)
-            data = b''
+            data = b""
             remaining = datalen
 
             while remaining > 0:
@@ -70,7 +70,7 @@ class PDNSPBConnHandler(object):
             msg = dnsmessage_pb2.PBDNSMessage()
             try:
                 msg.ParseFromString(data)
-                if opentelemetryAvailable and self._oturl is not None and msg.HasField('openTelemetryData'):
+                if opentelemetryAvailable and self._oturl is not None and msg.HasField("openTelemetryData"):
                     self.postOT(msg.openTelemetryData)
                 if msg.type == dnsmessage_pb2.PBDNSMessage.DNSQueryType:
                     self.printQueryMessage(msg)
@@ -81,49 +81,47 @@ class PDNSPBConnHandler(object):
                 elif msg.type == dnsmessage_pb2.PBDNSMessage.DNSIncomingResponseType:
                     self.printIncomingResponseMessage(msg)
                 else:
-                    print('Discarding unsupported message type %d' % (msg.type))
+                    print("Discarding unsupported message type %d" % (msg.type))
             except google.protobuf.message.DecodeError as exp:
-                print('Error parsing message of size %d: %s' % (datalen, str(exp)))
+                print("Error parsing message of size %d: %s" % (datalen, str(exp)))
                 break
 
         self._conn.close()
 
     def postOT(self, msg):
         print("- Posting OTData to " + self._oturl)
-        headers = {'Content-Type': 'application/x-protobuf'}
-        answer = requests.post(self._oturl, data = msg, headers = headers)
-        print('  - ' + str(answer))
+        headers = {"Content-Type": "application/x-protobuf"}
+        answer = requests.post(self._oturl, data=msg, headers=headers)
+        print("  - " + str(answer))
 
     def printQueryMessage(self, message):
-        self.printSummary(message, 'Query')
+        self.printSummary(message, "Query")
         self.printQuery(message)
         self.printOT(message)
 
     def printOutgoingQueryMessage(self, message):
-        self.printSummary(message, 'Query (O)')
+        self.printSummary(message, "Query (O)")
         self.printQuery(message)
         self.printOT(message)
 
     def printResponseMessage(self, message):
-        self.printSummary(message, 'Response')
+        self.printSummary(message, "Response")
         self.printQuery(message)
         self.printResponse(message)
         self.printOT(message)
 
     def printIncomingResponseMessage(self, message):
-        self.printSummary(message, 'Response (I)')
+        self.printSummary(message, "Response (I)")
         self.printQuery(message)
         self.printResponse(message)
         self.printOT(message)
 
     def printQuery(self, message):
-        if message.HasField('question'):
+        if message.HasField("question"):
             qclass = 1
-            if message.question.HasField('qClass'):
+            if message.question.HasField("qClass"):
                 qclass = message.question.qClass
-            print("- Question: %d, %d, %s" % (qclass,
-                                              message.question.qType,
-                                              message.question.qName))
+            print("- Question: %d, %d, %s" % (qclass, message.question.qType, message.question.qName))
 
     def convertKV(self, parent, key, value):
         if isinstance(value, dict):
@@ -133,7 +131,7 @@ class PDNSPBConnHandler(object):
             for key1, value1 in enumerate(value):
                 self.convertKV(value, key1, value1)
         else:
-            if key in ('trace_id', 'span_id', 'parent_span_id'):
+            if key in ("trace_id", "span_id", "parent_span_id"):
                 parent[key] = binascii.hexlify(base64.b64decode(value)).decode("utf-8")
 
     def convertIDs(self, values):
@@ -147,7 +145,7 @@ class PDNSPBConnHandler(object):
     def printOT(self, msg):
         if self._printjson:
             if opentelemetryAvailable:
-                if msg.HasField('openTelemetryData'):
+                if msg.HasField("openTelemetryData"):
                     json_string = None
                     otmsg = opentelemetry.proto.trace.v1.trace_pb2.TracesData()
                     otmsg.ParseFromString(msg.openTelemetryData)
@@ -156,7 +154,9 @@ class PDNSPBConnHandler(object):
                     json_string = json.dumps(values, indent=True)
                     print("- openTelemetry: " + json_string)
                 else:
-                    print("- openTelemetry decoding not available, see the comments in ProtoBuffer.py to make it available.")
+                    print(
+                        "- openTelemetry decoding not available, see the comments in ProtoBuffer.py to make it available."
+                    )
 
     @staticmethod
     def getAppliedPolicyTypeAsString(polType):
@@ -164,79 +164,76 @@ class PDNSPBConnHandler(object):
 
     @staticmethod
     def getEventAsString(event):
-        descr =  dnsmessage_pb2.PBDNSMessage.DESCRIPTOR
-        return descr.EnumValueName('EventType', event);
+        descr = dnsmessage_pb2.PBDNSMessage.DESCRIPTOR
+        return descr.EnumValueName("EventType", event)
 
     @staticmethod
     def getTransportAsString(transport):
-        descr =  dnsmessage_pb2.PBDNSMessage.DESCRIPTOR
-        return descr.EnumValueName('SocketProtocol', transport);
+        descr = dnsmessage_pb2.PBDNSMessage.DESCRIPTOR
+        return descr.EnumValueName("SocketProtocol", transport)
 
     def printResponse(self, message):
         if message.trace:
             print("- Event Trace:")
             for event in message.trace:
                 ev = self.getEventAsString(event.event)
-                if event.event == dnsmessage_pb2.PBDNSMessage.CustomEvent and event.HasField('custom'):
+                if event.event == dnsmessage_pb2.PBDNSMessage.CustomEvent and event.HasField("custom"):
                     ev += ":" + event.custom
-                ev += '(' + str(event.ts)
-                valstr = ''
-                if event.HasField('boolVal'):
-                      valstr = str(event.boolVal)
-                elif event.HasField('intVal'):
-                      valstr = str(event.intVal)
-                elif event.HasField('stringVal'):
-                      valstr = event.stringVal
-                elif event.HasField('bytesVal'):
-                      valstr = binascii.hexlify(event.bytesVal)
+                ev += "(" + str(event.ts)
+                valstr = ""
+                if event.HasField("boolVal"):
+                    valstr = str(event.boolVal)
+                elif event.HasField("intVal"):
+                    valstr = str(event.intVal)
+                elif event.HasField("stringVal"):
+                    valstr = event.stringVal
+                elif event.HasField("bytesVal"):
+                    valstr = binascii.hexlify(event.bytesVal)
                 if len(valstr) > 0:
-                    valstr = ',' + valstr
+                    valstr = "," + valstr
                 if not event.start:
-                    startstr = ',done'
+                    startstr = ",done"
                 else:
-                    startstr = ''
+                    startstr = ""
                 print("\t- %s%s%s)" % (ev, valstr, startstr))
 
-        if message.HasField('response'):
+        if message.HasField("response"):
             response = message.response
 
-            if response.HasField('queryTimeSec'):
-                datestr = datetime.datetime.fromtimestamp(response.queryTimeSec).strftime('%Y-%m-%d %H:%M:%S')
-                if response.HasField('queryTimeUsec'):
-                    datestr = datestr + '.' + ("%06d" % response.queryTimeUsec)
+            if response.HasField("queryTimeSec"):
+                datestr = datetime.datetime.fromtimestamp(response.queryTimeSec).strftime("%Y-%m-%d %H:%M:%S")
+                if response.HasField("queryTimeUsec"):
+                    datestr = datestr + "." + ("%06d" % response.queryTimeUsec)
                 print("- Query time: %s" % (datestr))
 
-            policystr = ''
-            if response.HasField('appliedPolicy') and response.appliedPolicy:
-                policystr = ', Applied policy: ' + response.appliedPolicy
-                if response.HasField('appliedPolicyType'):
-                    policystr = policystr + ' (' + self.getAppliedPolicyTypeAsString(response.appliedPolicyType) + ')'
-                if response.HasField('appliedPolicyTrigger'):
-                    policystr = policystr + ', Trigger = ' + response.appliedPolicyTrigger
-                if response.HasField('appliedPolicyHit'):
-                    policystr = policystr + ', Hit = ' + response.appliedPolicyHit
-
-            tagsstr = ''
+            policystr = ""
+            if response.HasField("appliedPolicy") and response.appliedPolicy:
+                policystr = ", Applied policy: " + response.appliedPolicy
+                if response.HasField("appliedPolicyType"):
+                    policystr = policystr + " (" + self.getAppliedPolicyTypeAsString(response.appliedPolicyType) + ")"
+                if response.HasField("appliedPolicyTrigger"):
+                    policystr = policystr + ", Trigger = " + response.appliedPolicyTrigger
+                if response.HasField("appliedPolicyHit"):
+                    policystr = policystr + ", Hit = " + response.appliedPolicyHit
+
+            tagsstr = ""
             if response.tags:
-                tagsstr = ', Tags: ' + ','.join(response.tags)
+                tagsstr = ", Tags: " + ",".join(response.tags)
 
             rrscount = len(response.rrs)
 
-            print("- Response Code: %d, RRs: %d%s%s" % (response.rcode,
-                                                      rrscount,
-                                                      policystr,
-                                                      tagsstr))
+            print("- Response Code: %d, RRs: %d%s%s" % (response.rcode, rrscount, policystr, tagsstr))
 
             for rr in response.rrs:
                 rrclass = 1
-                rdatastr = ''
-                rrudr = 'N/A'
-                if rr.HasField('class'):
-                    rrclass = getattr(rr, 'class')
+                rdatastr = ""
+                rrudr = "N/A"
+                if rr.HasField("class"):
+                    rrclass = getattr(rr, "class")
                 rrtype = rr.type
-                if rr.HasField('udr'):
+                if rr.HasField("udr"):
                     rrudr = str(rr.udr)
-                if (rrclass == 1 or rrclass == 255) and rr.HasField('rdata'):
+                if (rrclass == 1 or rrclass == 255) and rr.HasField("rdata"):
                     if rrtype == 1:
                         rdatastr = socket.inet_ntop(socket.AF_INET, rr.rdata)
                     elif rrtype in (5, 35, 64, 65):
@@ -244,163 +241,158 @@ class PDNSPBConnHandler(object):
                     elif rrtype == 28:
                         rdatastr = socket.inet_ntop(socket.AF_INET6, rr.rdata)
 
-                print("\t - %d, %d, %s, %d, %s, %s" % (rrclass,
-                                                   rrtype,
-                                                   rr.name,
-                                                   rr.ttl,
-                                                   rdatastr,
-                                                   rrudr))
+                print("\t - %d, %d, %s, %d, %s, %s" % (rrclass, rrtype, rr.name, rr.ttl, rdatastr, rrudr))
 
     def printSummary(self, msg, typestr):
-        datestr = datetime.datetime.fromtimestamp(msg.timeSec).strftime('%Y-%m-%d %H:%M:%S')
-        if msg.HasField('timeUsec'):
-            datestr = datestr + '.' + ("%06d" % msg.timeUsec)
-        ipfromstr = 'N/A'
-        iptostr = 'N/A'
-        toportstr = ''
-        fromportstr = ''
-        fromvalue = getattr(msg, 'from')
+        datestr = datetime.datetime.fromtimestamp(msg.timeSec).strftime("%Y-%m-%d %H:%M:%S")
+        if msg.HasField("timeUsec"):
+            datestr = datestr + "." + ("%06d" % msg.timeUsec)
+        ipfromstr = "N/A"
+        iptostr = "N/A"
+        toportstr = ""
+        fromportstr = ""
+        fromvalue = getattr(msg, "from")
         if msg.socketFamily == dnsmessage_pb2.PBDNSMessage.INET:
-            if msg.HasField('from'):
+            if msg.HasField("from"):
                 ipfromstr = socket.inet_ntop(socket.AF_INET, fromvalue)
-            if msg.HasField('to'):
+            if msg.HasField("to"):
                 iptostr = socket.inet_ntop(socket.AF_INET, msg.to)
         else:
-            if msg.HasField('from'):
-                ipfromstr = '[' + socket.inet_ntop(socket.AF_INET6, fromvalue) + ']'
-            if msg.HasField('to'):
-                iptostr = '[' + socket.inet_ntop(socket.AF_INET6, msg.to) + ']'
+            if msg.HasField("from"):
+                ipfromstr = "[" + socket.inet_ntop(socket.AF_INET6, fromvalue) + "]"
+            if msg.HasField("to"):
+                iptostr = "[" + socket.inet_ntop(socket.AF_INET6, msg.to) + "]"
 
         protostr = self.getTransportAsString(msg.socketProtocol)
 
-        if msg.HasField('fromPort'):
-            fromportstr = ':' + str(msg.fromPort) + ' '
+        if msg.HasField("fromPort"):
+            fromportstr = ":" + str(msg.fromPort) + " "
 
-        if msg.HasField('toPort'):
-            toportstr = ':' + str(msg.toPort) + ' '
+        if msg.HasField("toPort"):
+            toportstr = ":" + str(msg.toPort) + " "
 
         messageidstr = binascii.hexlify(bytearray(msg.messageId))
 
-        serveridstr = 'N/A'
-        if msg.HasField('serverIdentity'):
+        serveridstr = "N/A"
+        if msg.HasField("serverIdentity"):
             serveridstr = msg.serverIdentity
 
-        initialrequestidstr = ''
-        if msg.HasField('initialRequestId'):
-            initialrequestidstr = ', initial uuid: %s ' % (binascii.hexlify(bytearray(msg.initialRequestId)))
+        initialrequestidstr = ""
+        if msg.HasField("initialRequestId"):
+            initialrequestidstr = ", initial uuid: %s " % (binascii.hexlify(bytearray(msg.initialRequestId)))
 
-        requestorstr = '(N/A)'
+        requestorstr = "(N/A)"
         requestor = self.getRequestorSubnet(msg)
         if requestor:
-            requestorstr = ' (' + requestor + ')'
+            requestorstr = " (" + requestor + ")"
 
-        deviceId = 'N/A'
-        if msg.HasField('deviceId'):
+        deviceId = "N/A"
+        if msg.HasField("deviceId"):
             deviceId = binascii.hexlify(bytearray(msg.deviceId))
-        deviceName = 'N/A'
-        if msg.HasField('deviceName'):
+        deviceName = "N/A"
+        if msg.HasField("deviceName"):
             deviceName = msg.deviceName
 
-        requestorId = 'N/A'
-        if msg.HasField('requestorId'):
+        requestorId = "N/A"
+        if msg.HasField("requestorId"):
             requestorId = msg.requestorId
 
-        nod = 'N/A';
-        if msg.HasField('newlyObservedDomain'):
+        nod = "N/A"
+        if msg.HasField("newlyObservedDomain"):
             nod = str(msg.newlyObservedDomain)
 
-        workerId = 'N/A'
-        if msg.HasField('workerId'):
-           workerId = str(msg.workerId)
+        workerId = "N/A"
+        if msg.HasField("workerId"):
+            workerId = str(msg.workerId)
 
-        pcCacheHit = 'N/A'
-        if msg.HasField('packetCacheHit'):
-           pcCacheHit = str(msg.packetCacheHit)
+        pcCacheHit = "N/A"
+        if msg.HasField("packetCacheHit"):
+            pcCacheHit = str(msg.packetCacheHit)
 
-        outgoingQs = 'N/A'
-        if msg.HasField('outgoingQueries'):
-           outgoingQs = str(msg.outgoingQueries)
+        outgoingQs = "N/A"
+        if msg.HasField("outgoingQueries"):
+            outgoingQs = str(msg.outgoingQueries)
 
         headerFlags = "N/A"
-        if msg.HasField('headerFlags'):
+        if msg.HasField("headerFlags"):
             headerFlags = "0x%04X" % socket.ntohs(msg.headerFlags)
 
         ednsVersion = "N/A"
-        if msg.HasField('ednsVersion'):
+        if msg.HasField("ednsVersion"):
             ednsVersion = "0x%08X" % socket.ntohl(msg.ednsVersion)
 
         ede = "N/A"
-        if msg.HasField('ede'):
+        if msg.HasField("ede"):
             ede = str(msg.ede)
         edeText = "N/A"
-        if msg.HasField('edeText'):
+        if msg.HasField("edeText"):
             edeText = msg.edeText
 
         openTelemetryDataLen = "N/A"
-        if opentelemetryAvailable and msg.HasField('openTelemetryData'):
+        if opentelemetryAvailable and msg.HasField("openTelemetryData"):
             openTelemetryDataLen = str(len(msg.openTelemetryData))
 
         openTelemetryTraceID = "N/A"
-        if msg.HasField('openTelemetryTraceID'):
+        if msg.HasField("openTelemetryTraceID"):
             openTelemetryTraceID = binascii.hexlify(msg.openTelemetryTraceID)
 
-        print('[%s] %s of size %d: %s%s%s -> %s%s(%s) id: %d uuid: %s%s '
-                  'requestorid: %s deviceid: %s devicename: %s serverid: %s nod: %s workerId: %s pcCacheHit: %s outgoingQueries: %s headerFlags: %s ednsVersion: %s ede: %s edeText: %s otTraceID: %s openTelemetryData: len %s' %
-              (datestr,
-               typestr,
-               msg.inBytes,
-               ipfromstr,
-               fromportstr,
-               requestorstr,
-               iptostr,
-               toportstr,
-               protostr,
-               msg.id,
-               messageidstr,
-               initialrequestidstr,
-               requestorId,
-               deviceId,
-               deviceName,
-               serveridstr,
-               nod,
-               workerId,
-               pcCacheHit,
-               outgoingQs,
-               headerFlags,
-               ednsVersion,
-               ede,
-               edeText,
-               openTelemetryTraceID,
-               openTelemetryDataLen))
+        print(
+            "[%s] %s of size %d: %s%s%s -> %s%s(%s) id: %d uuid: %s%s "
+            "requestorid: %s deviceid: %s devicename: %s serverid: %s nod: %s workerId: %s pcCacheHit: %s outgoingQueries: %s headerFlags: %s ednsVersion: %s ede: %s edeText: %s otTraceID: %s openTelemetryData: len %s"
+            % (
+                datestr,
+                typestr,
+                msg.inBytes,
+                ipfromstr,
+                fromportstr,
+                requestorstr,
+                iptostr,
+                toportstr,
+                protostr,
+                msg.id,
+                messageidstr,
+                initialrequestidstr,
+                requestorId,
+                deviceId,
+                deviceName,
+                serveridstr,
+                nod,
+                workerId,
+                pcCacheHit,
+                outgoingQs,
+                headerFlags,
+                ednsVersion,
+                ede,
+                edeText,
+                openTelemetryTraceID,
+                openTelemetryDataLen,
+            )
+        )
 
         for mt in msg.meta:
-            values = ''
+            values = ""
             for entry in mt.value.stringVal:
-                values = ', '.join([values, entry]) if values != '' else entry
+                values = ", ".join([values, entry]) if values != "" else entry
             for entry in mt.value.intVal:
-                values = ', '.join([values, str(entry)]) if values != '' else str(entry)
+                values = ", ".join([values, str(entry)]) if values != "" else str(entry)
 
-            print('- (meta) %s -> %s' % (mt.key, values))
+            print("- (meta) %s -> %s" % (mt.key, values))
 
     def getRequestorSubnet(self, msg):
         requestorstr = None
-        if msg.HasField('originalRequestorSubnet'):
+        if msg.HasField("originalRequestorSubnet"):
             if len(msg.originalRequestorSubnet) == 4:
-                requestorstr = socket.inet_ntop(socket.AF_INET,
-                                                msg.originalRequestorSubnet)
+                requestorstr = socket.inet_ntop(socket.AF_INET, msg.originalRequestorSubnet)
             elif len(msg.originalRequestorSubnet) == 16:
-                requestorstr = socket.inet_ntop(socket.AF_INET6,
-                                                msg.originalRequestorSubnet)
+                requestorstr = socket.inet_ntop(socket.AF_INET6, msg.originalRequestorSubnet)
         return requestorstr
 
-class PDNSPBListener(object):
 
+class PDNSPBListener(object):
     def __init__(self, addr, port, oturl, printjson):
         self._oturl = oturl
         self._printjson = printjson
-        res = socket.getaddrinfo(addr, port, socket.AF_UNSPEC,
-                                 socket.SOCK_STREAM, 0,
-                                 socket.AI_PASSIVE)
+        res = socket.getaddrinfo(addr, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
         if len(res) != 1:
             print("Error parsing the supplied address")
             sys.exit(1)
@@ -420,24 +412,22 @@ class PDNSPBListener(object):
             (conn, _) = self._sock.accept()
 
             handler = PDNSPBConnHandler(conn, self._oturl, self._printjson)
-            thread = threading.Thread(name='Connection Handler',
-                                      target=PDNSPBConnHandler.run,
-                                      args=[handler])
+            thread = threading.Thread(name="Connection Handler", target=PDNSPBConnHandler.run, args=[handler])
             thread.daemon = True
             thread.start()
 
 
 if __name__ == "__main__":
     parser = argparse.ArgumentParser(
-                    prog='ProtobufLogger',
-                    description='Listens for and prints dnsmessage.proto messages and optionally posts OT Trace data to a collector URL',
-                    epilog='URL is an optional url of a OpenTelemetry Trace collector endpoint'
+        prog="ProtobufLogger",
+        description="Listens for and prints dnsmessage.proto messages and optionally posts OT Trace data to a collector URL",
+        epilog="URL is an optional url of a OpenTelemetry Trace collector endpoint",
     )
 
-    parser.add_argument('-json', action='store_true')
-    parser.add_argument('address')
-    parser.add_argument('port')
-    parser.add_argument('-url')
-    args = parser.parse_args();
+    parser.add_argument("-json", action="store_true")
+    parser.add_argument("address")
+    parser.add_argument("port")
+    parser.add_argument("-url")
+    args = parser.parse_args()
     PDNSPBListener(args.address, args.port, args.url, args.json).run()
     sys.exit(0)
index 9a3605e0fce10302034cc9a67273e5cebdcbbe83..6c67f21bf3546211e211d587675a167c7dd38024 100644 (file)
@@ -2,21 +2,15 @@ import difflib
 import dns
 import unittest
 
+
 class AssertEqualDNSMessageMixin(unittest.TestCase):
     def assertEqualDNSMessage(self, first, second, msg=None):
         if not first == second:
-            a = str(first).split('\n')
-            b = str(second).split('\n')
+            a = str(first).split("\n")
+            b = str(second).split("\n")
 
-            diff = '\n'.join(
-                difflib.unified_diff(
-                    a,
-                    b,
-                    fromfile='first',
-                    tofile='second',
-                    n=max(len(a), len(b)),
-                    lineterm=""
-                )
+            diff = "\n".join(
+                difflib.unified_diff(a, b, fromfile="first", tofile="second", n=max(len(a), len(b)), lineterm="")
             )
 
             standardMsg = "%s != %s:\n%s" % (repr(first), repr(second), diff)
index 1c0e012deee37131d249c177ad28a07fb2f9ab49..090e5f34cdb34766d6a21b18226c273ca008923b 100644 (file)
@@ -5,18 +5,14 @@ import ctypes as ct
 import netaddr
 import socket
 
+
 class DNSQuery(ct.Structure):
-    _fields_ = [
-        ("qname", ct.c_uint8 * 255),
-        ("qtype", ct.c_uint16)
-    ]
+    _fields_ = [("qname", ct.c_uint8 * 255), ("qtype", ct.c_uint16)]
+
 
 class PacketInfo(ct.Structure):
-    _fields_ = [
-        ("ipv4_src", ct.c_uint32),
-        ("ipv6_src", ct.c_uint8 * 16),
-        ("query", DNSQuery)
-    ]
+    _fields_ = [("ipv4_src", ct.c_uint32), ("ipv6_src", ct.c_uint8 * 16), ("query", DNSQuery)]
+
 
 def decode_qname(qname_array):
     qname = ""
@@ -28,23 +24,97 @@ def decode_qname(qname_array):
             else:
                 length = int(qname_byte)
                 if qname != "":
-                    qname += '.'
+                    qname += "."
         else:
             qname += chr(int(qname_byte))
             length -= 1
     return qname
 
+
 def print_event(cpu, data, size):
     event = ct.cast(data, ct.POINTER(PacketInfo)).contents
     if event.ipv4_src != 0:
         src_ip = str(netaddr.IPAddress(socket.htonl(event.ipv4_src)))
     else:
-        src_ip = str(netaddr.IPAddress(sum([byte << 8*(15-index) for index, byte in enumerate(event.ipv6_src)]), 6))
+        src_ip = str(netaddr.IPAddress(sum([byte << 8 * (15 - index) for index, byte in enumerate(event.ipv6_src)]), 6))
     qtype = INV_QTYPES[socket.htons(event.query.qtype)]
     qname = decode_qname(event.query.qname)
     print(f"{src_ip}|{qtype}|{qname}")
 
-QTYPES = {'LOC': 29, '*': 255, 'IXFR': 251, 'UINFO': 100, 'NSEC3': 50, 'AAAA': 28, 'CNAME': 5, 'MINFO': 14, 'EID': 31, 'GPOS': 27, 'X25': 19, 'HINFO': 13, 'CAA': 257, 'NULL': 10, 'DNSKEY': 48, 'DS': 43, 'ISDN': 20, 'SOA': 6, 'RP': 17, 'UID': 101, 'TALINK': 58, 'TKEY': 249, 'PX': 26, 'NSAP-PTR': 23, 'TXT': 16, 'IPSECKEY': 45, 'DNAME': 39, 'MAILA': 254, 'AFSDB': 18, 'SSHFP': 44, 'NS': 2, 'PTR': 12, 'SPF': 99, 'TA': 32768, 'A': 1, 'NXT': 30, 'AXFR': 252, 'RKEY': 57, 'KEY': 25, 'NIMLOC': 32, 'A6': 38, 'TLSA': 52, 'MG': 8, 'HIP': 55, 'NSEC': 47, 'GID': 102, 'SRV': 33, 'DLV': 32769, 'NSEC3PARAM': 51, 'UNSPEC': 103, 'TSIG': 250, 'ATMA': 34, 'RRSIG': 46, 'OPT': 41, 'MD': 3, 'NAPTR': 35, 'MF': 4, 'MB': 7, 'DHCID': 49, 'MX': 15, 'MAILB': 253, 'CERT': 37, 'NINFO': 56, 'APL': 42, 'MR': 9, 'SIG': 24, 'WKS': 11, 'KX': 36, 'NSAP': 22, 'RT': 21, 'SINK': 40}
+
+QTYPES = {
+    "LOC": 29,
+    "*": 255,
+    "IXFR": 251,
+    "UINFO": 100,
+    "NSEC3": 50,
+    "AAAA": 28,
+    "CNAME": 5,
+    "MINFO": 14,
+    "EID": 31,
+    "GPOS": 27,
+    "X25": 19,
+    "HINFO": 13,
+    "CAA": 257,
+    "NULL": 10,
+    "DNSKEY": 48,
+    "DS": 43,
+    "ISDN": 20,
+    "SOA": 6,
+    "RP": 17,
+    "UID": 101,
+    "TALINK": 58,
+    "TKEY": 249,
+    "PX": 26,
+    "NSAP-PTR": 23,
+    "TXT": 16,
+    "IPSECKEY": 45,
+    "DNAME": 39,
+    "MAILA": 254,
+    "AFSDB": 18,
+    "SSHFP": 44,
+    "NS": 2,
+    "PTR": 12,
+    "SPF": 99,
+    "TA": 32768,
+    "A": 1,
+    "NXT": 30,
+    "AXFR": 252,
+    "RKEY": 57,
+    "KEY": 25,
+    "NIMLOC": 32,
+    "A6": 38,
+    "TLSA": 52,
+    "MG": 8,
+    "HIP": 55,
+    "NSEC": 47,
+    "GID": 102,
+    "SRV": 33,
+    "DLV": 32769,
+    "NSEC3PARAM": 51,
+    "UNSPEC": 103,
+    "TSIG": 250,
+    "ATMA": 34,
+    "RRSIG": 46,
+    "OPT": 41,
+    "MD": 3,
+    "NAPTR": 35,
+    "MF": 4,
+    "MB": 7,
+    "DHCID": 49,
+    "MX": 15,
+    "MAILB": 253,
+    "CERT": 37,
+    "NINFO": 56,
+    "APL": 42,
+    "MR": 9,
+    "SIG": 24,
+    "WKS": 11,
+    "KX": 36,
+    "NSAP": 22,
+    "RT": 21,
+    "SINK": 40,
+}
 INV_QTYPES = {v: k for k, v in QTYPES.items()}
 
 # Main
@@ -69,6 +139,6 @@ while True:
         break
 
 if progs[ct.c_int(0)]:
-    del(progs[ct.c_int(0)])
+    del progs[ct.c_int(0)]
 if progs[ct.c_int(1)]:
-    del(progs[ct.c_int(1)])
+    del progs[ct.c_int(1)]
index 5365e8e971f14a64545ef2012ec74b4790147df0..b27c8beab24000fc4ba3e4124f263504159c7018 100644 (file)
@@ -7,124 +7,128 @@ import netaddr
 from bcc import BPF
 
 # Constants
-QTYPES = {'*': 65535,
-          'LOC': 29,
-          'ANY': 255,
-          'IXFR': 251,
-          'UINFO': 100,
-          'NSEC3': 50,
-          'AAAA': 28,
-          'CNAME': 5,
-          'MINFO': 14,
-          'EID': 31,
-          'GPOS': 27,
-          'X25': 19,
-          'HINFO': 13,
-          'CAA': 257,
-          'NULL': 10,
-          'DNSKEY': 48,
-          'DS': 43,
-          'ISDN': 20,
-          'SOA': 6,
-          'RP': 17,
-          'UID': 101,
-          'TALINK': 58,
-          'TKEY': 249,
-          'PX': 26,
-          'NSAP-PTR': 23,
-          'TXT': 16,
-          'IPSECKEY': 45,
-          'DNAME': 39,
-          'MAILA': 254,
-          'AFSDB': 18,
-          'SSHFP': 44,
-          'NS': 2,
-          'PTR': 12,
-          'SPF': 99,
-          'TA': 32768,
-          'A': 1,
-          'NXT': 30,
-          'AXFR': 252,
-          'RKEY': 57,
-          'KEY': 25,
-          'NIMLOC': 32,
-          'A6': 38,
-          'TLSA': 52,
-          'MG': 8,
-          'HIP': 55,
-          'NSEC': 47,
-          'GID': 102,
-          'SRV': 33,
-          'DLV': 32769,
-          'NSEC3PARAM': 51,
-          'UNSPEC': 103,
-          'TSIG': 250,
-          'ATMA': 34,
-          'RRSIG': 46,
-          'OPT': 41,
-          'MD': 3,
-          'NAPTR': 35,
-          'MF': 4,
-          'MB': 7,
-          'DHCID': 49,
-          'MX': 15,
-          'MAILB': 253,
-          'CERT': 37,
-          'NINFO': 56,
-          'APL': 42,
-          'MR': 9,
-          'SIG': 24,
-          'WKS': 11,
-          'KX': 36,
-          'NSAP': 22,
-          'RT': 21,
-          'SINK': 40
+QTYPES = {
+    "*": 65535,
+    "LOC": 29,
+    "ANY": 255,
+    "IXFR": 251,
+    "UINFO": 100,
+    "NSEC3": 50,
+    "AAAA": 28,
+    "CNAME": 5,
+    "MINFO": 14,
+    "EID": 31,
+    "GPOS": 27,
+    "X25": 19,
+    "HINFO": 13,
+    "CAA": 257,
+    "NULL": 10,
+    "DNSKEY": 48,
+    "DS": 43,
+    "ISDN": 20,
+    "SOA": 6,
+    "RP": 17,
+    "UID": 101,
+    "TALINK": 58,
+    "TKEY": 249,
+    "PX": 26,
+    "NSAP-PTR": 23,
+    "TXT": 16,
+    "IPSECKEY": 45,
+    "DNAME": 39,
+    "MAILA": 254,
+    "AFSDB": 18,
+    "SSHFP": 44,
+    "NS": 2,
+    "PTR": 12,
+    "SPF": 99,
+    "TA": 32768,
+    "A": 1,
+    "NXT": 30,
+    "AXFR": 252,
+    "RKEY": 57,
+    "KEY": 25,
+    "NIMLOC": 32,
+    "A6": 38,
+    "TLSA": 52,
+    "MG": 8,
+    "HIP": 55,
+    "NSEC": 47,
+    "GID": 102,
+    "SRV": 33,
+    "DLV": 32769,
+    "NSEC3PARAM": 51,
+    "UNSPEC": 103,
+    "TSIG": 250,
+    "ATMA": 34,
+    "RRSIG": 46,
+    "OPT": 41,
+    "MD": 3,
+    "NAPTR": 35,
+    "MF": 4,
+    "MB": 7,
+    "DHCID": 49,
+    "MX": 15,
+    "MAILB": 253,
+    "CERT": 37,
+    "NINFO": 56,
+    "APL": 42,
+    "MR": 9,
+    "SIG": 24,
+    "WKS": 11,
+    "KX": 36,
+    "NSAP": 22,
+    "RT": 21,
+    "SINK": 40,
 }
 INV_QTYPES = {v: k for k, v in QTYPES.items()}
-ACTIONS = {1 : 'DROP', 2 : 'TC'}
+ACTIONS = {1: "DROP", 2: "TC"}
 
 DROP_ACTION = 1
 TC_ACTION = 2
 
 # The list of blocked IPv4, IPv6 and QNames
-# IP format : (IPAddress, Action)
-# CIDR format : (IPAddress/cidr, Action)
-# QName format : (QName, QType, Action)
+# IP format : (IPAddress, Action)
+# CIDR format : (IPAddress/cidr, Action)
+# QName format : (QName, QType, Action)
 blocked_ipv4 = [("192.0.2.1", TC_ACTION)]
 blocked_ipv6 = [("2001:db8::1", TC_ACTION)]
 blocked_cidr4 = [("192.0.1.1/24", TC_ACTION)]
 blocked_cidr6 = [("2001:db8::1/128", TC_ACTION)]
-blocked_qnames = [("localhost", "A", DROP_ACTION),
-                  ("test.com", "*", TC_ACTION)]
+blocked_qnames = [("localhost", "A", DROP_ACTION), ("test.com", "*", TC_ACTION)]
 
 # Main
-parser = argparse.ArgumentParser(description='XDP helper for DNSDist')
-parser.add_argument('--interface', '-i', type=str, default=[], action='append',
-                    help='The interface(s) on which the filter will be attached')
-parser.add_argument('--maps-size', '-m', type=int, default=1024,
-                    help='Maximum number of entries in the eBPF maps')
-parser.add_argument('--number-of-queues', '-q', type=int, default=64,
-                    help='Maximum number of network queues in XSK (AF_XDP) mode')
-parser.add_argument('--xsk', action='store_true', default=False,
-                    help='Enable XSK (AF_XDP) mode')
+parser = argparse.ArgumentParser(description="XDP helper for DNSDist")
+parser.add_argument(
+    "--interface",
+    "-i",
+    type=str,
+    default=[],
+    action="append",
+    help="The interface(s) on which the filter will be attached",
+)
+parser.add_argument("--maps-size", "-m", type=int, default=1024, help="Maximum number of entries in the eBPF maps")
+parser.add_argument(
+    "--number-of-queues", "-q", type=int, default=64, help="Maximum number of network queues in XSK (AF_XDP) mode"
+)
+parser.add_argument("--xsk", action="store_true", default=False, help="Enable XSK (AF_XDP) mode")
 
 parameters = parser.parse_args()
-cflag = [f'-DDDIST_MAX_NUMBER_OF_QUEUES={parameters.number_of_queues}',
-         f'-DDDIST_MAPS_SIZE={parameters.maps_size}']
+cflag = [f"-DDDIST_MAX_NUMBER_OF_QUEUES={parameters.number_of_queues}", f"-DDDIST_MAPS_SIZE={parameters.maps_size}"]
 interfaces = set(parameters.interface)
 if len(interfaces) == 0:
-    interfaces = ['eth0']
+    interfaces = ["eth0"]
 
 if parameters.xsk:
     for interface in interfaces:
-        print(f'Enabling XSK (AF_XDP) on {interface}..')
-    cflag.append('-DUseXsk')
+        print(f"Enabling XSK (AF_XDP) on {interface}..")
+    cflag.append("-DUseXsk")
 else:
     ports = [53]
-    ports_str = ', '.join(str(port) for port in ports)
+    ports_str = ", ".join(str(port) for port in ports)
     for interface in interfaces:
-        print(f'Enabling XDP on {interface} and ports {ports_str}..')
-    IN_DNS_PORT_SET = "||".join("COMPARE_PORT((x),"+str(i)+")" for i in ports)
+        print(f"Enabling XDP on {interface} and ports {ports_str}..")
+    IN_DNS_PORT_SET = "||".join("COMPARE_PORT((x)," + str(i) + ")" for i in ports)
     cflag.append(r"-DIN_DNS_PORT_SET(x)=(" + IN_DNS_PORT_SET + r")")
 
 xdp = BPF(src_file="xdp-filter.ebpf.src", cflags=cflag)
@@ -156,7 +160,7 @@ for ip in blocked_ipv4:
 for ip in blocked_ipv6:
     print(f"Blocking {ip}")
     ipv6_int = int(netaddr.IPAddress(ip[0]).value)
-    ipv6_bytes = bytearray([(ipv6_int & (255 << 8*(15-i))) >> (8*(15-i)) for i in range(16)])
+    ipv6_bytes = bytearray([(ipv6_int & (255 << 8 * (15 - i))) >> (8 * (15 - i)) for i in range(16)])
     key = (ct.c_uint8 * 16).from_buffer(ipv6_bytes)
     leaf = v6filter.Leaf()
     leaf.counter = 0
@@ -180,7 +184,7 @@ for item in blocked_cidr6:
     network = netaddr.IPNetwork(item[0])
     key.cidr = network.prefixlen
     ipv6_int = int(network.network.value)
-    ipv6_bytes = bytearray([(ipv6_int & (255 << 8*(15-i))) >> (8*(15-i)) for i in range(16)])
+    ipv6_bytes = bytearray([(ipv6_int & (255 << 8 * (15 - i))) >> (8 * (15 - i)) for i in range(16)])
     key.addr.in6_u.u6_addr8 = (ct.c_uint8 * 16).from_buffer(ipv6_bytes)
     leaf = cidr6filter.Leaf()
     leaf.counter = 0
@@ -191,7 +195,7 @@ for qname in blocked_qnames:
     print(f"Blocking {qname}")
     key = qnamefilter.Key()
     qn = bytearray()
-    for sub in qname[0].split('.'):
+    for sub in qname[0].split("."):
         qn.append(len(sub))
         for ch in sub:
             qn.append(ord(ch))
@@ -224,12 +228,16 @@ if v4filter or v6filter or cidr4filter or cidr6filter:
         print(f"- {str(addr)}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}")
 
     for item in cidr6filter.items():
-        print(f"- {str(socket.inet_ntop(socket.AF_INET6, item[0].addr))}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}")
+        print(
+            f"- {str(socket.inet_ntop(socket.AF_INET6, item[0].addr))}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}"
+        )
 
 if qnamefilter:
     print("Blocked query names:")
     for item in qnamefilter.items():
-        print(f"- {''.join(map(chr, item[0].qname)).strip()}/{INV_QTYPES[item[0].qtype]} ({ACTIONS[item[1].action]}): {item[1].counter}")
+        print(
+            f"- {''.join(map(chr, item[0].qname)).strip()}/{INV_QTYPES[item[0].qtype]} ({ACTIONS[item[1].action]}): {item[1].counter}"
+        )
 
 if parameters.xsk and (xsk_destinations4 or xsk_destinations6):
     print("Content of the AF_XDP (XSK) routing maps:")
index 432b90538dbcb8932272978c6e3f047738045ab5..71bc53bbf307e6f97a195ee78a4c7c343e4c0c2c 100755 (executable)
@@ -3,20 +3,20 @@ import os
 import sys
 import jinja2
 
-program = sys.argv[0].split('-')[0]
+program = sys.argv[0].split("-")[0]
 product = os.path.basename(program)
 
 apienvvar = None
 apiconftemplate = None
-templateroot = '/etc/powerdns/templates.d'
-templatedestination = ''
+templateroot = "/etc/powerdns/templates.d"
+templatedestination = ""
 args = []
-suffix='.conf' # default suffix, rec uses .yml
+suffix = ".conf"  # default suffix, rec uses .yml
 
-if product == 'pdns_recursor':
-    args = ['--disable-syslog']
-    apienvvar = 'PDNS_RECURSOR_API_KEY'
-    suffix = '.yml'
+if product == "pdns_recursor":
+    args = ["--disable-syslog"]
+    apienvvar = "PDNS_RECURSOR_API_KEY"
+    suffix = ".yml"
     apiconftemplate = """webservice:
   webserver: true
   api_key: '{{ apikey }}'
@@ -24,10 +24,10 @@ if product == 'pdns_recursor':
   allow_from: [0.0.0.0/0]
   password: '{{ apikey }}'
 """
-    templatedestination = '/etc/powerdns/recursor.d'
-elif product == 'pdns_server':
-    args = ['--disable-syslog']
-    apienvvar = 'PDNS_AUTH_API_KEY'
+    templatedestination = "/etc/powerdns/recursor.d"
+elif product == "pdns_server":
+    args = ["--disable-syslog"]
+    apienvvar = "PDNS_AUTH_API_KEY"
     apiconftemplate = """webserver
 api
 api-key={{ apikey }}
@@ -35,41 +35,41 @@ webserver-address=0.0.0.0
 webserver-allow-from=0.0.0.0/0
 webserver-password={{ apikey }}
     """
-    templatedestination = '/etc/powerdns/pdns.d'
-elif product == 'dnsdist':
-    args = ['--supervised', '--disable-syslog']
-    apienvvar = 'DNSDIST_API_KEY'
+    templatedestination = "/etc/powerdns/pdns.d"
+elif product == "dnsdist":
+    args = ["--supervised", "--disable-syslog"]
+    apienvvar = "DNSDIST_API_KEY"
     apiconftemplate = """webserver("0.0.0.0:8083")
     setWebserverConfig({password='{{ apikey }}', apiKey='{{ apikey }}', acl='0.0.0.0/0'})
 controlSocket('0.0.0.0:5199')
 setKey('{{ apikey }}')
 setConsoleACL('0.0.0.0/0')
     """
-    templateroot = '/etc/dnsdist/templates.d'
-    templatedestination = '/etc/dnsdist/conf.d'
+    templateroot = "/etc/dnsdist/templates.d"
+    templatedestination = "/etc/dnsdist/conf.d"
 
-debug = os.getenv("DEBUG_CONFIG", 'no').lower() == 'yes'
+debug = os.getenv("DEBUG_CONFIG", "no").lower() == "yes"
 
 apikey = os.getenv(apienvvar)
 if apikey is not None:
     webserver_conf = jinja2.Template(apiconftemplate).render(apikey=apikey)
-    conffile = os.path.join(templatedestination, '_api' + suffix)
-    with open(conffile, 'w') as f:
+    conffile = os.path.join(templatedestination, "_api" + suffix)
+    with open(conffile, "w") as f:
         f.write(webserver_conf)
     if debug:
         print("Created {} with content:\n{}\n".format(conffile, webserver_conf))
 
-templates = os.getenv('TEMPLATE_FILES')
+templates = os.getenv("TEMPLATE_FILES")
 if templates is not None:
-    for templateFile in templates.split(','):
+    for templateFile in templates.split(","):
         template = None
-        with open(os.path.join(templateroot, templateFile + '.j2')) as f:
+        with open(os.path.join(templateroot, templateFile + ".j2")) as f:
             template = jinja2.Template(f.read())
         rendered = template.render(os.environ)
         target = os.path.join(templatedestination, templateFile + suffix)
-        with open(target, 'w') as f:
+        with open(target, "w") as f:
             f.write(rendered)
         if debug:
             print("Created {} with content:\n{}\n".format(target, rendered))
 
-os.execv(program, [program]+args+sys.argv[1:])
+os.execv(program, [program] + args + sys.argv[1:])
index bb67aaeb940211268c406ec28eb135bc7527f8c6..44f8f9214ad3efdbfe309cd8f41e4252393c2cf4 100644 (file)
@@ -29,41 +29,40 @@ import guzzle_sphinx_theme
 #
 # needs_sphinx = '1.0'
 
-sys.path.append(str(Path('.').resolve()))
+sys.path.append(str(Path(".").resolve()))
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-#extensions = []
-#extensions = ['redjack.sphinx.lua', 'sphinxcontrib.httpdomain', 'sphinxjsondomain']
-extensions = ['sphinxcontrib.openapi',
-              'sphinxcontrib.fulltoc', 'changelog', 'depfile']
+# extensions = []
+# extensions = ['redjack.sphinx.lua', 'sphinxcontrib.httpdomain', 'sphinxjsondomain']
+extensions = ["sphinxcontrib.openapi", "sphinxcontrib.fulltoc", "changelog", "depfile"]
 
 # Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
 
 # The suffix(es) of source filenames.
 # You can specify multiple suffix as a list of string:
 #
 # source_suffix = ['.rst', '.md']
-source_suffix = '.rst'
+source_suffix = ".rst"
 
 # The master toctree document.
-master_doc = 'indexTOC'
+master_doc = "indexTOC"
 
 # General information about the project.
-project = 'PowerDNS Authoritative Server'
-copyright = 'PowerDNS.COM BV'
-author = 'PowerDNS.COM BV'
+project = "PowerDNS Authoritative Server"
+copyright = "PowerDNS.COM BV"
+author = "PowerDNS.COM BV"
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-#version = '4.2'
+# version = '4.2'
 # The full version, including alpha/beta/rc tags.
-#release = '4.1.1-pre'
+# release = '4.1.1-pre'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -75,15 +74,19 @@ language = None
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This patterns also effect to html_static_path and html_extra_path
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store',
-                    '.venv',
-                    'security-advisories/security-policy.rst',
-                    'common/secpoll.rst',
-                    'common/api/*']
+exclude_patterns = [
+    "_build",
+    "Thumbs.db",
+    ".DS_Store",
+    ".venv",
+    "security-advisories/security-policy.rst",
+    "common/secpoll.rst",
+    "common/api/*",
+]
 
 # The name of the Pygments (syntax highlighting) style to use.
-highlight_language = 'none'
-pygments_style = 'sphinx'
+highlight_language = "none"
+pygments_style = "sphinx"
 
 # If true, `todo` and `todoList` produce output, else they produce nothing.
 todo_include_todos = False
@@ -95,8 +98,20 @@ changelog_render_ticket = "https://github.com/PowerDNS/pdns/issues/%s"
 changelog_render_pullreq = "https://github.com/PowerDNS/pdns/pull/%s"
 changelog_render_changeset = "https://github.com/PowerDNS/pdns/commit/%s"
 
-changelog_sections = ['New Features', 'Removed Features', 'Improvements', 'Bug Fixes']
-changelog_inner_tag_sort = ['Internals', 'API', 'Tools', 'ALIAS', 'DNSUpdate', 'BIND', 'MySQL', 'Postgresql', 'LDAP', 'GeoIP', 'Remote']
+changelog_sections = ["New Features", "Removed Features", "Improvements", "Bug Fixes"]
+changelog_inner_tag_sort = [
+    "Internals",
+    "API",
+    "Tools",
+    "ALIAS",
+    "DNSUpdate",
+    "BIND",
+    "MySQL",
+    "Postgresql",
+    "LDAP",
+    "GeoIP",
+    "Remote",
+]
 
 changelog_hide_tags_in_entry = True
 
@@ -106,7 +121,7 @@ changelog_hide_tags_in_entry = True
 # a list of builtin themes.
 #
 html_theme_path = guzzle_sphinx_theme.html_theme_path()
-html_theme = 'guzzle_sphinx_theme'
+html_theme = "guzzle_sphinx_theme"
 
 extensions.append("guzzle_sphinx_theme")
 
@@ -114,9 +129,9 @@ html_theme_options = {
     # Set the name of the project to appear in the sidebar
     "project_nav_name": "PowerDNS Authoritative Server",
 }
-html_favicon = 'common/favicon.ico'
+html_favicon = "common/favicon.ico"
 
-html_sidebars = { '**': ['logo-text.html', 'searchbox.html', 'relations.html', 'localtoc.html', 'sourcelink.html'] }
+html_sidebars = {"**": ["logo-text.html", "searchbox.html", "relations.html", "localtoc.html", "sourcelink.html"]}
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
@@ -127,32 +142,29 @@ html_sidebars = { '**': ['logo-text.html', 'searchbox.html', 'relations.html', '
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-html_style = 'pdns.css'
+html_static_path = ["_static"]
+html_style = "pdns.css"
 
 
 # -- Options for HTMLHelp output ------------------------------------------
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = 'PowerDNSAuthoritativedoc'
+htmlhelp_basename = "PowerDNSAuthoritativedoc"
 
 
 # -- Options for LaTeX output ---------------------------------------------
 
 latex_elements = {
-    'maxlistdepth' : '8',
+    "maxlistdepth": "8",
     # The paper size ('letterpaper' or 'a4paper').
     #
-    'papersize': 'a4paper',
-
+    "papersize": "a4paper",
     # The font size ('10pt', '11pt' or '12pt').
     #
     # 'pointsize': '10pt',
-
     # Additional stuff for the LaTeX preamble.
     #
     # 'preamble': '',
-
     # Latex figure (float) alignment
     #
     # 'figure_align': 'htbp',
@@ -162,61 +174,63 @@ latex_elements = {
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
 latex_documents = [
-    (master_doc, 'PowerDNS-Authoritative.tex', 'PowerDNS Authoritative Server Documentation',
-     'PowerDNS.COM BV', 'manual'),
+    (
+        master_doc,
+        "PowerDNS-Authoritative.tex",
+        "PowerDNS Authoritative Server Documentation",
+        "PowerDNS.COM BV",
+        "manual",
+    ),
 ]
 
-latex_logo = 'common/powerdns-logo-500px.png'
+latex_logo = "common/powerdns-logo-500px.png"
 
 # -- Options for manual page output ---------------------------------------
 
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 descriptions = {
-    'calidns': 'A DNS recursor testing tool',
-    'dnsbulktest': 'A debugging tool for intermittent resolver failures',
-    'dnsgram': 'A debugging tool for intermittent resolver failures',
-    'dnspcap2calidns': 'A tool to convert PCAPs of DNS traffic to calidns input',
-    'dnspcap2protobuf': 'A tool to convert PCAPs of DNS traffic to PowerDNS Protobuf',
-    'dnsreplay': 'A PowerDNS nameserver debugging tool',
-    'dnsscan': 'List the amount of queries per qtype in a pcap',
-    'dnsscope': 'A PowerDNS nameserver debugging tool',
-    'dnstcpbench': 'tool to perform TCP benchmarking of nameservers',
-    'dnswasher': 'A PowerDNS nameserver debugging tool',
-    'dumresp': 'A dumb DNS responder',
-    'ixfrdist': 'An IXFR/AXFR-only server that re-distributes zones',
-    'ixplore': 'A tool that provides insights into IXFRs',
-    'nproxy': 'DNS notification proxy',
-    'nsec3dig': 'Show and validate NSEC3 proofs',
-    'pdns_control': 'Control the PowerDNS nameserver',
-    'pdns_notify': 'A simple DNS NOTIFY sender',
-    'pdns_server': 'The PowerDNS Authoritative Nameserver',
-    'pdnsutil': 'PowerDNS record and DNSSEC command and control',
-    'saxfr': 'Perform AXFRs and show information about it',
-    'sdig': 'Perform a DNS query and show the results',
-    'zone2json': 'convert BIND zones to JSON',
-    'zone2ldap': 'convert zonefiles to ldif',
-    'zone2sql': 'convert BIND zones to SQL',
+    "calidns": "A DNS recursor testing tool",
+    "dnsbulktest": "A debugging tool for intermittent resolver failures",
+    "dnsgram": "A debugging tool for intermittent resolver failures",
+    "dnspcap2calidns": "A tool to convert PCAPs of DNS traffic to calidns input",
+    "dnspcap2protobuf": "A tool to convert PCAPs of DNS traffic to PowerDNS Protobuf",
+    "dnsreplay": "A PowerDNS nameserver debugging tool",
+    "dnsscan": "List the amount of queries per qtype in a pcap",
+    "dnsscope": "A PowerDNS nameserver debugging tool",
+    "dnstcpbench": "tool to perform TCP benchmarking of nameservers",
+    "dnswasher": "A PowerDNS nameserver debugging tool",
+    "dumresp": "A dumb DNS responder",
+    "ixfrdist": "An IXFR/AXFR-only server that re-distributes zones",
+    "ixplore": "A tool that provides insights into IXFRs",
+    "nproxy": "DNS notification proxy",
+    "nsec3dig": "Show and validate NSEC3 proofs",
+    "pdns_control": "Control the PowerDNS nameserver",
+    "pdns_notify": "A simple DNS NOTIFY sender",
+    "pdns_server": "The PowerDNS Authoritative Nameserver",
+    "pdnsutil": "PowerDNS record and DNSSEC command and control",
+    "saxfr": "Perform AXFRs and show information about it",
+    "sdig": "Perform a DNS query and show the results",
+    "zone2json": "convert BIND zones to JSON",
+    "zone2ldap": "convert zonefiles to ldif",
+    "zone2sql": "convert BIND zones to SQL",
 }
 man_pages = []
-for f in glob.glob('manpages/*.1.rst'):
-    srcname = '.'.join(f.split('.')[:-1])
-    destname = srcname.split('/')[-1][:-2]
-    man_pages.append((srcname, destname, descriptions.get(destname, ''),
-                      [author], 1))
-man_pages.append(('manpages/ixfrdist.yml.5', 'ixfrdist.yml',
-                  'The ixfrdist configuration file', [author], 5))
+for f in glob.glob("manpages/*.1.rst"):
+    srcname = ".".join(f.split(".")[:-1])
+    destname = srcname.split("/")[-1][:-2]
+    man_pages.append((srcname, destname, descriptions.get(destname, ""), [author], 1))
+man_pages.append(("manpages/ixfrdist.yml.5", "ixfrdist.yml", "The ixfrdist configuration file", [author], 5))
 # -- Options for Texinfo output -------------------------------------------
 
 # Grouping the document tree into Texinfo files. List of tuples
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
-#texinfo_documents = [
+# texinfo_documents = [
 #    (master_doc, 'PowerDNSRecursor', 'PowerDNS Recursor Documentation',
 #     author, 'PowerDNSRecursor', 'One line description of project.',
 #     'Miscellaneous'),
-#]
-
+# ]
 
 
 # -- Options for Epub output ----------------------------------------------
@@ -237,7 +251,7 @@ epub_copyright = copyright
 # epub_uid = ''
 
 # A list of files that should not be packed into the epub file.
-epub_exclude_files = ['search.html']
+epub_exclude_files = ["search.html"]
 
-depfile = 'sphinx.d'
-depfile_stamp = 'sphinx.stamp'
+depfile = "sphinx.d"
+depfile_stamp = "sphinx.stamp"
index 548b71a6f945cbc321a572a94d55770b69502fae..26c605d607aa49711f6b5b6afccd6eda08dc0e25 100644 (file)
@@ -8,30 +8,30 @@
 # See the COPYING file in the top-level directory.
 
 """depfile is a Sphinx extension that writes a dependency file for
-   an external build system"""
+an external build system"""
 
 import os
 import sys
 from pathlib import Path
 
-__version__ = '1.0'
+__version__ = "1.0"
+
 
 def get_infiles(env):
     for x in env.found_docs:
         yield str(env.doc2path(x))
-        yield from ((os.path.join(env.srcdir, dep)
-                    for dep in env.dependencies[x]))
+        yield from ((os.path.join(env.srcdir, dep) for dep in env.dependencies[x]))
     for mod in sys.modules.values():
-        if hasattr(mod, '__file__'):
+        if hasattr(mod, "__file__"):
             if mod.__file__:
                 yield mod.__file__
     # this is perhaps going to include unused files:
     for static_path in env.config.html_static_path + env.config.templates_path:
-        for path in Path(static_path).rglob('*'):
+        for path in Path(static_path).rglob("*"):
             yield str(path)
 
     # also include kdoc script
-    #yield str(env.config.kerneldoc_bin[1])
+    # yield str(env.config.kerneldoc_bin[1])
 
 
 def write_depfile(app, exception):
@@ -46,23 +46,20 @@ def write_depfile(app, exception):
     # its timestamp does not necessarily change when the contents change.
     # So create a timestamp file.
     if env.config.depfile_stamp:
-        with open(env.config.depfile_stamp, 'w') as f:
-            print('depfile.py: Writing ' + env.config.depfile_stamp)
+        with open(env.config.depfile_stamp, "w") as f:
+            print("depfile.py: Writing " + env.config.depfile_stamp)
 
-    with open(env.config.depfile, 'w') as f:
-        print('depfile.py: Writing ' + env.config.depfile)
+    with open(env.config.depfile, "w") as f:
+        print("depfile.py: Writing " + env.config.depfile)
         print((env.config.depfile_stamp or app.outdir) + ": \\", file=f)
         print(*get_infiles(env), file=f)
         for x in get_infiles(env):
             print(x + ":", file=f)
 
+
 def setup(app):
-    app.add_config_value('depfile', None, 'env')
-    app.add_config_value('depfile_stamp', None, 'env')
-    app.connect('build-finished', write_depfile)
+    app.add_config_value("depfile", None, "env")
+    app.add_config_value("depfile_stamp", None, "env")
+    app.connect("build-finished", write_depfile)
 
-    return dict(
-        version = __version__,
-        parallel_read_safe = True,
-        parallel_write_safe = True
-    )
+    return dict(version=__version__, parallel_read_safe=True, parallel_write_safe=True)
index 4c5d7b134f482d262814469a12a7722c3509e051..7d099acd57b0792952ccfc1726af97961821905d 100755 (executable)
@@ -40,13 +40,7 @@ def main():
     sphinx_build = venv_directory.joinpath("bin").joinpath("sphinx-build")
 
     if args.pdf_name:
-        build_args = [
-            sphinx_build,
-            "-M",
-            "latexpdf",
-            source_directory,
-            '.'
-        ]
+        build_args = [sphinx_build, "-M", "latexpdf", source_directory, "."]
     else:
         build_args = [
             sphinx_build,
@@ -56,17 +50,16 @@ def main():
             target_directory,
         ]
     subprocess.run(
-        build_args + files, # if files is empty, it means do all files
-        check=True
+        build_args + files,  # if files is empty, it means do all files
+        check=True,
     )
     if args.pdf_name:
-        os.rename(build_root.joinpath('latex').joinpath(args.pdf_name), args.pdf_name)
+        os.rename(build_root.joinpath("latex").joinpath(args.pdf_name), args.pdf_name)
+
 
 def create_argument_parser():
     """Create command-line argument parser."""
-    parser = argparse.ArgumentParser(
-        description="Build html and pdf docs for PowerDNS open source products"
-    )
+    parser = argparse.ArgumentParser(description="Build html and pdf docs for PowerDNS open source products")
     parser.add_argument(
         "--build-root",
         type=Path,
index 33599fa231d43201ddab606a475eb225e1027bb0..ede364861febc2df4e23c83c5a85dd5f1385913a 100755 (executable)
@@ -46,15 +46,13 @@ def main():
             target_directory,
         ]
         + files,
-        check=True
+        check=True,
     )
 
 
 def create_argument_parser():
     """Create command-line argument parser."""
-    parser = argparse.ArgumentParser(
-        description="Build man pages for PowerDNS open source products"
-    )
+    parser = argparse.ArgumentParser(description="Build man pages for PowerDNS open source products")
     parser.add_argument(
         "--build-root",
         type=Path,
index 8d082ece308bbb74737e48c0f53f2649fd437c52..52a03b012c5f9455c33f1c61e49766b11ee209e2 100644 (file)
@@ -5,61 +5,54 @@ import time
 # define a simple $domain
 
 ID_DOMAIN = {
-    1: 'unit.test.',
+    1: "unit.test.",
 }
 
 DOMAINS = {
-    'unit.test.': {
-        'id': 1,
-        'ttl': 300,
-        'name': 'unit.test.',
-        'notified_serial': 0,
-        'meta': {},
-        'keys': {},
-        'rr': {
-            'unit.test.' : {
-                'SOA': ["ns.unit.test. hostmaster.unit.test. 1 2 3 4 5"],
-                'NS':  ["ns1.unit.test.", "ns2.unit.test."],
+    "unit.test.": {
+        "id": 1,
+        "ttl": 300,
+        "name": "unit.test.",
+        "notified_serial": 0,
+        "meta": {},
+        "keys": {},
+        "rr": {
+            "unit.test.": {
+                "SOA": ["ns.unit.test. hostmaster.unit.test. 1 2 3 4 5"],
+                "NS": ["ns1.unit.test.", "ns2.unit.test."],
             },
-            'ns1.unit.test.': {
-               'A': ["10.0.0.1"]
-            },
-            'ns2.unit.test.': {
-               'A': ["10.0.0.2"]
-            },
-            'empty.unit.test.': {}
+            "ns1.unit.test.": {"A": ["10.0.0.1"]},
+            "ns2.unit.test.": {"A": ["10.0.0.2"]},
+            "empty.unit.test.": {},
         },
-        'kind': 'native',
+        "kind": "native",
     },
-    'master.test.': {
-        'id': 2,
-        'ttl': 300,
-        'name': 'master.test.',
-        'notified_serial': 2,
-        'meta': {},
-        'keys': {},
-        'rr': {
-            'master.test.': {
-                'SOA': ["ns.master.test. hostmaster.master.test. 1 2 3 4 5"],
+    "master.test.": {
+        "id": 2,
+        "ttl": 300,
+        "name": "master.test.",
+        "notified_serial": 2,
+        "meta": {},
+        "keys": {},
+        "rr": {
+            "master.test.": {
+                "SOA": ["ns.master.test. hostmaster.master.test. 1 2 3 4 5"],
             }
         },
-        'kind': 'master',
+        "kind": "master",
     },
 }
 
 TSIG_KEYS = {
-    'test.': {
-        'name': 'test.',
-        'algorithm': 'NULL.',
-        'content': 'NULL',
+    "test.": {
+        "name": "test.",
+        "algorithm": "NULL.",
+        "content": "NULL",
     }
 }
 
-MASTERS = {
-    'ns1.unit.test.': {
-        'ip': '10.0.0.1'
-    }
-}
+MASTERS = {"ns1.unit.test.": {"ip": "10.0.0.1"}}
+
 
 class Handler(pdns.remotebackend.Handler):
     def get_domain(self, domain):
@@ -71,131 +64,133 @@ class Handler(pdns.remotebackend.Handler):
             p = domain.find(".")
             if p == -1:
                 break
-            domain = domain[p+1:]
+            domain = domain[p + 1 :]
         return None
 
-    def do_lookup(self, qname='', qtype='', **kwargs):
+    def do_lookup(self, qname="", qtype="", **kwargs):
         domain = self.get_domain(qname)
         if domain:
             self.result = []
-            rrset = domain['rr'].get(qname, {'qtype': []})
+            rrset = domain["rr"].get(qname, {"qtype": []})
             rr = rrset.get(qtype, [])
             for r in rr:
-                self.result.append(self.record(qname=qname, qtype=qtype, content=r, ttl=domain['ttl']))
+                self.result.append(self.record(qname=qname, qtype=qtype, content=r, ttl=domain["ttl"]))
 
     def do_list(self, zonename="", **kwargs):
         domain = self.get_domain(zonename)
         if domain:
             self.result = []
-            for qname, rrset in domain['rr'].items():
+            for qname, rrset in domain["rr"].items():
                 for qtype, rr in rrset.items():
                     for r in rr:
-                        self.result.append(self.record(qname=qname, qtype=qtype, content=r, ttl=domain['ttl']))
+                        self.result.append(self.record(qname=qname, qtype=qtype, content=r, ttl=domain["ttl"]))
 
-    def do_getalldomainmetadata(self, name='', **kwargs):
+    def do_getalldomainmetadata(self, name="", **kwargs):
         domain = self.get_domain(name)
         if domain:
-            self.result = domain['meta']
+            self.result = domain["meta"]
 
-    def do_getdomainmetadata(self, name='', kind='', **kwargs):
+    def do_getdomainmetadata(self, name="", kind="", **kwargs):
         self.do_getalldomainmetadata(name=name)
         if self.result:
             self.result = self.result[kind]
 
-    def do_setdomainmetadata(self, name='', kind='', value=None, **kwargs):
+    def do_setdomainmetadata(self, name="", kind="", value=None, **kwargs):
         domain = self.get_domain(name)
         if domain:
             if value is None:
-                del domain['meta'][kind]
+                del domain["meta"][kind]
             else:
-                domain['meta'][kind] = value
+                domain["meta"][kind] = value
             self.result = True
 
-    def do_adddomainkey(self, name='', key=None, **kwargs):
+    def do_adddomainkey(self, name="", key=None, **kwargs):
         if key is None:
             key = {}
         domain = self.get_domain(name)
         if domain:
-            k_id = len(domain['keys']) + 1
-            key['id'] = k_id
-            domain['keys'][k_id] = key
+            k_id = len(domain["keys"]) + 1
+            key["id"] = k_id
+            domain["keys"][k_id] = key
             self.result = k_id
 
-    def do_getdomainkeys(self, name='', **kwargs):
+    def do_getdomainkeys(self, name="", **kwargs):
         domain = self.get_domain(name)
         if domain:
             self.result = []
-            for k_id, k in domain['keys'].items():
+            for k_id, k in domain["keys"].items():
                 self.result.append(k)
 
-    def do_activatedomainkey(self, name='', **kwargs):
+    def do_activatedomainkey(self, name="", **kwargs):
         domain = self.get_domain(name)
         if domain:
-            key = domain['keys'].get(int(kwargs['id']))
+            key = domain["keys"].get(int(kwargs["id"]))
             if key:
-                key['active'] = True
+                key["active"] = True
                 self.result = True
 
-    def do_deactivatedomainkey(self, name='', **kwargs):
+    def do_deactivatedomainkey(self, name="", **kwargs):
         domain = self.get_domain(name)
         if domain:
-            key = domain['keys'].get(int(kwargs['id']))
+            key = domain["keys"].get(int(kwargs["id"]))
             if key:
-                key['active'] = False
+                key["active"] = False
                 self.result = True
 
-    def do_publishdomainkey(self, name='', **kwargs):
+    def do_publishdomainkey(self, name="", **kwargs):
         domain = self.get_domain(name)
         if domain:
-            key = domain['keys'].get(int(kwargs['id']))
+            key = domain["keys"].get(int(kwargs["id"]))
             if key:
-                key['published'] = True
+                key["published"] = True
                 self.result = True
 
-    def do_unpublishdomainkey(self, name='', **kwargs):
+    def do_unpublishdomainkey(self, name="", **kwargs):
         domain = self.get_domain(name)
         if domain:
-            key = domain['keys'].get(int(kwargs['id']))
+            key = domain["keys"].get(int(kwargs["id"]))
             if key:
-                key['published'] = False
+                key["published"] = False
                 self.result = True
 
-    def do_removedomainkey(self, name='', **kwargs):
+    def do_removedomainkey(self, name="", **kwargs):
         domain = self.get_domain(name)
         if domain:
-            k_id = int(kwargs['id'])
-            if k_id in domain['keys']:
-                del domain['keys'][k_id]
+            k_id = int(kwargs["id"])
+            if k_id in domain["keys"]:
+                del domain["keys"][k_id]
                 self.result = True
 
-    def do_getbeforeandafternamesabsolute(self, qname='', **kwargs):
-        if qname == 'middle.unit.test.':
+    def do_getbeforeandafternamesabsolute(self, qname="", **kwargs):
+        if qname == "middle.unit.test.":
             self.result = {
-                'unhashed': 'middle.',
-                'before': 'begin.',
-                'after': 'stop.',
+                "unhashed": "middle.",
+                "before": "begin.",
+                "after": "stop.",
             }
 
     def do_setnotified(self, **kwargs):
-        d_id = int(kwargs['id'])
+        d_id = int(kwargs["id"])
         domain_name = ID_DOMAIN.get(d_id)
         domain = DOMAINS.get(domain_name)
         if domain:
-            domain['notified_serial'] = kwargs['serial']
+            domain["notified_serial"] = kwargs["serial"]
             self.result = True
 
     def fill_domaininfo(self, name=""):
         domain = self.get_domain(name)
         if domain:
-            self.result.append({
-                'id': domain['id'],
-                'zone': domain['name'],
-                'masters': MASTERS,
-                'notified_serial': domain['notified_serial'],
-                'serial': domain['notified_serial'],
-                'last_check': int(time.time()),
-                'kind': domain['kind']
-            })
+            self.result.append(
+                {
+                    "id": domain["id"],
+                    "zone": domain["name"],
+                    "masters": MASTERS,
+                    "notified_serial": domain["notified_serial"],
+                    "serial": domain["notified_serial"],
+                    "last_check": int(time.time()),
+                    "kind": domain["kind"],
+                }
+            )
 
     def do_getdomaininfo(self, name="", **kwargs):
         self.result = []
@@ -203,82 +198,74 @@ class Handler(pdns.remotebackend.Handler):
         if self.result:
             self.result = self.result[0]
 
-    def do_ismaster(self, name='', ip='', **kwargs):
+    def do_ismaster(self, name="", ip="", **kwargs):
         ips = MASTERS.get(name, [])
         if ip in ips:
             self.result = True
 
-    def do_supermasterbackend(self, domain='', nsset=[], **kwargs):
+    def do_supermasterbackend(self, domain="", nsset=[], **kwargs):
         d_id = len(DOMAINS) + 1
         dom = domain.lower()
         domainObject = {
-            'id': d_id,
-            'name': dom,
-            'kind': 'slave',
-            'notified_serial': 0,
-            'meta': {},
-            'keys': {},
-            'rr': {
+            "id": d_id,
+            "name": dom,
+            "kind": "slave",
+            "notified_serial": 0,
+            "meta": {},
+            "keys": {},
+            "rr": {
                 dom: {
-                    'SOA': ["ns.%s hostmaster.%s 1 2 3 4 5" % (dom, dom)],
+                    "SOA": ["ns.%s hostmaster.%s 1 2 3 4 5" % (dom, dom)],
                 }
             },
-            'ttl': 300,
+            "ttl": 300,
         }
 
         nsset = []
         for rr in nsset:
-            nsset.append(self.record(qname=rr['qname'], qtype=rr['qtype'], content=rr['content'], ttl=rr['ttl']))
+            nsset.append(self.record(qname=rr["qname"], qtype=rr["qtype"], content=rr["content"], ttl=rr["ttl"]))
 
-        domainObject['rr'][dom]['NS'] = nsset
+        domainObject["rr"][dom]["NS"] = nsset
         DOMAINS[dom] = domainObject
 
-        self.result = [{
-            'nameserver': 'ns.%s' % dom,
-            'account': ''
-        }]
+        self.result = [{"nameserver": "ns.%s" % dom, "account": ""}]
 
-
-    def do_createslavedomain(self, domain='', **kwargs):
+    def do_createslavedomain(self, domain="", **kwargs):
         d_id = len(DOMAINS) + 1
         dom = domain.lower()
         domainObject = {
-            'id': d_id,
-            'name': dom,
-            'kind': 'slave',
-            'notified_serial': 0,
-            'ttl': 300,
-            'meta': {},
-            'keys': {},
-            'rr': {
-            }
+            "id": d_id,
+            "name": dom,
+            "kind": "slave",
+            "notified_serial": 0,
+            "ttl": 300,
+            "meta": {},
+            "keys": {},
+            "rr": {},
         }
         DOMAINS[dom] = domainObject
 
         self.result = True
 
     def do_feedrecord(self, rr={}, **kwargs):
-        qname = rr['qname']
-        qtype = rr['qtype']
+        qname = rr["qname"]
+        qtype = rr["qtype"]
         domain = self.get_domain(qname)
         if domain:
-            if not qname in domain['rr']:
-                domain['rr'][qname] = {qtype: []}
-            elif not qtype in domain['rr'][qname]:
-                 domain['rr'][qname][qtype] = []
-            domain['rr'][qname][qtype].append(self.record(
-                qname=qname,
-                qtype=qtype,
-                content=rr['content'],
-                ttl=rr.get('ttl', domain['ttl']))
+            if not qname in domain["rr"]:
+                domain["rr"][qname] = {qtype: []}
+            elif not qtype in domain["rr"][qname]:
+                domain["rr"][qname][qtype] = []
+            domain["rr"][qname][qtype].append(
+                self.record(qname=qname, qtype=qtype, content=rr["content"], ttl=rr.get("ttl", domain["ttl"]))
             )
             self.result = True
 
-    def do_replacerrset(self, qname='', qtype='', rrset=[], **kwargs):
+    def do_replacerrset(self, qname="", qtype="", rrset=[], **kwargs):
         domain = self.get_domain(qname)
-        if domain and qname in domain['rr']:
-            if qtype in domain['rr'][qname]:
-                del domain['rr'][qname][qtype]
+        if domain and qname in domain["rr"]:
+            if qtype in domain["rr"][qname]:
+                del domain["rr"][qname][qtype]
         for row in rrset:
             self.do_feedrecord(rr=row)
 
@@ -288,15 +275,15 @@ class Handler(pdns.remotebackend.Handler):
     def do_feedents3(self, **kwargs):
         self.result = True
 
-    def do_gettsigkey(self, name='', **kwargs):
+    def do_gettsigkey(self, name="", **kwargs):
         if name in TSIG_KEYS:
             self.result = TSIG_KEYS[name]
 
-    def do_settsigkey(self, name='', algorithm='', content='', **kwargs):
+    def do_settsigkey(self, name="", algorithm="", content="", **kwargs):
         TSIG_KEYS[name] = {
-            'name': name,
-            'algorithm': algorithm,
-            'content': content,
+            "name": name,
+            "algorithm": algorithm,
+            "content": content,
         }
         self.result = True
 
@@ -305,7 +292,7 @@ class Handler(pdns.remotebackend.Handler):
         for name, key in TSIG_KEYS.items():
             self.result.append(key)
 
-    def do_deletetsigkey(self, name='', **kwargs):
+    def do_deletetsigkey(self, name="", **kwargs):
         if name in TSIG_KEYS:
             del TSIG_KEYS[name]
             self.result = True
@@ -319,7 +306,7 @@ class Handler(pdns.remotebackend.Handler):
     def do_aborttransaction(self, **kwargs):
         self.result = True
 
-    def do_directbackendcmd(self, query='', **kwargs):
+    def do_directbackendcmd(self, query="", **kwargs):
         self.result = query
 
     def do_getalldomains(self, **kwargs):
@@ -330,5 +317,5 @@ class Handler(pdns.remotebackend.Handler):
     def do_getupdatedmasters(self, **kwargs):
         self.result = []
         for name in DOMAINS.keys():
-            if DOMAINS[name]['kind'] == 'master':
+            if DOMAINS[name]["kind"] == "master":
                 self.fill_domaininfo(name=name)
index 59a8f0bec4a20855e6711487edf72a6613ee4b93..acd68d00d7a4585827809a5e60612934c86f7594 100755 (executable)
@@ -7,7 +7,7 @@ from pdns.remotebackend import Handler
 class BackendHandler(Handler):
     def __init__(self, options={}):
         super().__init__(options=options)
-        self.dbpath = options['dbpath']
+        self.dbpath = options["dbpath"]
         self.db = sqlite3.connect(self.dbpath)
 
     def get_domain_id(self, name):
@@ -18,43 +18,52 @@ class BackendHandler(Handler):
             raise KeyError
         return int(row[0])
 
-    def record(self, qname='', qtype='', content='', ttl=1, prio=0, auth=1, domain_id=-1):
+    def record(self, qname="", qtype="", content="", ttl=1, prio=0, auth=1, domain_id=-1):
         """Generate one record"""
         if ttl == -1:
             ttl = self.ttl
-        if qtype in ('MX', 'SRV'):
+        if qtype in ("MX", "SRV"):
             content = "%d %s" % (prio, content)
-        return {'qtype': qtype, 'qname': qname, 'content': content,
-                'ttl': ttl, 'auth': auth, 'domain_id': domain_id}
+        return {"qtype": qtype, "qname": qname, "content": content, "ttl": ttl, "auth": auth, "domain_id": domain_id}
 
     # ends up here as qname=qname, id=id
     def getbeforename(self, **kwargs):
-        cur = self.db.execute("SELECT ordername FROM records WHERE ordername < :qname AND domain_id = :id ORDER BY ordername DESC LIMIT 1", kwargs)
+        cur = self.db.execute(
+            "SELECT ordername FROM records WHERE ordername < :qname AND domain_id = :id ORDER BY ordername DESC LIMIT 1",
+            kwargs,
+        )
         row = cur.fetchone()
         if not row:
-            cur = self.db.execute("SELECT ordername FROM records WHERE domain_id = :id ORDER by ordername DESC LIMIT 1", kwargs)
+            cur = self.db.execute(
+                "SELECT ordername FROM records WHERE domain_id = :id ORDER by ordername DESC LIMIT 1", kwargs
+            )
             row = cur.fetchone()
         result = row[0]
         if row[0] is None:
-            result = ''
+            result = ""
         return result
 
     def getaftername(self, **kwargs):
-        cur = self.db.execute("SELECT ordername FROM records WHERE ordername > :qname AND domain_id = :id ORDER BY ordername LIMIT 1", kwargs)
+        cur = self.db.execute(
+            "SELECT ordername FROM records WHERE ordername > :qname AND domain_id = :id ORDER BY ordername LIMIT 1",
+            kwargs,
+        )
         row = cur.fetchone()
         if row is None:
-            cur = self.db.execute("SELECT ordername FROM records WHERE domain_id = :id ORDER by ordername LIMIT 1", kwargs)
+            cur = self.db.execute(
+                "SELECT ordername FROM records WHERE domain_id = :id ORDER by ordername LIMIT 1", kwargs
+            )
             row = cur.fetchone()
         result = row[0]
         if row[0] is None:
-            result = ''
+            result = ""
         return result
 
     def do_getbeforeandafternamesabsolute(self, **kwargs):
         self.result = {
-            'before':   self.getbeforename(**kwargs),
-            'after':    self.getaftername(**kwargs),
-            'unhashed': kwargs['qname']
+            "before": self.getbeforename(**kwargs),
+            "after": self.getaftername(**kwargs),
+            "unhashed": kwargs["qname"],
         }
 
     def do_getbeforeandafternames(self, **kwargs):
@@ -62,23 +71,22 @@ class BackendHandler(Handler):
 
     def do_getdomainkeys(self, name, **kwargs):
         self.result = []
-        cur = self.db.execute("SELECT cryptokeys.id, flags, active, published, content FROM domains JOIN cryptokeys ON domains.id = cryptokeys.domain_id WHERE domains.name = :name", {'name':name})
+        cur = self.db.execute(
+            "SELECT cryptokeys.id, flags, active, published, content FROM domains JOIN cryptokeys ON domains.id = cryptokeys.domain_id WHERE domains.name = :name",
+            {"name": name},
+        )
         for row in cur.fetchall():
-            self.result.append({
-                'id': row[0],
-                'flags': row[1],
-                'active': row[2] != 0,
-                'published': row[3],
-                'content': row[4]
-            })
+            self.result.append(
+                {"id": row[0], "flags": row[1], "active": row[2] != 0, "published": row[3], "content": row[4]}
+            )
         if len(self.result) == 0:
             self.result = False
         self.log.append(self.dbpath)
 
-    def do_lookup(self, qname='', qtype='', domain_id=-1, **kwargs):
+    def do_lookup(self, qname="", qtype="", domain_id=-1, **kwargs):
         self.result = []
-        if kwargs.get('zone-id', -1) > 0:
-            domain_id = kwargs['zone-id']
+        if kwargs.get("zone-id", -1) > 0:
+            domain_id = kwargs["zone-id"]
         if domain_id > -1:
             if qtype == "ANY":
                 sql = "SELECT domain_id,name,type,content,ttl,prio,auth FROM records WHERE name = :qname AND domain_id = :domain_id"
@@ -89,33 +97,43 @@ class BackendHandler(Handler):
                 sql = "SELECT domain_id,name,type,content,ttl,prio,auth FROM records WHERE name = :qname"
             else:
                 sql = "SELECT domain_id,name,type,content,ttl,prio,auth FROM records WHERE name = :qname AND type = :qtype"
-        cur = self.db.execute(sql, {'qname': qname, 'qtype': qtype, 'domain_id': domain_id})
-        for row in cur.fetchall():            
-            self.result.append(self.record(qname=row[1],qtype=row[2],content=row[3],ttl=row[4],prio=row[5],auth=row[6],domain_id=row[0]))
+        cur = self.db.execute(sql, {"qname": qname, "qtype": qtype, "domain_id": domain_id})
+        for row in cur.fetchall():
+            self.result.append(
+                self.record(
+                    qname=row[1], qtype=row[2], content=row[3], ttl=row[4], prio=row[5], auth=row[6], domain_id=row[0]
+                )
+            )
 
-    def do_getdomaininfo(self, name='', **kwargs):
+    def do_getdomaininfo(self, name="", **kwargs):
         self.result = False
-        cur = self.db.execute("SELECT domain_id,name,content FROM records WHERE name = :name AND type = 'SOA'", {'name': name})
+        cur = self.db.execute(
+            "SELECT domain_id,name,content FROM records WHERE name = :name AND type = 'SOA'", {"name": name}
+        )
         for row in cur.fetchall():
             self.result = {
-                'zone': row[1],
-                'serial': int(row[2].split(' ')[2]),
-                'kind': 'native',
-                'id': row[0],
+                "zone": row[1],
+                "serial": int(row[2].split(" ")[2]),
+                "kind": "native",
+                "id": row[0],
             }
 
     def do_getalldomains(self):
         self.result = []
-        cur = self.db.execute("SELECT domain_id,name,content FROM records WHERE name = :name AND type = 'SOA'", {'name': name})
+        cur = self.db.execute(
+            "SELECT domain_id,name,content FROM records WHERE name = :name AND type = 'SOA'", {"name": name}
+        )
         for row in cur.fetchall():
-            self.result.append({
-                'zone': row[1],
-                'serial': int(row[2].split(' ')[2]),
-                'kind': 'native',
-                'id': row[0],
-            })
-
-    def do_list(self, zonename='', domain_id=-1, **kwargs):
+            self.result.append(
+                {
+                    "zone": row[1],
+                    "serial": int(row[2].split(" ")[2]),
+                    "kind": "native",
+                    "id": row[0],
+                }
+            )
+
+    def do_list(self, zonename="", domain_id=-1, **kwargs):
         if domain_id == -1:
             try:
                 domain_id = self.get_domain_id(zonename)
@@ -123,18 +141,33 @@ class BackendHandler(Handler):
                 return
         if domain_id > -1:
             self.result = []
-            cur = self.db.execute("SELECT domain_id,name,type,content,ttl,prio,auth FROM records WHERE domain_id = ?", (domain_id,))
+            cur = self.db.execute(
+                "SELECT domain_id,name,type,content,ttl,prio,auth FROM records WHERE domain_id = ?", (domain_id,)
+            )
             for row in cur.fetchall():
-                self.result.append(self.record(qname=row[1],qtype=row[2],content=row[3],ttl=row[4],prio=row[5],auth=row[6],domain_id=row[0]))
+                self.result.append(
+                    self.record(
+                        qname=row[1],
+                        qtype=row[2],
+                        content=row[3],
+                        ttl=row[4],
+                        prio=row[5],
+                        auth=row[6],
+                        domain_id=row[0],
+                    )
+                )
 
     def do_adddomainkey(self, name, key, **kwargs):
         try:
             domain_id = self.get_domain_id(name)
         except KeyError:
             return
-        key['domain_id'] = domain_id
+        key["domain_id"] = domain_id
 
-        cur = self.db.execute("INSERT INTO cryptokeys (domain_id, flags, active, published, content) VALUES(:domain_id, :flags, :active, :published, :content)", key)
+        cur = self.db.execute(
+            "INSERT INTO cryptokeys (domain_id, flags, active, published, content) VALUES(:domain_id, :flags, :active, :published, :content)",
+            key,
+        )
         self.db.commit()
 
         self.result = cur.lastrowid
@@ -142,10 +175,10 @@ class BackendHandler(Handler):
 
     def do_deactivatedomainkey(self, **kwargs):
         try:
-            domain_id = self.get_domain_id(kwargs['name'])
+            domain_id = self.get_domain_id(kwargs["name"])
         except KeyError:
             return
-        kwargs['domain_id'] = domain_id
+        kwargs["domain_id"] = domain_id
 
         self.db.execute("UPDATE cryptokeys SET active = 0 WHERE domain_id = :domain_id AND id = :id", kwargs)
         self.db.commit()
@@ -154,10 +187,10 @@ class BackendHandler(Handler):
 
     def do_activatedomainkey(self, **kwargs):
         try:
-            domain_id = self.get_domain_id(kwargs['name'])
+            domain_id = self.get_domain_id(kwargs["name"])
         except KeyError:
             return
-        kwargs['domain_id'] = domain_id
+        kwargs["domain_id"] = domain_id
 
         self.db.execute("UPDATE cryptokeys SET active = 1 WHERE domain_id = :domain_id AND id = :id", kwargs)
         self.db.commit()
@@ -166,10 +199,10 @@ class BackendHandler(Handler):
 
     def do_unpublishdomainkey(self, **kwargs):
         try:
-            domain_id = self.get_domain_id(kwargs['name'])
+            domain_id = self.get_domain_id(kwargs["name"])
         except KeyError:
             return
-        kwargs['domain_id'] = domain_id
+        kwargs["domain_id"] = domain_id
 
         self.db.execute("UPDATE cryptokeys SET published = 0 WHERE domain_id = :domain_id AND id = :id", kwargs)
         self.db.commit()
@@ -178,10 +211,10 @@ class BackendHandler(Handler):
 
     def do_publishdomainkey(self, **kwargs):
         try:
-            domain_id = self.get_domain_id(kwargs['name'])
+            domain_id = self.get_domain_id(kwargs["name"])
         except KeyError:
             return
-        kwargs['domain_id'] = domain_id
+        kwargs["domain_id"] = domain_id
 
         self.db.execute("UPDATE cryptokeys SET published = 1 WHERE domain_id = :domain_id AND id = :id", kwargs)
         self.db.commit()
@@ -189,7 +222,9 @@ class BackendHandler(Handler):
         self.result = True
 
     def do_getalldomainmetadata(self, name, **kwargs):
-        cur = self.db.execute("SELECT kind, content FROM domainmetadata JOIN domains WHERE name = :name", {'name': name})
+        cur = self.db.execute(
+            "SELECT kind, content FROM domainmetadata JOIN domains WHERE name = :name", {"name": name}
+        )
         self.result = {}
         for row in cur.fetchall():
             if not row[0] in self.result:
@@ -197,7 +232,10 @@ class BackendHandler(Handler):
             self.result[row[0]].append(row[1])
 
     def do_getdomainmetadata(self, name, kind, **kwargs):
-        cur = self.db.execute("SELECT content FROM domainmetadata JOIN domains WHERE name = :name AND kind = :kind", {'name': name, 'kind': kind})
+        cur = self.db.execute(
+            "SELECT content FROM domainmetadata JOIN domains WHERE name = :name AND kind = :kind",
+            {"name": name, "kind": kind},
+        )
         self.result = cur.fetchall()
 
     def do_setdomainmetadata(self, name, kind, value, **kwargs):
@@ -206,16 +244,15 @@ class BackendHandler(Handler):
         except KeyError:
             return
 
-        self.db.execute("DELETE FROM domainmetadata WHERE domain_id = :domain_id AND kind = :kind", {
-                'domain_id': domain_id,
-                'kind': kind
-        })
+        self.db.execute(
+            "DELETE FROM domainmetadata WHERE domain_id = :domain_id AND kind = :kind",
+            {"domain_id": domain_id, "kind": kind},
+        )
         if value:
-            self.db.execute("INSERT INTO domainmetadata (domain_id,kind,content) VALUES(:domain_id, :kind, :content)", {
-                'domain_id': domain_id,
-                'kind': kind,
-                'content': content
-            })
+            self.db.execute(
+                "INSERT INTO domainmetadata (domain_id,kind,content) VALUES(:domain_id, :kind, :content)",
+                {"domain_id": domain_id, "kind": kind, "content": content},
+            )
         self.db.commit()
 
     def do_starttransaction(self, trxid, **kwargs):
index 18ff5667542d4219c288440bfe34c14680eb688a..62973f3a3629776b496ea25ac295fff348a8dd79 100755 (executable)
@@ -6,9 +6,10 @@ import re
 
 from urllib.parse import parse_qsl, urlparse, unquote
 
+
 class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
     def __init__(self, *args, **kwargs):
-        self.handler = kwargs['handler']
+        self.handler = kwargs["handler"]
         super().__init__(*args)
 
     def url_to_args(self):
@@ -17,52 +18,59 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
         parts.pop(0)
         self.method = None
 
-        if parts.pop(0) != 'dns':
+        if parts.pop(0) != "dns":
             return
 
         self.method = parts.pop(0).lower()
         self.args = {}
 
-        if self.method == 'lookup':
-            self.args['qname'] = parts.pop(0)
-            self.args['qtype'] = parts.pop(0)
-        elif self.method == 'list':
-            self.args['id'] = int(parts.pop(0))
-            self.args['zonename'] = parts.pop(0)
-        elif self.method in ('getbeforeandafternamesabsolute', 'getbeforeandafternames'):
-            self.args['id'] = int(parts.pop(0))
-            self.args['qname'] = parts.pop(0)
-        elif self.method in ('getdomainmetadata', 'setdomainmetadata'):
-            self.args['name'] = parts.pop(0)
-            self.args['kind'] = parts.pop(0)
-        elif self.method == 'getdomainkeys':
-            self.args['name'] = parts.pop(0)
-        elif self.method in ('removedomainkey', 'activatedomainkey', 'deactivatedomainkey'):
-            self.args['id'] = int(parts.pop(0))
-            self.args['name'] = parts.pop(0)
-        elif self.method in ('adddomainkey', 'gettsigkey', 'getdomaininfo', 'settsigkey', 'deletetsigkey', 'getalldomainmetadata'):
-            self.args['name'] = parts.pop(0)
-        elif self.method == 'setnotified':
-            self.args['id'] = int(parts.pop(0))
-        elif self.method == 'feedents':
-            self.args['id'] = int(parts.pop(0))
-            self.args['trxid'] = int(parts.pop(0))
-        elif self.method == 'ismaster':
-            self.args['name'] = parts.pop(0)
-            self.args['ip'] = parts.pop(0)
-        elif self.method in ('supermasterbackend', 'createslavedomain'):
-            self.args['ip'] = parts.pop(0)
-            self.args['domain'] = parts.pop(0)
-        elif self.method in ('feedents3', 'starttransaction'):
-            self.args['id'] = int(parts.pop(0))
-            self.args['domain'] = parts.pop(0)
-            self.args['trxid'] = int(parts.pop(0))
-        elif self.method in ('feedrecord', 'committransaction', 'aborttransaction'):
-            self.args['trxid'] = int(parts.pop(0))
-        elif self.method == 'replacerrset':
-            self.args['id'] = int(parts.pop(0))
-            self.args['qname'] = parts.pop(0)
-            self.args['qtype'] = parts.pop(0)
+        if self.method == "lookup":
+            self.args["qname"] = parts.pop(0)
+            self.args["qtype"] = parts.pop(0)
+        elif self.method == "list":
+            self.args["id"] = int(parts.pop(0))
+            self.args["zonename"] = parts.pop(0)
+        elif self.method in ("getbeforeandafternamesabsolute", "getbeforeandafternames"):
+            self.args["id"] = int(parts.pop(0))
+            self.args["qname"] = parts.pop(0)
+        elif self.method in ("getdomainmetadata", "setdomainmetadata"):
+            self.args["name"] = parts.pop(0)
+            self.args["kind"] = parts.pop(0)
+        elif self.method == "getdomainkeys":
+            self.args["name"] = parts.pop(0)
+        elif self.method in ("removedomainkey", "activatedomainkey", "deactivatedomainkey"):
+            self.args["id"] = int(parts.pop(0))
+            self.args["name"] = parts.pop(0)
+        elif self.method in (
+            "adddomainkey",
+            "gettsigkey",
+            "getdomaininfo",
+            "settsigkey",
+            "deletetsigkey",
+            "getalldomainmetadata",
+        ):
+            self.args["name"] = parts.pop(0)
+        elif self.method == "setnotified":
+            self.args["id"] = int(parts.pop(0))
+        elif self.method == "feedents":
+            self.args["id"] = int(parts.pop(0))
+            self.args["trxid"] = int(parts.pop(0))
+        elif self.method == "ismaster":
+            self.args["name"] = parts.pop(0)
+            self.args["ip"] = parts.pop(0)
+        elif self.method in ("supermasterbackend", "createslavedomain"):
+            self.args["ip"] = parts.pop(0)
+            self.args["domain"] = parts.pop(0)
+        elif self.method in ("feedents3", "starttransaction"):
+            self.args["id"] = int(parts.pop(0))
+            self.args["domain"] = parts.pop(0)
+            self.args["trxid"] = int(parts.pop(0))
+        elif self.method in ("feedrecord", "committransaction", "aborttransaction"):
+            self.args["trxid"] = int(parts.pop(0))
+        elif self.method == "replacerrset":
+            self.args["id"] = int(parts.pop(0))
+            self.args["qname"] = parts.pop(0)
+            self.args["qtype"] = parts.pop(0)
         assert len(parts) == 0, parts
 
         self.parse_qsl(url.query)
@@ -86,20 +94,20 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
                     k1 = m.group(1)
                     k2 = m.group(2)
                     if k1 not in res:
-                        if k2 == '':
+                        if k2 == "":
                             res[k1] = list()
                         else:
                             res[k1] = {}
-                    if k2 == '':
+                    if k2 == "":
                         res[k1].append(value)
-                    else:                        
+                    else:
                         res[k1][k2] = value
                 else:
                     res[key] = value
         self.args = self.args | res
 
     def do_GET(self):
-        if self.path == '/ping':
+        if self.path == "/ping":
             self.send_response(200)
             self.end_headers()
             self.wfile.write("pong".encode())
@@ -116,7 +124,7 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
         self.do_POST()
 
     def do_POST(self):
-        self.url_to_args()        
+        self.url_to_args()
 
         if not self.method:
             self.send_error(404)
@@ -124,26 +132,26 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
 
         try:
             length = 0
-            if 'content-length' in self.headers:
-                length = int(self.headers.get('content-length'))
+            if "content-length" in self.headers:
+                length = int(self.headers.get("content-length"))
             if length > 0:
                 qs = self.rfile.read(length).decode()
                 self.parse_qsl(qs)
 
             if self.method == "adddomainkey":
-                self.args['key'] = {
-                    'flags': self.args['flags'],
-                    'active': self.args['active'],
-                    'published': self.args['published'],
-                    'content': self.args['content']
+                self.args["key"] = {
+                    "flags": self.args["flags"],
+                    "active": self.args["active"],
+                    "published": self.args["published"],
+                    "content": self.args["content"],
                 }
-                del self.args['flags']
-                del self.args['active']
-                del self.args['published']
-                del self.args['content']
+                del self.args["flags"]
+                del self.args["active"]
+                del self.args["published"]
+                del self.args["content"]
 
-            if 'serial' in self.args:
-                self.args['serial'] = int(self.args['serial'])
+            if "serial" in self.args:
+                self.args["serial"] = int(self.args["serial"])
 
             method = "do_%s" % self.method
 
@@ -152,14 +160,14 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
 
             if callable(getattr(self.handler, method, None)):
                 getattr(self.handler, method)(**self.args)
-                result = json.dumps({'result':self.handler.result,'log':self.handler.log}).encode()
+                result = json.dumps({"result": self.handler.result, "log": self.handler.log}).encode()
                 self.send_response(200)
-                self.send_header("content-type", "text/javascript");
+                self.send_header("content-type", "text/javascript")
                 self.send_header("content-length", len(result))
                 self.end_headers()
                 self.wfile.write(result)
             else:
-                self.send_error(404, message=json.dumps({'error': 'No such method'}))
+                self.send_error(404, message=json.dumps({"error": "No such method"}))
         except BrokenPipeError as e2:
             raise e2
         except Exception as e:
index a029ffb4aec644f740e7839a33d90ea3d9fee315..7cd71d00e30fb9bf0d12e327121565a3ad6b4d6d 100755 (executable)
@@ -5,21 +5,24 @@ from backend import BackendHandler
 from dnsbackend import DNSBackendHandler
 import os
 
+
 class DNSBackendServer(http.server.HTTPServer):
     def __init__(self, *args, **kwargs):
         path = os.path.dirname(os.path.realpath(__file__))
-        self.handler = BackendHandler(options={'dbpath': os.path.join(path, 'remote.sqlite3')})
+        self.handler = BackendHandler(options={"dbpath": os.path.join(path, "remote.sqlite3")})
         super().__init__(*args, **kwargs)
 
     def finish_request(self, request, client_address):
         """Finish one request by instantiating RequestHandlerClass."""
         self.RequestHandlerClass(request, client_address, self, handler=self.handler)
 
+
 def main():
-    server = DNSBackendServer(('', 62434), DNSBackendHandler)
+    server = DNSBackendServer(("", 62434), DNSBackendHandler)
     try:
         server.serve_forever()
     except KeyboardInterrupt:
         pass
 
+
 main()
index 997ad4b05a4af9ad1e8d62b6278fb097eec4f634..e6a40191697e57a9623e057390af0a086f90bac9 100755 (executable)
@@ -4,9 +4,13 @@ from pdns.remotebackend import PipeConnector
 from backend import BackendHandler
 import os
 
+
 def main():
     path = os.path.dirname(os.path.realpath(__file__))
-    connector = PipeConnector(BackendHandler, options={'dbpath': os.path.join(path, 'remote.sqlite3'), 'rawlog':'/tmp/raw.json'})
+    connector = PipeConnector(
+        BackendHandler, options={"dbpath": os.path.join(path, "remote.sqlite3"), "rawlog": "/tmp/raw.json"}
+    )
     connector.run()
 
+
 main()
index 997ad4b05a4af9ad1e8d62b6278fb097eec4f634..e6a40191697e57a9623e057390af0a086f90bac9 100755 (executable)
@@ -4,9 +4,13 @@ from pdns.remotebackend import PipeConnector
 from backend import BackendHandler
 import os
 
+
 def main():
     path = os.path.dirname(os.path.realpath(__file__))
-    connector = PipeConnector(BackendHandler, options={'dbpath': os.path.join(path, 'remote.sqlite3'), 'rawlog':'/tmp/raw.json'})
+    connector = PipeConnector(
+        BackendHandler, options={"dbpath": os.path.join(path, "remote.sqlite3"), "rawlog": "/tmp/raw.json"}
+    )
     connector.run()
 
+
 main()
index c3bb1c60c9a3f8e504b13805c217e52f8233446c..373039853a264c6559d855cbea82b79da635286d 100755 (executable)
@@ -5,18 +5,19 @@ import json
 import os
 from backend import BackendHandler
 
+
 def run(socket, handler):
     while True:
         message = socket.recv()
         try:
             message = json.loads(message.decode().strip())
-            method = "do_%s" % message['method'].lower()
-            args = message['parameters']
+            method = "do_%s" % message["method"].lower()
+            args = message["parameters"]
             handler.result = False
             handler.log = []
             if callable(getattr(handler, method, None)):
                 getattr(handler, method)(**args)
-                result = json.dumps({'result': handler.result,'log': handler.log})
+                result = json.dumps({"result": handler.result, "log": handler.log})
                 socket.send(result.encode())
         except KeyboardInterrupt as e3:
             return
@@ -24,7 +25,7 @@ def run(socket, handler):
             raise e2
         except Exception as e:
             print(e)
-            socket.send(json.dumps({'result':False}).encode())
+            socket.send(json.dumps({"result": False}).encode())
 
 
 def main():
@@ -32,7 +33,7 @@ def main():
     context = zmq.Context()
     socket = context.socket(zmq.REP)
     socket.bind("ipc:///tmp/pdns.0")
-    handler = BackendHandler(options={'dbpath': os.path.join(path, 'remote.sqlite3')})
+    handler = BackendHandler(options={"dbpath": os.path.join(path, "remote.sqlite3")})
 
     try:
         run(socket, handler)
@@ -40,5 +41,6 @@ def main():
         pass
 
     os.unlink("/tmp/remotebackend.0")
+
+
 main()
index aa2ba3383625479708e82a0dde536007a1929fbe..6168167fe09b8e127cf31897a937211ffd418f65 100755 (executable)
@@ -7,6 +7,7 @@ import re
 from pdns_unittest import Handler
 from urllib.parse import parse_qsl, urlparse, unquote
 
+
 class DNSBackendServer(http.server.HTTPServer):
     def __init__(self, *args, **kwargs):
         self.handler = Handler()
@@ -19,7 +20,7 @@ class DNSBackendServer(http.server.HTTPServer):
 
 class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
     def __init__(self, *args, **kwargs):
-        self.handler = kwargs['handler']
+        self.handler = kwargs["handler"]
         super().__init__(*args)
 
     def url_to_args(self):
@@ -28,52 +29,59 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
         parts.pop(0)
         self.method = None
 
-        if parts.pop(0) != 'dns':
+        if parts.pop(0) != "dns":
             return
 
         self.method = parts.pop(0).lower()
         self.args = {}
 
-        if self.method == 'lookup':
-            self.args['qname'] = parts.pop(0)
-            self.args['qtype'] = parts.pop(0)
-        elif self.method == 'list':
-            self.args['id'] = int(parts.pop(0))
-            self.args['zonename'] = parts.pop(0)
-        elif self.method in ('getbeforeandafternamesabsolute', 'getbeforeandafternames'):
-            self.args['id'] = int(parts.pop(0))
-            self.args['qname'] = parts.pop(0)
-        elif self.method in ('getdomainmetadata', 'setdomainmetadata'):
-            self.args['name'] = parts.pop(0)
-            self.args['kind'] = parts.pop(0)
-        elif self.method == 'getdomainkeys':
-            self.args['name'] = parts.pop(0)
-        elif self.method in ('removedomainkey', 'activatedomainkey', 'deactivatedomainkey'):
-            self.args['id'] = int(parts.pop(0))
-            self.args['name'] = parts.pop(0)
-        elif self.method in ('adddomainkey', 'gettsigkey', 'getdomaininfo', 'settsigkey', 'deletetsigkey', 'getalldomainmetadata'):
-            self.args['name'] = parts.pop(0)
-        elif self.method == 'setnotified':
-            self.args['id'] = int(parts.pop(0))
-        elif self.method == 'feedents':
-            self.args['id'] = int(parts.pop(0))
-            self.args['trxid'] = int(parts.pop(0))
-        elif self.method == 'ismaster':
-            self.args['name'] = parts.pop(0)
-            self.args['ip'] = parts.pop(0)
-        elif self.method in ('supermasterbackend', 'createslavedomain'):
-            self.args['ip'] = parts.pop(0)
-            self.args['domain'] = parts.pop(0)
-        elif self.method in ('feedents3', 'starttransaction'):
-            self.args['id'] = int(parts.pop(0))
-            self.args['domain'] = parts.pop(0)
-            self.args['trxid'] = int(parts.pop(0))
-        elif self.method in ('feedrecord', 'committransaction', 'aborttransaction'):
-            self.args['trxid'] = int(parts.pop(0))
-        elif self.method == 'replacerrset':
-            self.args['id'] = int(parts.pop(0))
-            self.args['qname'] = parts.pop(0)
-            self.args['qtype'] = parts.pop(0)
+        if self.method == "lookup":
+            self.args["qname"] = parts.pop(0)
+            self.args["qtype"] = parts.pop(0)
+        elif self.method == "list":
+            self.args["id"] = int(parts.pop(0))
+            self.args["zonename"] = parts.pop(0)
+        elif self.method in ("getbeforeandafternamesabsolute", "getbeforeandafternames"):
+            self.args["id"] = int(parts.pop(0))
+            self.args["qname"] = parts.pop(0)
+        elif self.method in ("getdomainmetadata", "setdomainmetadata"):
+            self.args["name"] = parts.pop(0)
+            self.args["kind"] = parts.pop(0)
+        elif self.method == "getdomainkeys":
+            self.args["name"] = parts.pop(0)
+        elif self.method in ("removedomainkey", "activatedomainkey", "deactivatedomainkey"):
+            self.args["id"] = int(parts.pop(0))
+            self.args["name"] = parts.pop(0)
+        elif self.method in (
+            "adddomainkey",
+            "gettsigkey",
+            "getdomaininfo",
+            "settsigkey",
+            "deletetsigkey",
+            "getalldomainmetadata",
+        ):
+            self.args["name"] = parts.pop(0)
+        elif self.method == "setnotified":
+            self.args["id"] = int(parts.pop(0))
+        elif self.method == "feedents":
+            self.args["id"] = int(parts.pop(0))
+            self.args["trxid"] = int(parts.pop(0))
+        elif self.method == "ismaster":
+            self.args["name"] = parts.pop(0)
+            self.args["ip"] = parts.pop(0)
+        elif self.method in ("supermasterbackend", "createslavedomain"):
+            self.args["ip"] = parts.pop(0)
+            self.args["domain"] = parts.pop(0)
+        elif self.method in ("feedents3", "starttransaction"):
+            self.args["id"] = int(parts.pop(0))
+            self.args["domain"] = parts.pop(0)
+            self.args["trxid"] = int(parts.pop(0))
+        elif self.method in ("feedrecord", "committransaction", "aborttransaction"):
+            self.args["trxid"] = int(parts.pop(0))
+        elif self.method == "replacerrset":
+            self.args["id"] = int(parts.pop(0))
+            self.args["qname"] = parts.pop(0)
+            self.args["qtype"] = parts.pop(0)
         assert len(parts) == 0, parts
 
         self.parse_qsl(url.query)
@@ -97,20 +105,20 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
                     k1 = m.group(1)
                     k2 = m.group(2)
                     if k1 not in res:
-                        if k2 == '':
+                        if k2 == "":
                             res[k1] = list()
                         else:
                             res[k1] = {}
-                    if k2 == '':
+                    if k2 == "":
                         res[k1].append(value)
-                    else:                        
+                    else:
                         res[k1][k2] = value
                 else:
                     res[key] = value
         self.args = self.args | res
 
     def do_GET(self):
-        if self.path == '/ping':
+        if self.path == "/ping":
             self.send_response(200)
             self.end_headers()
             self.wfile.write("pong".encode())
@@ -127,7 +135,7 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
         self.do_POST()
 
     def do_POST(self):
-        self.url_to_args()        
+        self.url_to_args()
 
         if not self.method:
             self.send_error(404)
@@ -135,26 +143,26 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
 
         try:
             length = 0
-            if 'content-length' in self.headers:
-                length = int(self.headers.get('content-length'))
+            if "content-length" in self.headers:
+                length = int(self.headers.get("content-length"))
             if length > 0:
                 qs = self.rfile.read(length).decode()
                 self.parse_qsl(qs)
 
             if self.method == "adddomainkey":
-                self.args['key'] = {
-                    'flags': self.args['flags'],
-                    'active': self.args['active'],
-                    'published': self.args['published'],
-                    'content': self.args['content']
+                self.args["key"] = {
+                    "flags": self.args["flags"],
+                    "active": self.args["active"],
+                    "published": self.args["published"],
+                    "content": self.args["content"],
                 }
-                del self.args['flags']
-                del self.args['active']
-                del self.args['published']
-                del self.args['content']
+                del self.args["flags"]
+                del self.args["active"]
+                del self.args["published"]
+                del self.args["content"]
 
-            if 'serial' in self.args:
-                self.args['serial'] = int(self.args['serial'])
+            if "serial" in self.args:
+                self.args["serial"] = int(self.args["serial"])
 
             self.log_error("%r", self.args)
             method = "do_%s" % self.method
@@ -164,15 +172,15 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
 
             if callable(getattr(self.handler, method, None)):
                 getattr(self.handler, method)(**self.args)
-                result = json.dumps({'result':self.handler.result,'log':self.handler.log}).encode()
+                result = json.dumps({"result": self.handler.result, "log": self.handler.log}).encode()
                 self.log_error("%r", self.handler.result)
                 self.send_response(200)
-                self.send_header("content-type", "text/javascript");
+                self.send_header("content-type", "text/javascript")
                 self.send_header("content-length", len(result))
                 self.end_headers()
                 self.wfile.write(result)
             else:
-                self.send_error(404, message=json.dumps({'error': 'No such method'}))
+                self.send_error(404, message=json.dumps({"error": "No such method"}))
         except BrokenPipeError as e2:
             raise e2
         except Exception as e:
@@ -182,10 +190,11 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
 
 
 def main():
-    server = DNSBackendServer(('', 62434), DNSBackendHandler)
+    server = DNSBackendServer(("", 62434), DNSBackendHandler)
     try:
         server.serve_forever()
     except KeyboardInterrupt:
         pass
 
+
 main()
index 7ba2cc492407c6cff4dafd5aba2264f70cb34039..3a8f6efb9f57e9c61056a378734c4b804e80fa11 100755 (executable)
@@ -17,11 +17,11 @@ class DNSBackendServer(http.server.HTTPServer):
 
 class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
     def __init__(self, *args, **kwargs):
-        self.handler = kwargs['handler']
+        self.handler = kwargs["handler"]
         super().__init__(*args)
 
     def do_GET(self):
-        if self.path == '/ping':
+        if self.path == "/ping":
             self.send_response(200)
             self.end_headers()
             self.wfile.write("pong".encode())
@@ -34,25 +34,25 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
             return
 
         try:
-            length = int(self.headers.get('content-length'))
+            length = int(self.headers.get("content-length"))
             message = json.loads(self.rfile.read(length).decode())
 
-            method = "do_" + message['method'].lower()
-            args = message['parameters']
+            method = "do_" + message["method"].lower()
+            args = message["parameters"]
             self.handler.result = False
             self.handler.log = []
 
             if callable(getattr(self.handler, method, None)):
                 getattr(self.handler, method)(**args)
-                result = json.dumps({'result':self.handler.result,'log':self.handler.log}).encode()
+                result = json.dumps({"result": self.handler.result, "log": self.handler.log}).encode()
 
                 self.send_response(200)
-                self.send_header("content-type", "text/javascript");
+                self.send_header("content-type", "text/javascript")
                 self.send_header("content-length", len(result))
                 self.end_headers()
                 self.wfile.write(result)
             else:
-                self.send_error(404, message=json.dumps({'error': 'No such method'}))
+                self.send_error(404, message=json.dumps({"error": "No such method"}))
         except BrokenPipeError as e2:
             raise e2
         except Exception as e:
@@ -60,10 +60,11 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
 
 
 def main():
-    server = DNSBackendServer(('', 62434), DNSBackendHandler)
+    server = DNSBackendServer(("", 62434), DNSBackendHandler)
     try:
         server.serve_forever()
     except KeyboardInterrupt:
         pass
 
+
 main()
index 4fd106dded06c19d5c23176b164398c29c977fc2..2c5b16e83e538976273d5271351d89afa14cd0f0 100755 (executable)
@@ -18,11 +18,11 @@ class DNSBackendServer(http.server.HTTPServer):
 
 class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
     def __init__(self, *args, **kwargs):
-        self.handler = kwargs['handler']
+        self.handler = kwargs["handler"]
         super().__init__(*args)
 
     def do_GET(self):
-        if self.path == '/ping':
+        if self.path == "/ping":
             self.send_response(200)
             self.end_headers()
             self.wfile.write("pong".encode())
@@ -31,13 +31,13 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
 
     def do_POST(self):
         path = urlparse(self.path).path
-        if not path.startswith('/dns/'):
+        if not path.startswith("/dns/"):
             self.send_error(404)
             return
 
         try:
-            length = int(self.headers.get('content-length'))
-            args = json.loads(parse_qs(self.rfile.read(length).decode())['parameters'][0])
+            length = int(self.headers.get("content-length"))
+            args = json.loads(parse_qs(self.rfile.read(length).decode())["parameters"][0])
             method = "do_%s" % path[5:].lower()
             self.log_error("%r", args)
 
@@ -46,15 +46,15 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
 
             if callable(getattr(self.handler, method, None)):
                 getattr(self.handler, method)(**args)
-                result = json.dumps({'result':self.handler.result,'log':self.handler.log}).encode()
+                result = json.dumps({"result": self.handler.result, "log": self.handler.log}).encode()
 
                 self.send_response(200)
-                self.send_header("content-type", "text/javascript");
+                self.send_header("content-type", "text/javascript")
                 self.send_header("content-length", len(result))
                 self.end_headers()
                 self.wfile.write(result)
             else:
-                self.send_error(404, message=json.dumps({'error': 'No such method'}))
+                self.send_error(404, message=json.dumps({"error": "No such method"}))
         except BrokenPipeError as e2:
             raise e2
         except Exception as e:
@@ -62,10 +62,11 @@ class DNSBackendHandler(http.server.BaseHTTPRequestHandler):
 
 
 def main():
-    server = DNSBackendServer(('', 62434), DNSBackendHandler)
+    server = DNSBackendServer(("", 62434), DNSBackendHandler)
     try:
         server.serve_forever()
     except KeyboardInterrupt:
         pass
 
+
 main()
index 4300b1e46a542c4781176f38fde8931f0b7a7497..2e5e12592b15dce10e3a01c1eeae725c6a5e3dc7 100755 (executable)
@@ -5,18 +5,19 @@ import json
 import os
 from pdns_unittest import Handler
 
+
 def run(socket, handler):
     while True:
         message = socket.recv()
         try:
             message = json.loads(message.decode().strip())
-            method = "do_%s" % message['method'].lower()
-            args = message['parameters']
+            method = "do_%s" % message["method"].lower()
+            args = message["parameters"]
             handler.result = False
             handler.log = []
             if callable(getattr(handler, method, None)):
                 getattr(handler, method)(**args)
-                result = json.dumps({'result': handler.result,'log': handler.log})
+                result = json.dumps({"result": handler.result, "log": handler.log})
                 socket.send(result.encode())
         except KeyboardInterrupt as e3:
             return
@@ -24,7 +25,7 @@ def run(socket, handler):
             raise e2
         except Exception as e:
             print(e)
-            socket.send(json.dumps({'result':False}).encode())
+            socket.send(json.dumps({"result": False}).encode())
 
 
 def main():
@@ -40,5 +41,6 @@ def main():
         pass
 
     os.unlink("/tmp/remotebackend.0")
+
+
 main()
index a12b5aad4a23294b62cb9c8bdc6040c8c197fc8e..e80eaec922fbe563498215f70eed0f667cff74a1 100644 (file)
@@ -151,12 +151,8 @@ def get_cpp_parameters(parameters, lua_interface):
 
 
 def get_temporary_file_for_generated_code(dest_dir):
-    generated_fp = tempfile.NamedTemporaryFile(
-        mode="w+t", encoding="utf-8", dir=dest_dir, delete=False
-    )
-    generated_fp.write(
-        "// !! This file has been generated by dnsdist-rules-generator.py, do not edit by hand!!\n"
-    )
+    generated_fp = tempfile.NamedTemporaryFile(mode="w+t", encoding="utf-8", dir=dest_dir, delete=False)
+    generated_fp.write("// !! This file has been generated by dnsdist-rules-generator.py, do not edit by hand!!\n")
     return generated_fp
 
 
@@ -181,9 +177,7 @@ def generate_actions_factory_header(definitions, build_dir, response=False):
         generated_fp.write(output)
 
     output_file_name = (
-        "dnsdist-response-actions-factory-generated.hh"
-        if response
-        else "dnsdist-actions-factory-generated.hh"
+        "dnsdist-response-actions-factory-generated.hh" if response else "dnsdist-actions-factory-generated.hh"
     )
     handle_generated_file(generated_fp.name, output_file_name, build_dir)
 
@@ -237,9 +231,7 @@ def generate_lua_actions_bindings(definitions, build_dir, response=False):
         generated_fp.write(output)
 
     output_file_name = (
-        "dnsdist-lua-response-actions-generated-body.hh"
-        if response
-        else "dnsdist-lua-actions-generated-body.hh"
+        "dnsdist-lua-response-actions-generated-body.hh" if response else "dnsdist-lua-actions-generated-body.hh"
     )
     handle_generated_file(generated_fp.name, output_file_name, build_dir)
 
@@ -296,9 +288,7 @@ def generate_lua_selectors_bindings(definitions, build_dir):
         if "parameters" in selector:
             output += get_cpp_parameters_definition(selector["parameters"], True)
         output += ") {\n"
-        output += (
-            f"  return std::shared_ptr<DNSRule>(dnsdist::selectors::get{name}Selector("
-        )
+        output += f"  return std::shared_ptr<DNSRule>(dnsdist::selectors::get{name}Selector("
         if "parameters" in selector:
             output += get_cpp_parameters(selector["parameters"], True)
         output += "));\n"
@@ -317,23 +307,17 @@ def main():
     source_dir = sys.argv[1]
     build_dir = sys.argv[2]
 
-    definitions = get_definitions_from_file(
-        f"{source_dir}/dnsdist-actions-definitions.yml"
-    )
+    definitions = get_definitions_from_file(f"{source_dir}/dnsdist-actions-definitions.yml")
     generate_actions_factory_header(definitions, build_dir)
     generate_actions_factory(definitions, build_dir)
     generate_lua_actions_bindings(definitions, build_dir)
 
-    definitions = get_definitions_from_file(
-        f"{source_dir}/dnsdist-response-actions-definitions.yml"
-    )
+    definitions = get_definitions_from_file(f"{source_dir}/dnsdist-response-actions-definitions.yml")
     generate_actions_factory_header(definitions, build_dir, response=True)
     generate_actions_factory(definitions, build_dir, response=True)
     generate_lua_actions_bindings(definitions, build_dir, response=True)
 
-    definitions = get_definitions_from_file(
-        f"{source_dir}/dnsdist-selectors-definitions.yml"
-    )
+    definitions = get_definitions_from_file(f"{source_dir}/dnsdist-selectors-definitions.yml")
     generate_selectors_factory_header(definitions, build_dir)
     generate_selectors_factory(definitions, build_dir)
     generate_lua_selectors_bindings(definitions, build_dir)
index b4d58176c73ba469d7309d95f78d701aa5c28d2c..589c22712601a0c59ffad12860d0f296c51706a8 100644 (file)
@@ -184,9 +184,7 @@ def write_rust_default_trait_impl(struct, skip_namespace=False):
     return result
 
 
-def get_rust_serde_annotations(
-    rust_type, default, rename, obj, field, default_functions
-):
+def get_rust_serde_annotations(rust_type, default, rename, obj, field, default_functions):
     rename_value = f'rename = "{rename}", ' if rename else ""
     if default is None:
         if not rename_value:
@@ -199,9 +197,7 @@ def get_rust_serde_annotations(
         return f"""#[serde({rename_value}default = "crate::{type_upper}::<{default}>::value", skip_serializing_if = "crate::if_true")]"""
     if rust_type in ["String", "Vec<String>"]:
         basename = obj + "_" + field
-        default_functions.append(
-            gen_rust_default_functions(rust_type, default, basename)
-        )
+        default_functions.append(gen_rust_default_functions(rust_type, default, basename))
         return f"""#[serde({rename_value}default = "crate::default_value_{basename}", skip_serializing_if = "crate::default_value_equal_{basename}")]"""
     return f"""#[serde({rename_value}default = "crate::{type_upper}::<{default}>::value", skip_serializing_if = "crate::{type_upper}::<{default}>::is_equal")]"""
 
@@ -221,18 +217,12 @@ def get_converted_serde_type(rust_type):
     return f"dnsdistsettings::{rust_type}"
 
 
-def get_rust_struct_fields_from_definition(
-    name, keys, default_functions, indent, special_serde_object=False
-):
+def get_rust_struct_fields_from_definition(name, keys, default_functions, indent, special_serde_object=False):
     if not "parameters" in keys:
         return ""
     output = ""
     for parameter in keys["parameters"]:
-        parameter_name = (
-            get_rust_field_name(parameter["name"])
-            if not "rename" in parameter
-            else parameter["rename"]
-        )
+        parameter_name = get_rust_field_name(parameter["name"]) if not "rename" in parameter else parameter["rename"]
         rust_type = parameter["type"]
         if "rust-type" in parameter:
             rust_type = parameter["rust-type"]
@@ -265,9 +255,7 @@ def get_rust_struct_fields_from_definition(
     return output
 
 
-def get_rust_struct_from_definition(
-    name, keys, default_functions, indent_spaces=4, special_serde_object=False
-):
+def get_rust_struct_from_definition(name, keys, default_functions, indent_spaces=4, special_serde_object=False):
     if not "parameters" in keys:
         return ""
     obj_name = get_rust_object_name(name)
@@ -291,9 +279,7 @@ def get_rust_struct_from_definition(
     output += "    }\n"
     if special_serde_object or not "skip-serde" in keys or not keys["skip-serde"]:
         default_functions.append(
-            write_rust_default_trait_impl(
-                f"{obj_name}Configuration{name_suffix}", special_serde_object
-            )
+            write_rust_default_trait_impl(f"{obj_name}Configuration{name_suffix}", special_serde_object)
         )
     return output
 
@@ -321,9 +307,7 @@ def get_validation_for_field(field_name, rust_type):
 """
 
 
-def get_struct_validation_function_from_definition(
-    name, parameters, special_serde_object=False
-):
+def get_struct_validation_function_from_definition(name, parameters, special_serde_object=False):
     if len(parameters) == 0:
         return ""
     namespace = "dnsdistsettings::" if not special_serde_object else ""
@@ -333,11 +317,7 @@ def get_struct_validation_function_from_definition(
     fn validate(&self) -> Result<(), ValidationError> {{
 """
     for parameter in parameters:
-        field_name = (
-            get_rust_field_name(parameter["name"])
-            if parameter["name"] != "namespace"
-            else "name_space"
-        )
+        field_name = get_rust_field_name(parameter["name"]) if parameter["name"] != "namespace" else "name_space"
         rust_type = parameter["type"]
         output += get_validation_for_field(field_name, rust_type)
     output += """        Ok(())
@@ -363,9 +343,7 @@ def include_file(out_fp, include_file_name):
 def generate_flat_settings_for_cxx(definitions, src_dir, out_file_path):
     cxx_flat_settings_fp = get_temporary_file_for_generated_code(out_file_path)
 
-    include_file(
-        cxx_flat_settings_fp, src_dir + "/dnsdist-configuration-yaml-items-pre-in.cc"
-    )
+    include_file(cxx_flat_settings_fp, src_dir + "/dnsdist-configuration-yaml-items-pre-in.cc")
 
     # first we do runtime-settable settings
     cxx_flat_settings_fp.write("""#if defined(HAVE_YAML_CONFIGURATION)
@@ -395,18 +373,10 @@ void convertRuntimeFlatSettingsFromRust(const dnsdist::rust::settings::GlobalCon
                 continue
             internal_field_name = parameter["internal-field-name"]
             rust_field_name = (
-                get_rust_field_name(parameter["name"])
-                if not "rename" in parameter
-                else parameter["rename"]
-            )
-            default = (
-                parameter["default"]
-                if parameter["type"] != "String"
-                else '"' + parameter["default"] + '"'
-            )
-            cxx_flat_settings_fp.write(
-                f"  if (config.{internal_field_name} == {default}) {{\n"
+                get_rust_field_name(parameter["name"]) if not "rename" in parameter else parameter["rename"]
             )
+            default = parameter["default"] if parameter["type"] != "String" else '"' + parameter["default"] + '"'
+            cxx_flat_settings_fp.write(f"  if (config.{internal_field_name} == {default}) {{\n")
             if parameter["type"] != "String":
                 cxx_flat_settings_fp.write(
                     f"    config.{internal_field_name} = yamlConfig.{category_name}.{rust_field_name};\n"
@@ -440,18 +410,10 @@ void convertRuntimeFlatSettingsFromRust(const dnsdist::rust::settings::GlobalCon
                 continue
             internal_field_name = parameter["internal-field-name"]
             rust_field_name = (
-                get_rust_field_name(parameter["name"])
-                if not "rename" in parameter
-                else parameter["rename"]
-            )
-            default = (
-                parameter["default"]
-                if parameter["type"] != "String"
-                else '"' + parameter["default"] + '"'
-            )
-            cxx_flat_settings_fp.write(
-                f"  if (config.{internal_field_name} == {default}) {{\n"
+                get_rust_field_name(parameter["name"]) if not "rename" in parameter else parameter["rename"]
             )
+            default = parameter["default"] if parameter["type"] != "String" else '"' + parameter["default"] + '"'
+            cxx_flat_settings_fp.write(f"  if (config.{internal_field_name} == {default}) {{\n")
             if parameter["type"] != "String":
                 cxx_flat_settings_fp.write(
                     f"    config.{internal_field_name} = yamlConfig.{category_name}.{rust_field_name};\n"
@@ -494,9 +456,7 @@ def generate_actions_config(output, def_dir, response, default_functions):
             action_buffer += f'{indent}#[serde(default, skip_serializing_if = "crate::is_default")]\n'
         action_buffer += f"{indent}name: String,\n"
 
-        action_buffer += get_rust_struct_fields_from_definition(
-            struct_name, action, default_functions, indent
-        )
+        action_buffer += get_rust_struct_fields_from_definition(struct_name, action, default_functions, indent)
 
         action_buffer += "    }\n\n"
 
@@ -524,9 +484,7 @@ def generate_selectors_config(output, def_dir, default_functions):
             selector_buffer += f'{indent}#[serde(default, skip_serializing_if = "crate::is_default")]\n'
         selector_buffer += f"{indent}name: String,\n"
 
-        selector_buffer += get_rust_struct_fields_from_definition(
-            struct_name, selector, default_functions, indent
-        )
+        selector_buffer += get_rust_struct_fields_from_definition(struct_name, selector, default_functions, indent)
 
         selector_buffer += "    }\n\n"
 
@@ -625,11 +583,7 @@ def generate_cpp_action_wrappers(def_dir, cxx_dest_dir):
             continue
         name = get_rust_object_name(action["name"])
         struct_name = f"{name}{suffix}Configuration"
-        parameters = (
-            get_cpp_parameters("config", action["parameters"], True)
-            if "parameters" in action
-            else ""
-        )
+        parameters = get_cpp_parameters("config", action["parameters"], True) if "parameters" in action else ""
         wrappers_buffer += f"""std::shared_ptr<DNS{suffix}Wrapper> get{name}{suffix}(const {struct_name}& config)
 {{
   auto action = dnsdist::actions::get{name}{suffix}({parameters});
@@ -645,11 +599,7 @@ def generate_cpp_action_wrappers(def_dir, cxx_dest_dir):
             continue
         name = get_rust_object_name(action["name"])
         struct_name = f"{name}{suffix}Configuration"
-        parameters = (
-            get_cpp_parameters("config", action["parameters"], True)
-            if "parameters" in action
-            else ""
-        )
+        parameters = get_cpp_parameters("config", action["parameters"], True) if "parameters" in action else ""
         wrappers_buffer += f"""std::shared_ptr<DNS{suffix}Wrapper> get{name}{suffix}(const {struct_name}& config)
 {{
   auto action = dnsdist::actions::get{name}{suffix}({parameters});
@@ -675,11 +625,7 @@ def generate_cpp_selector_wrappers(def_dir, cxx_dest_dir):
             continue
         name = get_rust_object_name(selector["name"])
         struct_name = f"{name}{suffix}Configuration"
-        parameters = (
-            get_cpp_parameters("config", selector["parameters"], True)
-            if "parameters" in selector
-            else ""
-        )
+        parameters = get_cpp_parameters("config", selector["parameters"], True) if "parameters" in selector else ""
         wrappers_buffer += f"""std::shared_ptr<DNS{suffix}> get{name}{suffix}(const {struct_name}& config)
 {{
   auto selector = dnsdist::selectors::get{name}{suffix}({parameters});
@@ -788,7 +734,9 @@ def generate_cpp_action_selector_functions_callable_from_rust(output, def_dir):
     suffix = "Selector"
     for selector in selectors_definitions:
         name = get_rust_object_name(selector["name"])
-        output_buffer += f"        fn get{name}{suffix}(config: &{name}{suffix}Configuration) -> Result<SharedPtr<DNS{suffix}>>;\n"
+        output_buffer += (
+            f"        fn get{name}{suffix}(config: &{name}{suffix}Configuration) -> Result<SharedPtr<DNS{suffix}>>;\n"
+        )
 
     output_buffer += "    }\n"
     output.write(output_buffer)
@@ -797,11 +745,7 @@ def generate_cpp_action_selector_functions_callable_from_rust(output, def_dir):
 def generate_rust_action_to_config(output, def_dir, response):
     suffix = "ResponseAction" if response else "Action"
     actions_definitions = get_actions_definitions(def_dir, response)
-    function_name = (
-        "get_one_action_from_serde"
-        if not response
-        else "get_one_response_action_from_serde"
-    )
+    function_name = "get_one_action_from_serde" if not response else "get_one_response_action_from_serde"
     enum_buffer = f"""fn {function_name}(action: &{suffix}) -> Result<dnsdistsettings::SharedDNS{suffix}, cxx::Exception> {{
     match action {{
         {suffix}::Default => {{}}
@@ -893,14 +837,9 @@ def generate_rust_selector_to_config(output, def_dir):
     output.write(enum_buffer)
 
 
-def handle_structures(
-    generated_fp, definitions, default_functions, validation_functions
-):
+def handle_structures(generated_fp, definitions, default_functions, validation_functions):
     for definition_name, keys in definitions.items():
-        generated_fp.write(
-            get_rust_struct_from_definition(definition_name, keys, default_functions)
-            + "\n"
-        )
+        generated_fp.write(get_rust_struct_from_definition(definition_name, keys, default_functions) + "\n")
         if definition_name not in [
             "global",
             "proto_buf_meta",
@@ -916,28 +855,20 @@ def handle_structures(
 
 
 def get_temporary_file_for_generated_code(directory):
-    generated_fp = tempfile.NamedTemporaryFile(
-        mode="w+t", encoding="utf-8", dir=directory, delete=False
-    )
-    generated_fp.write(
-        "// !! This file has been generated by dnsdist-settings-generator.py, do not edit by hand!!\n"
-    )
+    generated_fp = tempfile.NamedTemporaryFile(mode="w+t", encoding="utf-8", dir=directory, delete=False)
+    generated_fp.write("// !! This file has been generated by dnsdist-settings-generator.py, do not edit by hand!!\n")
     return generated_fp
 
 
 def main():
     if len(sys.argv) != 4:
-        print(
-            f"Usage: {sys.argv[0]} <path/to/definitions/files> <rust/output/dir> <cxx/build/root/dir>"
-        )
+        print(f"Usage: {sys.argv[0]} <path/to/definitions/files> <rust/output/dir> <cxx/build/root/dir>")
         sys.exit(1)
 
     definitions_dir = sys.argv[1]
     rust_dir = sys.argv[2]
     cxx_build_dir = sys.argv[3]
-    definitions = get_definitions_from_file(
-        definitions_dir + "/dnsdist-settings-definitions.yml"
-    )
+    definitions = get_definitions_from_file(definitions_dir + "/dnsdist-settings-definitions.yml")
     default_functions = []
     validation_functions = []
 
@@ -953,13 +884,9 @@ def main():
     generate_actions_config(generated_fp, definitions_dir, True, default_functions)
     generate_selectors_config(generated_fp, definitions_dir, default_functions)
 
-    handle_structures(
-        generated_fp, definitions, default_functions, validation_functions
-    )
+    handle_structures(generated_fp, definitions, default_functions, validation_functions)
 
-    generate_cpp_action_selector_functions_callable_from_rust(
-        generated_fp, definitions_dir
-    )
+    generate_cpp_action_selector_functions_callable_from_rust(generated_fp, definitions_dir)
 
     include_file(generated_fp, f"{rust_dir}/rust-middle-in.rs")
     # we are now outside of the dnsdistsettings namespace
@@ -968,9 +895,7 @@ def main():
     for definition_name, keys in definitions.items():
         if definition_name == "global":
             generated_fp.write(
-                get_rust_struct_from_definition(
-                    definition_name, keys, default_functions, special_serde_object=True
-                )
+                get_rust_struct_from_definition(definition_name, keys, default_functions, special_serde_object=True)
                 + "\n"
             )
             validation_functions.append(
index 22d33199df34ea6ce0715b8f7679818eb3fa7700..7e8bcb484c99748aac6c7e5ecfc978e2e95f473b 100644 (file)
@@ -61,9 +61,7 @@ def get_objects(def_file):
 
 def rust_type_to_human_str(rust_type, entry_type, generate_ref=True):
     if is_vector_of(rust_type):
-        return "Sequence of " + rust_type_to_human_str(
-            get_vector_sub_type(rust_type), entry_type, generate_ref
-        )
+        return "Sequence of " + rust_type_to_human_str(get_vector_sub_type(rust_type), entry_type, generate_ref)
     if rust_type in ["u8", "u16", "u32", "u64"]:
         return "Unsigned integer"
     if rust_type == "f64":
@@ -111,9 +109,7 @@ def print_structure(parameters, entry_type):
     return output
 
 
-def process_object(
-    object_name, entries, entry_type, is_setting_struct=False, lua_equivalent=None
-):
+def process_object(object_name, entries, entry_type, is_setting_struct=False, lua_equivalent=None):
     output = f".. _yaml-{entry_type}-{object_name}:\n\n"
 
     output += f"{object_name}\n"
@@ -153,12 +149,8 @@ def process_object(
 
 
 def get_temporary_file_for_generated_content(directory):
-    generated_fp = tempfile.NamedTemporaryFile(
-        mode="w+t", encoding="utf-8", dir=directory, delete=False
-    )
-    generated_fp.write(
-        ".. THIS IS A GENERATED FILE. DO NOT EDIT. See dnsdist-settings-documentation-generator.py\n\n"
-    )
+    generated_fp = tempfile.NamedTemporaryFile(mode="w+t", encoding="utf-8", dir=directory, delete=False)
+    generated_fp.write(".. THIS IS A GENERATED FILE. DO NOT EDIT. See dnsdist-settings-documentation-generator.py\n\n")
     return generated_fp
 
 
@@ -224,9 +216,7 @@ def process_selectors_or_actions(def_file, entry_type):
         lua_equivalent = object_name + ("Rule" if entry_type == "selector" else suffix)
         if "no-lua-equivalent" in entry:
             lua_equivalent = None
-        output += process_object(
-            object_name + suffix, entry, "settings", lua_equivalent=lua_equivalent
-        )
+        output += process_object(object_name + suffix, entry, "settings", lua_equivalent=lua_equivalent)
 
     return output
 
@@ -239,9 +229,7 @@ def main():
     source_dir = sys.argv[1]
     docs_folder = f"{source_dir}/docs/"
     if not os.path.isdir(docs_folder):
-        print(
-            "Skipping settings documentation generation because the docs/ folder does not exist"
-        )
+        print("Skipping settings documentation generation because the docs/ folder does not exist")
         return
 
     generated_fp = get_temporary_file_for_generated_content(docs_folder)
@@ -250,23 +238,17 @@ def main():
     os.rename(generated_fp.name, f"{docs_folder}/reference/yaml-settings.rst")
 
     generated_fp = get_temporary_file_for_generated_content(docs_folder)
-    output = process_selectors_or_actions(
-        f"{source_dir}/dnsdist-actions-definitions.yml", "action"
-    )
+    output = process_selectors_or_actions(f"{source_dir}/dnsdist-actions-definitions.yml", "action")
     generated_fp.write(output)
     os.rename(generated_fp.name, f"{docs_folder}/reference/yaml-actions.rst")
 
     generated_fp = get_temporary_file_for_generated_content(docs_folder)
-    output = process_selectors_or_actions(
-        f"{source_dir}/dnsdist-response-actions-definitions.yml", "response-action"
-    )
+    output = process_selectors_or_actions(f"{source_dir}/dnsdist-response-actions-definitions.yml", "response-action")
     generated_fp.write(output)
     os.rename(generated_fp.name, f"{docs_folder}/reference/yaml-response-actions.rst")
 
     generated_fp = get_temporary_file_for_generated_content(docs_folder)
-    output = process_selectors_or_actions(
-        f"{source_dir}/dnsdist-selectors-definitions.yml", "selector"
-    )
+    output = process_selectors_or_actions(f"{source_dir}/dnsdist-selectors-definitions.yml", "selector")
     generated_fp.write(output)
     os.rename(generated_fp.name, f"{docs_folder}/reference/yaml-selectors.rst")
 
index 0066bbf5b8f7502c2d80679b76814510dc873f34..85a05d01187f2641c4948f108e92712c0bac5918 100644 (file)
@@ -145,9 +145,7 @@ html_static_path = ["_static"]
 
 html_favicon = "_static/favicon.ico"
 
-html_sidebars = {
-    "**": ["searchbox.html", "relations.html", "localtoc.html", "sourcelink.html"]
-}
+html_sidebars = {"**": ["searchbox.html", "relations.html", "localtoc.html", "sourcelink.html"]}
 
 # -- Options for HTMLHelp output ------------------------------------------
 
index 139d06cbfea3f9fa27aa2b9b1882375c86828e4b..f2542412ddd7ce215c47ae465e4baee5abcbbcd0 100755 (executable)
@@ -9,79 +9,108 @@ from pdnsapi.api import PDNSApi
 from datetime import datetime, timedelta
 import random
 
-logger = logging.getLogger('pdns-keyroller')
+logger = logging.getLogger("pdns-keyroller")
+
 
 def display_keyrollerdomain_infos(zone, api):
     zoneconf = keyrollerdomain.KeyrollerDomain(zone, api)
-    if zoneconf.state :
+    if zoneconf.state:
         if zoneconf.state.is_rolling:
             timeleft = zoneconf.state.current_roll.current_step_datetime - datetime.now()
             logger.info(
-                '{} is rolling its {} using the {} method. It is in the step {}, which was made {}. Next step scheduled {}'.format(
-                    zone, zoneconf.state.current_roll.keytype.upper(),
-                    zoneconf.state.current_roll.rolltype, zoneconf.state.current_roll.current_step_name,
+                "{} is rolling its {} using the {} method. It is in the step {}, which was made {}. Next step scheduled {}".format(
+                    zone,
+                    zoneconf.state.current_roll.keytype.upper(),
+                    zoneconf.state.current_roll.rolltype,
+                    zoneconf.state.current_roll.current_step_name,
                     zoneconf.state.current_roll.step_datetimes[-1],
-                    "in {}".format(timeleft) if timeleft > timedelta(0) else "ASAP"
+                    "in {}".format(timeleft) if timeleft > timedelta(0) else "ASAP",
                 )
             )
         else:
-            logger.info('{} is not rolling. Last KSK roll was {} and the last ZSK roll was {}'.format(
-                zone, zoneconf.state.last_ksk_roll_str, zoneconf.state.last_zsk_roll_str))
-    else :
-        logger.info('{} is not rolling'.format(zone))
+            logger.info(
+                "{} is not rolling. Last KSK roll was {} and the last ZSK roll was {}".format(
+                    zone, zoneconf.state.last_ksk_roll_str, zoneconf.state.last_zsk_roll_str
+                )
+            )
+    else:
+        logger.info("{} is not rolling".format(zone))
+
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     argp = argparse.ArgumentParser(
-        prog='pdns-keyroller-ctl', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
-        description='PowerDNS DNSSEC key-roller')
-    argp.add_argument('--config', '-c', metavar='PATH', type=str, default='/etc/powerdns/pdns-keyroller.conf',
-                      help='Load this configuration file')
-    argp.add_argument('--baseurl', '-b', required=False, metavar='BASEURL', help='The base-URL for the authoritative webserver'
-                      'Overrides the one set in the config-file')
-    argp.add_argument('--apikey', '-k', required=False, metavar='API-KEY', help='The key needed to access the API')
-    argp.add_argument('--verbose', '-v', action='count', help='Be more verbose')
-    argp.set_defaults(command='none')
+        prog="pdns-keyroller-ctl",
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+        description="PowerDNS DNSSEC key-roller",
+    )
+    argp.add_argument(
+        "--config",
+        "-c",
+        metavar="PATH",
+        type=str,
+        default="/etc/powerdns/pdns-keyroller.conf",
+        help="Load this configuration file",
+    )
+    argp.add_argument(
+        "--baseurl",
+        "-b",
+        required=False,
+        metavar="BASEURL",
+        help="The base-URL for the authoritative webserverOverrides the one set in the config-file",
+    )
+    argp.add_argument("--apikey", "-k", required=False, metavar="API-KEY", help="The key needed to access the API")
+    argp.add_argument("--verbose", "-v", action="count", help="Be more verbose")
+    argp.set_defaults(command="none")
 
     sub_parsers = argp.add_subparsers()
 
-    configs_parser = sub_parsers.add_parser('configs', help='Lists configured domains')
-    configs_parser.set_defaults(command='configs', action='list')
+    configs_parser = sub_parsers.add_parser("configs", help="Lists configured domains")
+    configs_parser.set_defaults(command="configs", action="list")
 
     configs_subparsers = configs_parser.add_subparsers()
 
-    configs_show_parser = configs_subparsers.add_parser('show', help='Show the roll configuration of the current domain')
-    configs_show_parser.set_defaults(action='show')
-    configs_show_parser.add_argument('domain', metavar='DOMAIN')
-
-    configs_roll_parser = configs_subparsers.add_parser('roll', help='Setup the domain for autoroll')
-    configs_roll_parser.set_defaults(action='roll')
-    configs_roll_parser.add_argument('domain', metavar='DOMAIN')
-
-    configs_roll_parser.add_argument('--force', '-f', required=False, default=False, action="store_true", help='Force creation even if a configuration already exists')
-    configs_roll_parser.add_argument('--ksk-frequency', required=False)
-    configs_roll_parser.add_argument('--ksk-algo', required=False)
-    configs_roll_parser.add_argument('--zsk-algo', required=False)
-    configs_roll_parser.add_argument('--zsk-frequency', required=False)
-
-    configs_list_parser = configs_subparsers.add_parser('list', help='List all configured domains')
-    configs_list_parser.set_defaults(action='list')
-
-
+    configs_show_parser = configs_subparsers.add_parser(
+        "show", help="Show the roll configuration of the current domain"
+    )
+    configs_show_parser.set_defaults(action="show")
+    configs_show_parser.add_argument("domain", metavar="DOMAIN")
+
+    configs_roll_parser = configs_subparsers.add_parser("roll", help="Setup the domain for autoroll")
+    configs_roll_parser.set_defaults(action="roll")
+    configs_roll_parser.add_argument("domain", metavar="DOMAIN")
+
+    configs_roll_parser.add_argument(
+        "--force",
+        "-f",
+        required=False,
+        default=False,
+        action="store_true",
+        help="Force creation even if a configuration already exists",
+    )
+    configs_roll_parser.add_argument("--ksk-frequency", required=False)
+    configs_roll_parser.add_argument("--ksk-algo", required=False)
+    configs_roll_parser.add_argument("--zsk-algo", required=False)
+    configs_roll_parser.add_argument("--zsk-frequency", required=False)
+
+    configs_list_parser = configs_subparsers.add_parser("list", help="List all configured domains")
+    configs_list_parser.set_defaults(action="list")
 
     # roll
-    roll_parser = sub_parsers.add_parser('roll', help='Manipulate current rolls')
-    roll_parser.set_defaults(command='roll', action='waiting')
+    roll_parser = sub_parsers.add_parser("roll", help="Manipulate current rolls")
+    roll_parser.set_defaults(command="roll", action="waiting")
 
     roll_subparsers = roll_parser.add_subparsers()
 
-    roll_waiting_parser = roll_subparsers.add_parser('waiting', help='List waiting zones (KSK rolls waiting for DS change)')
-    roll_waiting_parser.set_defaults(action='waiting')
+    roll_waiting_parser = roll_subparsers.add_parser(
+        "waiting", help="List waiting zones (KSK rolls waiting for DS change)"
+    )
+    roll_waiting_parser.set_defaults(action="waiting")
 
-    roll_step_parser = roll_subparsers.add_parser('step', help='Step waiting roll')
-    roll_step_parser.set_defaults(action='step')
+    roll_step_parser = roll_subparsers.add_parser("step", help="Step waiting roll")
+    roll_step_parser.set_defaults(action="step")
 
-    roll_step_parser.add_argument('domain', metavar='DOMAIN')
-    roll_step_parser.add_argument('ttl', metavar='TTL')
+    roll_step_parser.add_argument("domain", metavar="DOMAIN")
+    roll_step_parser.add_argument("ttl", metavar="TTL")
 
     arguments = argp.parse_args()
 
@@ -95,20 +124,20 @@ if __name__ == '__main__':
     api_config = config.api()
     try:
         if arguments.baseurl:
-            api_config['baseurl'] = arguments.baseurl
+            api_config["baseurl"] = arguments.baseurl
         if arguments.apikey:
-            api_config['apikey'] = arguments.apikey
+            api_config["apikey"] = arguments.apikey
         api = PDNSApi(**api_config)
     except ConnectionError as e:
         logger.error("Unable to connect to PowerDNS: {}".format(e))
         sys.exit(1)
 
-    if arguments.command == 'none':
+    if arguments.command == "none":
         argp.print_help()
         sys.exit(1)
 
-    if arguments.command == 'configs':
-        if arguments.action == 'list':
+    if arguments.command == "configs":
+        if arguments.action == "list":
             for zone in api.get_zones():
                 try:
                     display_keyrollerdomain_infos(zone.id, api)
@@ -117,11 +146,11 @@ if __name__ == '__main__':
                     continue
                 except Exception as e:
                     logger.error("Unable to get config for domain {}: {}".format(zone.id, e))
-        if arguments.action == 'show':
+        if arguments.action == "show":
             try:
                 domaincfg = domainconfig.from_api(arguments.domain, api)
                 logger.info(
-                    '{} has the following roll configuration: KSK {}, ZSK {}'.format(
+                    "{} has the following roll configuration: KSK {}, ZSK {}".format(
                         arguments.domain,
                         domaincfg.ksk_frequency,
                         domaincfg.zsk_frequency,
@@ -131,35 +160,22 @@ if __name__ == '__main__':
             except FileNotFoundError:
                 logger.error("{} is not under automatic keyroll".format(arguments.domain))
             except ConnectionError:
-                logger.error(
-                    'No such domain {}'.format(
-                        arguments.domain
-                    )
-                )
+                logger.error("No such domain {}".format(arguments.domain))
             except Exception as e:
                 logger.error("Unable to get config for domain {}: {}".format(zone.id, e))
 
-
-        if arguments.action == 'roll':
+        if arguments.action == "roll":
             docreate = False
             try:
                 domaincfg = domainconfig.from_api(arguments.domain, api)
                 if not arguments.force:
-                    logger.error(
-                        '{} already has an autoroll setup'.format(
-                            arguments.domain
-                        )
-                    )
+                    logger.error("{} already has an autoroll setup".format(arguments.domain))
                 else:
                     docreate = True
             except FileNotFoundError:
                 docreate = True
             except ConnectionError:
-                logger.error(
-                    'No such domain {}'.format(
-                        arguments.domain
-                    )
-                )
+                logger.error("No such domain {}".format(arguments.domain))
 
             if docreate:
                 domaincfg = domainconfig.DomainConfig(**config.defaults())
@@ -174,42 +190,34 @@ if __name__ == '__main__':
                         domaincfg.zsk_algo = arguments.zsk_algo
                     domainconfig.to_api(arguments.domain, api, domaincfg)
                     logger.info(
-                        'Successfully created configuration for {}: KSK {}, ZSK {}'.format(
+                        "Successfully created configuration for {}: KSK {}, ZSK {}".format(
                             arguments.domain,
                             domaincfg.ksk_frequency,
                             domaincfg.zsk_frequency,
                         )
                     )
                 except SyntaxError as e:
-                    logger.error(
-                        'Unable to setup given frequency {}: {}'.format(
-                            arguments.domain, e
-                        )
-                    )
-    if arguments.command == 'roll':
-        if arguments.action == 'waiting':
+                    logger.error("Unable to setup given frequency {}: {}".format(arguments.domain, e))
+    if arguments.command == "roll":
+        if arguments.action == "waiting":
             for zone in api.get_zones():
                 try:
                     zoneconf = keyrollerdomain.KeyrollerDomain(zone.id, api)
                     if zoneconf.state and zoneconf.state.is_rolling and zoneconf.state.current_roll.is_waiting_ds():
-                        logger.info('{} is waiting for DS replacement'.format(zone.id))
+                        logger.info("{} is waiting for DS replacement".format(zone.id))
                 except FileNotFoundError:
                     continue
-        elif arguments.action == 'step':
+        elif arguments.action == "step":
             try:
                 zoneconf = keyrollerdomain.KeyrollerDomain(arguments.domain, api)
                 if zoneconf.state and zoneconf.state.current_roll.is_waiting_ds():
                     zoneconf.step(force=True, customttl=int(arguments.ttl))
                     logger.info(
-                        'Successfully stepped {}, now waiting {} before deleting the keys'.format(
+                        "Successfully stepped {}, now waiting {} before deleting the keys".format(
                             arguments.domain,
                             arguments.ttl,
                         )
                     )
 
             except FileNotFoundError:
-                logger.error(
-                    'No such zone to step {}'.format(
-                        arguments.domain
-                    )
-                )
+                logger.error("No such zone to step {}".format(arguments.domain))
index 8554433774f1ff1f15c5bce6b742a0d99140638a..8bce25c811e3450f7edc779c9a2f055950c90db7 100755 (executable)
@@ -5,15 +5,23 @@ import pdnskeyroller.daemon
 import sys
 import traceback
 
-logger = logging.getLogger('pdns-keyroller')
+logger = logging.getLogger("pdns-keyroller")
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     argp = argparse.ArgumentParser(
-        prog='pdns-keyroller', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
-        description='PowerDNS DNSSEC key-roller daemon')
-    argp.add_argument('--verbose', '-v', action='count', help='Be more verbose')
-    argp.add_argument('--config', '-c', metavar='PATH', type=str, default='/etc/powerdns/pdns-keyroller.conf',
-                      help='Load this configuration file')
+        prog="pdns-keyroller",
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+        description="PowerDNS DNSSEC key-roller daemon",
+    )
+    argp.add_argument("--verbose", "-v", action="count", help="Be more verbose")
+    argp.add_argument(
+        "--config",
+        "-c",
+        metavar="PATH",
+        type=str,
+        default="/etc/powerdns/pdns-keyroller.conf",
+        help="Load this configuration file",
+    )
 
     arguments = argp.parse_args()
 
@@ -27,7 +35,7 @@ if __name__ == '__main__':
     try:
         d = pdnskeyroller.daemon.Daemon(arguments.config)
     except ConnectionError as e:
-        logger.fatal('Unable to start: {}'.format(e))
+        logger.fatal("Unable to start: {}".format(e))
         sys.exit(1)
 
     try:
index 57401eebc338e2539372bed70beab8abe0e60459..d28489a39357a34cfb3c2164c9e20e1588340533 100644 (file)
@@ -20,11 +20,11 @@ def _sanitize_dnsname(name):
     :return: A DNS Name that has a trailing dot
     :rtype: str
     """
-    if name == '.' or name == '=2E':
+    if name == "." or name == "=2E":
         # lol
-        return '=2E'
-    if name[-1] != '.':
-        return name + '.'
+        return "=2E"
+    if name[-1] != ".":
+        return name + "."
     return name
 
 
@@ -35,7 +35,7 @@ class PDNSApi:
     TODO: We should probably try to do some caching
     """
 
-    def __init__(self, apikey, version=1, baseurl='http://localhost:8081', server='localhost', timeout=2):
+    def __init__(self, apikey, version=1, baseurl="http://localhost:8081", server="localhost", timeout=2):
         """
         :param apikey: The API Key needed to access the API (`api-key` setting)
         :param version: The version of the API used, only 1 is supported at the moment
@@ -46,14 +46,14 @@ class PDNSApi:
         :raises: ConnectionError when the API is not reachable
         """
         api_suffix = {
-            0: '',
-            1: '/api/v1',
+            0: "",
+            1: "/api/v1",
         }[int(version)]
-        url = baseurl + '{}/servers/{}'.format(api_suffix, server)
+        url = baseurl + "{}/servers/{}".format(api_suffix, server)
         # Strip double (or more) slashes
-        self.url = urllib.parse.urljoin(url, re.sub(r'/{2,}', '/', urllib.parse.urlparse(url).path))
+        self.url = urllib.parse.urljoin(url, re.sub(r"/{2,}", "/", urllib.parse.urlparse(url).path))
         if apikey is None:
-            raise Exception('apikey may not be None!')
+            raise Exception("apikey may not be None!")
         self.apikey = apikey
         self.timeout = timeout
 
@@ -63,16 +63,11 @@ class PDNSApi:
         self._server = server
 
         # Test the API, raises in _do_request
-        self._do_request('', 'GET')
+        self._do_request("", "GET")
 
     def __repr__(self):
         return '{}.PDNSApi(apikey="{}", version={}, baseurl="{}", server="{}", timeout={})'.format(
-            __name__,
-            self.apikey,
-            self._version,
-            self._baseurl,
-            self._server,
-            self.timeout
+            __name__, self.apikey, self._version, self._baseurl, self._server, self.timeout
         )
 
     def _do_request(self, uri, method, data=None):
@@ -86,19 +81,19 @@ class PDNSApi:
         :rtype: tuple(int, str)
         """
         headers = {
-            'Accept': 'application/json',
-            'X-API-Key': self.apikey,
+            "Accept": "application/json",
+            "X-API-Key": self.apikey,
         }
 
         full_url = self.url + uri
 
         if data is not None:
             if not (isinstance(data, dict) or isinstance(data, list)):
-                raise ValueError('data was passed as a {}, needs to be dict or list!'.format(type(data)))
-            if method.upper() != 'GET':
-                headers.update({'Content-Type': 'application/json'})
+                raise ValueError("data was passed as a {}, needs to be dict or list!".format(type(data)))
+            if method.upper() != "GET":
+                headers.update({"Content-Type": "application/json"})
 
-        logger.debug('Attempting {} request to {} with data: {}'.format(method, full_url, data))
+        logger.debug("Attempting {} request to {} with data: {}".format(method, full_url, data))
 
         ret = None
         try:
@@ -116,8 +111,11 @@ class PDNSApi:
             raise ConnectionError("Unable to connect to {}: {}".format(full_url, e))
         except requests.HTTPError as e:
             logger.debug("Got an HTTP {} Error: {}".format(e.response.status_code, ret))
-            raise ConnectionError("HTTP error code {} received for {}: {}".format(
-                e.response.status_code, e.request.url, ret.get('error', ret)))
+            raise ConnectionError(
+                "HTTP error code {} received for {}: {}".format(
+                    e.response.status_code, e.request.url, ret.get("error", ret)
+                )
+            )
         except Exception as e:
             msg = "Error doing {} request to {}: {}".format(method, full_url, e)
             logger.debug(msg)
@@ -131,17 +129,16 @@ class PDNSApi:
         :return: All the cryptokeys for the zone
         :rtype: list(CryptoKey)
         """
-        code, resp = self._do_request('/zones/{}/cryptokeys'.format(_sanitize_dnsname(zone)),
-                                      'GET')
+        code, resp = self._do_request("/zones/{}/cryptokeys".format(_sanitize_dnsname(zone)), "GET")
 
         if code == 200:
             cryptokeys = []
             for k in resp:
-                k.pop('type')
+                k.pop("type")
                 cryptokeys.append(CryptoKey(**k))
             return cryptokeys
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
     def get_cryptokey(self, zone, cryptokey):
         """
@@ -160,14 +157,13 @@ class PDNSApi:
         if keyid == -1:
             raise Exception("cryptokey is not a CryptoKey, nor a str or int")
 
-        code, resp = self._do_request('/zones/{}/cryptokeys/{}'.format(_sanitize_dnsname(zone), keyid),
-                                      'GET')
+        code, resp = self._do_request("/zones/{}/cryptokeys/{}".format(_sanitize_dnsname(zone), keyid), "GET")
 
         if code == 200:
-            resp.pop('type')
+            resp.pop("type")
             return CryptoKey(**resp)
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
     def set_cryptokey_active(self, zone, cryptokey, active=True):
         """
@@ -188,16 +184,19 @@ class PDNSApi:
         if keyid == -1:
             raise Exception("cryptokey is not a CryptoKey, nor a str or int")
 
-        code, resp = self._do_request('/zones/{}/cryptokeys/{}'.format(_sanitize_dnsname(zone), keyid),
-                                      'PUT',
-                                      {'active': active})
+        code, resp = self._do_request(
+            "/zones/{}/cryptokeys/{}".format(_sanitize_dnsname(zone), keyid), "PUT", {"active": active}
+        )
         if code == 422:
-            raise Exception('Failed to set cryptokey {} in zone {} to {}: {}'.format(
-                keyid, zone, 'active' if active else 'inactive', resp))
+            raise Exception(
+                "Failed to set cryptokey {} in zone {} to {}: {}".format(
+                    keyid, zone, "active" if active else "inactive", resp
+                )
+            )
         if code == 204:
             return self.get_cryptokey(zone, cryptokey)
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
     def set_cryptokey_published(self, zone, cryptokey, published=True):
         """
@@ -217,25 +216,29 @@ class PDNSApi:
         if keyid == -1:
             raise Exception("cryptokey is not a CryptoKey, nor a str or int")
 
-        code, resp = self._do_request('/zones/{}/cryptokeys/{}'.format(_sanitize_dnsname(zone), keyid),
-                                      'PUT',
-                                      {'published': published,
-                                       'active': True})
+        code, resp = self._do_request(
+            "/zones/{}/cryptokeys/{}".format(_sanitize_dnsname(zone), keyid),
+            "PUT",
+            {"published": published, "active": True},
+        )
         if code == 422:
-            raise Exception('Failed to set cryptokey {} in zone {} to {}: {}'.format(
-                keyid, zone, 'published' if published else 'unpublished', resp))
+            raise Exception(
+                "Failed to set cryptokey {} in zone {} to {}: {}".format(
+                    keyid, zone, "published" if published else "unpublished", resp
+                )
+            )
         if code == 204:
             return self.get_cryptokey(zone, cryptokey)
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
     def publish_cryptokey(self, zone, cryptokey):
 
-        return  self.set_cryptokey_published(zone, cryptokey, published=True)
+        return self.set_cryptokey_published(zone, cryptokey, published=True)
 
     def unpublish_cryptokey(self, zone, cryptokey):
 
-        return  self.set_cryptokey_published(zone, cryptokey, published=False)
+        return self.set_cryptokey_published(zone, cryptokey, published=False)
 
     def delete_cryptokey(self, zone, cryptokey):
         """
@@ -254,17 +257,15 @@ class PDNSApi:
             keyid = cryptokey
         if keyid == -1:
             raise Exception("cryptokey is not a CryptoKey, nor a str or int")
-        code, resp = self._do_request('/zones/{}/cryptokeys/{}'.format(_sanitize_dnsname(zone), keyid),
-                                      'DELETE')
+        code, resp = self._do_request("/zones/{}/cryptokeys/{}".format(_sanitize_dnsname(zone), keyid), "DELETE")
         if code == 422:
-            raise Exception('Failed to remove cryptokey {} in zone {}: {}'.format(
-                keyid, zone, resp))
+            raise Exception("Failed to remove cryptokey {} in zone {}: {}".format(keyid, zone, resp))
         if code == 204:
             return
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
-    def add_cryptokey(self, zone, keytype='zsk', active=False, content=None, algo=None, bits=None, published=True):
+    def add_cryptokey(self, zone, keytype="zsk", active=False, content=None, algo=None, bits=None, published=True):
         """
         Adds a CryptoKey to zone. If content is None, a new key is generated by the server, using algorithm from `algo`
         and a size of `bits` (if applicable). If `content` and `algo` are both None, the server default is used (in
@@ -280,31 +281,27 @@ class PDNSApi:
         :raises: an Exception on failure
         """
 
-        data = {'active': active,
-                'keytype': keytype,
-                'published': published}
+        data = {"active": active, "keytype": keytype, "published": published}
 
         if content is not None:
-            data.update({'content': content})
+            data.update({"content": content})
 
         if algo is not None:
             algo = pdnsapi.cryptokey.shorthand_to_algo.get(algo, algo)
-            data.update({'algorithm': algo})
+            data.update({"algorithm": algo})
 
         if bits is not None:
-            data.update({'bits': bits})
+            data.update({"bits": bits})
 
-        code, resp = self._do_request('/zones/{}/cryptokeys'.format(_sanitize_dnsname(zone)),
-                                      'POST',
-                                      data)
+        code, resp = self._do_request("/zones/{}/cryptokeys".format(_sanitize_dnsname(zone)), "POST", data)
 
         if code == 422:
-            raise Exception('Unable to create CryptoKey in zone {}: {}'.format(zone, resp))
+            raise Exception("Unable to create CryptoKey in zone {}: {}".format(zone, resp))
         if code == 201:
-            resp.pop('type')
+            resp.pop("type")
             return CryptoKey(**resp)
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
     def get_zones(self):
         """
@@ -313,12 +310,11 @@ class PDNSApi:
         :return: All zones ons the server
         :rtype: list(:class:`pdnsapi.zone.Zone`)
         """
-        code, resp = self._do_request('/zones',
-                                      'GET')
+        code, resp = self._do_request("/zones", "GET")
         if code == 200:
             return [Zone(**zone) for zone in resp]
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
     def get_zone(self, zone):
         """
@@ -327,13 +323,12 @@ class PDNSApi:
         :param str zone: The zone we want the full contents for
         :return: a :class:`pdnsapi.zone.Zone`
         """
-        code, resp = self._do_request('/zones/{}'.format(_sanitize_dnsname(zone)),
-                                      'GET')
+        code, resp = self._do_request("/zones/{}".format(_sanitize_dnsname(zone)), "GET")
 
         if code == 200:
             return Zone(**resp)
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
     def bump_soa(self, zone, serial=None):
         """
@@ -347,40 +342,38 @@ class PDNSApi:
         soa = None
         content = self.get_zone(zone)
         for rrset in content.rrsets:
-            if rrset.rtype == "SOA" :
+            if rrset.rtype == "SOA":
                 soa = rrset
                 break
 
         if soa is None:
-            raise Exception('No such SOA record')
+            raise Exception("No such SOA record")
 
-        
         newcontent = soa.records[0].content.split(" ")
         if serial != None:
             newcontent[2] = serial
         else:
             newcontent[2] = str(int(newcontent[2]) + 1)
-        code, resp = self._do_request('/zones/{}'.format(_sanitize_dnsname(zone)),
-                                      'PATCH',
-                                      {
-                                          "rrsets": [{
-                                              "name": soa.name,
-                                              "type": soa.rtype,
-                                              "ttl": soa.ttl,
-                                              "changetype": "REPLACE",
-                                              "records": [
-                                                  {
-                                                      "content": " ".join(newcontent),
-                                                      "disabled": soa.records[0].disabled
-                                                  }
-                                              ]
-                                          }]
-                                      })
+        code, resp = self._do_request(
+            "/zones/{}".format(_sanitize_dnsname(zone)),
+            "PATCH",
+            {
+                "rrsets": [
+                    {
+                        "name": soa.name,
+                        "type": soa.rtype,
+                        "ttl": soa.ttl,
+                        "changetype": "REPLACE",
+                        "records": [{"content": " ".join(newcontent), "disabled": soa.records[0].disabled}],
+                    }
+                ]
+            },
+        )
 
         if code == 204:
             return self.get_zone(zone)
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
     def set_zone_param(self, zone, param, value):
         """
@@ -391,15 +384,14 @@ class PDNSApi:
         :return:
         """
         zonename = _sanitize_dnsname(zone)
-        code, resp = self._do_request('/zones/{}'.format(zonename),
-                                      'PUT', {param: value})
+        code, resp = self._do_request("/zones/{}".format(zonename), "PUT", {param: value})
 
         if code == 204:
             return self.get_zone(zonename)
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
-    def get_zone_metadata(self, zone, kind=''):
+    def get_zone_metadata(self, zone, kind=""):
         """
         Gets zone metadata
 
@@ -407,39 +399,37 @@ class PDNSApi:
         :param kind: The zone metadata kind to retrieve. If this is an empty string, all zone metadata is retrieved
         :return: A list of :class:`pdnsapi.metadata.ZoneMetadata` objects
         """
-        code, resp = self._do_request('/zones/{}/metadata{}'.format(_sanitize_dnsname(zone), '/' + kind if len(kind) else ''),
-                                      'GET')
+        code, resp = self._do_request(
+            "/zones/{}/metadata{}".format(_sanitize_dnsname(zone), "/" + kind if len(kind) else ""), "GET"
+        )
 
         if code == 200:
-            if kind == '':
-                return [ZoneMetadata(r['kind'], r['metadata']) for r in resp]
+            if kind == "":
+                return [ZoneMetadata(r["kind"], r["metadata"]) for r in resp]
             else:
-                return ZoneMetadata(resp['kind'], resp['metadata'])
+                return ZoneMetadata(resp["kind"], resp["metadata"])
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
     def set_zone_metadata(self, zone, kind, metadata):
         if not isinstance(metadata, list):
             metadata = [metadata]
-        obj = {'metadata': metadata}
-        code, resp = self._do_request('/zones/{}/metadata/{}'.format(_sanitize_dnsname(zone), kind),
-                                      'PUT',
-                                      obj)
+        obj = {"metadata": metadata}
+        code, resp = self._do_request("/zones/{}/metadata/{}".format(_sanitize_dnsname(zone), kind), "PUT", obj)
 
         if code == 422:
-            raise Exception('Failed to set metadata {} in zone {} to {}: {}'.format(kind, zone, metadata, resp))
+            raise Exception("Failed to set metadata {} in zone {} to {}: {}".format(kind, zone, metadata, resp))
         if code == 200:
-            return ZoneMetadata(resp['kind'], resp['metadata'])
+            return ZoneMetadata(resp["kind"], resp["metadata"])
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
 
     def delete_zone_metadata(self, zone, kind):
-        code, resp = self._do_request('/zones/{}/metadata/{}'.format(_sanitize_dnsname(zone), kind),
-                                      'DELETE')
+        code, resp = self._do_request("/zones/{}/metadata/{}".format(_sanitize_dnsname(zone), kind), "DELETE")
 
         if code == 422:
-            raise Exception('Failed to remove metadata {} in zone {}: {}'.format(kind, zone, resp))
+            raise Exception("Failed to remove metadata {} in zone {}: {}".format(kind, zone, resp))
         if code == 200:
             return
 
-        raise Exception('Unexpected response: {}: {}'.format(code, resp))
+        raise Exception("Unexpected response: {}: {}".format(code, resp))
index 5634d81bd6c3529cb9d44d4a4aa7a087a03ab8dc..a792b593825bc0495842d942f5b0f4bb119ab1ea 100644 (file)
@@ -16,18 +16,14 @@ algo_to_shorthand = {
 
 shorthand_to_algo = {v: k for k, v in algo_to_shorthand.items()}
 
-algo_to_bits = {
-    13: 256,
-    14: 512,
-    15: 32,
-    16: 57.
-}
+algo_to_bits = {13: 256, 14: 512, 15: 32, 16: 57.0}
 
 
 class CryptoKey:
     """
     Represents a CryptoKey from the API
     """
+
     _algo = None
 
     def __init__(self, id, active, keytype, flags=None, algo=None, dnskey=None, ds=None, privatekey=None, **kwargs):
@@ -51,24 +47,33 @@ class CryptoKey:
         self.dnskey = dnskey
         self.ds = ds
         self.privatekey = privatekey
-        self.algo = algo or dnskey.split(' ')[2]
+        self.algo = algo or dnskey.split(" ")[2]
 
     def __repr__(self):
         return 'CryptoKey({id}, {active}, {keytype}, {flags}, {algo}, {dnskey}, {ds}, "{privatekey})'.format(
-            id=self.id, active=self.active, keytype=self.keytype, flags=self.flags, algo=self.algo, dnskey=self.dnskey,
-            ds=self.ds, privatekey=self.privatekey)
+            id=self.id,
+            active=self.active,
+            keytype=self.keytype,
+            flags=self.flags,
+            algo=self.algo,
+            dnskey=self.dnskey,
+            ds=self.ds,
+            privatekey=self.privatekey,
+        )
 
     def __str__(self):
-        return str({
-            'id': self.id,
-            'active': self.active,
-            'keytype': self.keytype,
-            'flags': self.flags,
-            'dnskey': self.dnskey,
-            'ds': self.ds,
-            'privatekey': self.privatekey,
-            'algo': self.algo,
-        })
+        return str(
+            {
+                "id": self.id,
+                "active": self.active,
+                "keytype": self.keytype,
+                "flags": self.flags,
+                "dnskey": self.dnskey,
+                "ds": self.ds,
+                "privatekey": self.privatekey,
+                "algo": self.algo,
+            }
+        )
 
     @property
     def algo(self):
@@ -91,4 +96,3 @@ class CryptoKey:
                 self.algo = shorthand_to_algo.get(val, val)
             return
         raise ValueError("Value is not a str or int, but a {}".format(type(val)))
-
index 82093f2f1e36fbf9253765a2e3e4b6d5ba20d3af..a12ccc3c1bc0e813eb2a8318626d2fd5e9dff9f5 100644 (file)
@@ -2,17 +2,14 @@ class ZoneMetadata:
     def __init__(self, kind, metadata):
         self.kind = kind
         if not isinstance(metadata, list):
-            raise Exception('metadata must be a list, not a {}'.format(type(metadata)))
+            raise Exception("metadata must be a list, not a {}".format(type(metadata)))
         self.metadata = metadata
 
     def empty(self):
         return not self.metadata
 
     def __repr__(self):
-        return 'ZoneMetadata({}, {})'.format(self.kind, self.metadata)
+        return "ZoneMetadata({}, {})".format(self.kind, self.metadata)
 
     def __str__(self):
-        return str({
-            'kind': self.kind,
-            'metadata': self.metadata
-        })
+        return str({"kind": self.kind, "metadata": self.metadata})
index 5ba1693d31e41e9e3bcd01889607c162981af0a0..777f46eb3f54d61ec30874a422ba305db3cc576a 100644 (file)
@@ -21,9 +21,13 @@ class RRSet:
         return 'RRSet("{}", "{}", {}, {}, {})'.format(self.name, self.rtype, self.ttl, self.records, self.comments)
 
     def __str__(self):
-        ret = '\n'.join(['; {}'.format(c) for c in self.comments])
-        ret += '\n'.join(['{}{}\tIN\t{}\t{}'.format(';' if rec.disabled else '', self.name, self.rtype, rec.content)
-                         for rec in self.records])
+        ret = "\n".join(["; {}".format(c) for c in self.comments])
+        ret += "\n".join(
+            [
+                "{}{}\tIN\t{}\t{}".format(";" if rec.disabled else "", self.name, self.rtype, rec.content)
+                for rec in self.records
+            ]
+        )
         return ret
 
     @property
@@ -33,14 +37,14 @@ class RRSet:
     @records.setter
     def records(self, val):
         if not isinstance(val, list):
-            raise Exception('TODO')
+            raise Exception("TODO")
         if all(isinstance(v, dict) for v in val):
             self._records = []
             for v in val:
                 self._records.append(Record(**v))
             return
         if not all(isinstance(v, Record) for v in val):
-            raise Exception('Not all records are of type Record')
+            raise Exception("Not all records are of type Record")
         self._records = val
 
     @property
@@ -50,14 +54,14 @@ class RRSet:
     @comments.setter
     def comments(self, val):
         if not isinstance(val, list):
-            raise Exception('TODO')
+            raise Exception("TODO")
         if all(isinstance(v, dict) for v in val):
             self._comments = []
             for v in val:
                 self._comments.append(Comment(**v))
             return
         if not all(isinstance(v, Comment) for v in val):
-            raise Exception('Not all comments are of type Comment')
+            raise Exception("Not all comments are of type Comment")
         self._comments = val
 
 
@@ -95,18 +99,37 @@ class Comment:
         return 'Comment("{}", "{}", "{})'.format(self.content, self.modified_at, self.account)
 
     def __str__(self):
-        return '{} by {} on {}'.format(self.content, self.account, self.modified_at)
+        return "{} by {} on {}".format(self.content, self.account, self.modified_at)
 
 
 class Zone:
     """
     This represents a Zone-object
     """
-    _keys = ["id", "name", "url", "kind", "serial", "notified_serial", "masters", "dnssec", "nsec3param",
-             "nsec3narrow", "presigned", "soa_edit", "soa_edit_api", "account", "nameservers", "servers",
-             "recursion_desired", "rrsets", "last_check"]
+
+    _keys = [
+        "id",
+        "name",
+        "url",
+        "kind",
+        "serial",
+        "notified_serial",
+        "masters",
+        "dnssec",
+        "nsec3param",
+        "nsec3narrow",
+        "presigned",
+        "soa_edit",
+        "soa_edit_api",
+        "account",
+        "nameservers",
+        "servers",
+        "recursion_desired",
+        "rrsets",
+        "last_check",
+    ]
     _rrsets = []
-    _kind = ''
+    _kind = ""
 
     def __init__(self, **kwargs):
         """
@@ -118,14 +141,22 @@ class Zone:
                 setattr(self, k, v)
 
     def __str__(self):
-        ret = "{}".format('\n'.join(['; {} = {}'.format(
-            k, str(getattr(self, k))) for k in Zone._keys if getattr(self, k, None) and k != 'rrsets']))
-        ret += "\n{}".format('\n'.join([str(v) for v in self.rrsets]))
+        ret = "{}".format(
+            "\n".join(
+                [
+                    "; {} = {}".format(k, str(getattr(self, k)))
+                    for k in Zone._keys
+                    if getattr(self, k, None) and k != "rrsets"
+                ]
+            )
+        )
+        ret += "\n{}".format("\n".join([str(v) for v in self.rrsets]))
         return ret
 
     def __repr__(self):
-        return 'Zone({})'.format(
-            ', '.join(['{}="{}"'.format(k, getattr(self, k)) for k in Zone._keys if getattr(self, k, None)]))
+        return "Zone({})".format(
+            ", ".join(['{}="{}"'.format(k, getattr(self, k)) for k in Zone._keys if getattr(self, k, None)])
+        )
 
     @property
     def kind(self):
@@ -133,7 +164,7 @@ class Zone:
 
     @kind.setter
     def kind(self, val):
-        if val not in ['Native', 'Master', 'Slave']:
+        if val not in ["Native", "Master", "Slave"]:
             raise Exception("TODO")
         self._kind = val
 
@@ -149,12 +180,12 @@ class Zone:
         :return:
         """
         if not isinstance(val, list):
-            raise Exception('Please pass a list of RRSets')
+            raise Exception("Please pass a list of RRSets")
         if all(isinstance(v, dict) for v in val):
             self._rrsets = []
             for v in val:
                 self._rrsets.append(RRSet(**v))
             return
         if not all(isinstance(v, RRSet) for v in val):
-            raise Exception('Not all rrsets are actually RRSets')
+            raise Exception("Not all rrsets are actually RRSets")
         self._rrsets = val
index 115fdb943ac9a22437a2557eed9755ab696116ef..a75e9fed70f12d31cbb3c4884e67eefaf7a17264 100644 (file)
@@ -1,4 +1,4 @@
-__author__ = 'PowerDNS.COM BV'
+__author__ = "PowerDNS.COM BV"
 
-PDNSKEYROLLER_CONFIG_metadata_kind = 'X-PDNSKEYROLLER-CONFIG'
-PDNSKEYROLLER_STATE_metadata_kind = 'X-PDNSKEYROLLER-STATE'
+PDNSKEYROLLER_CONFIG_metadata_kind = "X-PDNSKEYROLLER-CONFIG"
+PDNSKEYROLLER_STATE_metadata_kind = "X-PDNSKEYROLLER-STATE"
index 9cbb281837711755abd288ff91ff8523c00933e6..c0f55bc62c38d7f1c994b3254b0058d450aac6e0 100644 (file)
@@ -16,32 +16,32 @@ class KeyrollerConfig:
     def _load_config(self):
         # These are all the Defaults
         tmp_conf = {
-            'keyroller': {
-                'loglevel': 'info',
+            "keyroller": {
+                "loglevel": "info",
             },
-            'API': {
-                'version': 1,
-                'baseurl': 'http://localhost:8081',
-                'server': 'localhost',
-                'apikey': '',
-                'timeout': '2',
+            "API": {
+                "version": 1,
+                "baseurl": "http://localhost:8081",
+                "server": "localhost",
+                "apikey": "",
+                "timeout": "2",
             },
-            'domain_defaults': {
-                'ksk_frequency': 0,
-                'ksk_algo': 13,
-                'ksk_method': 'prepublish',
-                'zsk_frequency': '6w',
-                'zsk_algo': 13,
-                'zsk_method': 'prepublish',
-                'key_style': 'single',
-                'ksk_keysize': 3069,
-                'zsk_keysize': 3069,
+            "domain_defaults": {
+                "ksk_frequency": 0,
+                "ksk_algo": 13,
+                "ksk_method": "prepublish",
+                "zsk_frequency": "6w",
+                "zsk_algo": 13,
+                "zsk_method": "prepublish",
+                "key_style": "single",
+                "ksk_keysize": 3069,
+                "zsk_keysize": 3069,
             },
         }
 
         logger.debug("Loading configuration from {}".format(self._configfile))
         try:
-            with open(self._configfile, 'r') as f:
+            with open(self._configfile, "r") as f:
                 a = yaml.safe_load(f)
                 if a:
                     for k, v in tmp_conf.items():
@@ -50,19 +50,19 @@ class KeyrollerConfig:
                         if isinstance(v, list) and isinstance(a.get(k), list):
                             tmp_conf[k] = a.get(k)
 
-            loglevel = getattr(logging, tmp_conf['keyroller']['loglevel'].upper())
+            loglevel = getattr(logging, tmp_conf["keyroller"]["loglevel"].upper())
             if not isinstance(loglevel, int):
                 loglevel = logging.INFO
             logger.info("Setting loglevel to {}".format(loglevel))
             logging.basicConfig(level=loglevel)
 
         except FileNotFoundError as e:
-            logger.error('Unable to load configuration file: {}'.format(e))
+            logger.error("Unable to load configuration file: {}".format(e))
 
         return tmp_conf
 
     def api(self):
-        return self._config['API']
+        return self._config["API"]
 
     def defaults(self):
-        return self._config['domain_defaults']
+        return self._config["domain_defaults"]
index b63b6627de5620c7bcbbad5ceaccab95006cf98e..788b10f593133613f54ba3ccbfc471a8dca9d4b8 100644 (file)
@@ -17,7 +17,7 @@ class Daemon:
 
         # Initialize all domains
         self._domains = {}
-        api = PDNSApi(**self._config['API'])
+        api = PDNSApi(**self._config["API"])
         for zone in api.get_zones():
             try:
                 zoneconf = pdnskeyroller.keyrollerdomain.KeyrollerDomain(zone.id, api)
@@ -32,21 +32,21 @@ class Daemon:
     def _load_config(self):
         # These are all the Defaults
         tmp_conf = {
-            'keyroller': {
-                'loglevel': 'info',
+            "keyroller": {
+                "loglevel": "info",
             },
-            'API': {
-                'version': 1,
-                'baseurl': 'http://localhost:8081',
-                'server': 'localhost',
-                'apikey': '',
-                'timeout': '2',
+            "API": {
+                "version": 1,
+                "baseurl": "http://localhost:8081",
+                "server": "localhost",
+                "apikey": "",
+                "timeout": "2",
             },
         }
 
         logger.debug("Loading configuration from {}".format(self._configfile))
         try:
-            with open(self._configfile, 'r') as f:
+            with open(self._configfile, "r") as f:
                 a = yaml.safe_load(f)
                 if a:
                     for k, v in tmp_conf.items():
@@ -55,21 +55,24 @@ class Daemon:
                         if isinstance(v, list) and isinstance(a.get(k), list):
                             tmp_conf[k] = a.get(k)
 
-            loglevel = getattr(logging, tmp_conf['keyroller']['loglevel'].upper())
+            loglevel = getattr(logging, tmp_conf["keyroller"]["loglevel"].upper())
             if not isinstance(loglevel, int):
                 loglevel = logging.INFO
             logger.info("Setting loglevel to {}".format(loglevel))
             logging.basicConfig(level=loglevel)
 
         except FileNotFoundError as e:
-            logger.error('Unable to load configuration file: {}'.format(e))
+            logger.error("Unable to load configuration file: {}".format(e))
 
         return tmp_conf
 
     def _get_actionable_domains(self):
         now = datetime.datetime.now()
-        return [zone for zone, domainconf in self._domains.items() if
-                domainconf.next_action_datetime and domainconf.next_action_datetime <= now]
+        return [
+            zone
+            for zone, domainconf in self._domains.items()
+            if domainconf.next_action_datetime and domainconf.next_action_datetime <= now
+        ]
 
     def update_config(self):
         """
@@ -84,13 +87,16 @@ class Daemon:
         now = datetime.datetime.now()
         logger.debug("Found {} domain(s) ({} actionable)".format(len(self._domains), len(actionable_domains)))
 
-
         if len(actionable_domains) > 0:
             for domain in actionable_domains:
                 keyrollerdomain = self._domains[domain]
                 if keyrollerdomain.state.is_rolling:
                     try:
-                        logger.info("Moving to step {} for {} roll".format(keyrollerdomain.current_step_name, keyrollerdomain.zone))
+                        logger.info(
+                            "Moving to step {} for {} roll".format(
+                                keyrollerdomain.current_step_name, keyrollerdomain.zone
+                            )
+                        )
                         keyrollerdomain.step()
                     except Exception as e:
                         logger.error("Unable to advance keyroll: {}".format(e))
@@ -99,18 +105,30 @@ class Daemon:
                     next_zsk_roll = keyrollerdomain.next_zsk_roll()
                     if next_zsk_roll is not None and next_zsk_roll <= now:
                         try:
-                            logger.info("Starting {} {} keyroll for {} ({} algo)".format("pre-publish", "ZSK", keyrollerdomain.zone, keyrollerdomain.config.zsk_algo))
+                            logger.info(
+                                "Starting {} {} keyroll for {} ({} algo)".format(
+                                    "pre-publish", "ZSK", keyrollerdomain.zone, keyrollerdomain.config.zsk_algo
+                                )
+                            )
                             roll = PrePublishKeyRoll()
-                            roll.initiate(keyrollerdomain.zone, keyrollerdomain.api, 'zsk', keyrollerdomain.config.zsk_algo)
+                            roll.initiate(
+                                keyrollerdomain.zone, keyrollerdomain.api, "zsk", keyrollerdomain.config.zsk_algo
+                            )
                             keyrollerdomain.state.current_roll = roll
                             domainstate.to_api(keyrollerdomain.zone, keyrollerdomain.api, keyrollerdomain.state)
                         except Exception as e:
                             logger.error("Unable to start keyroll: {}".format(e))
                     elif next_ksk_roll is not None and next_ksk_roll <= now:
                         try:
-                            logger.info("Starting {} {} keyroll for {} ({} algo)".format("pre-publish", "KSK", keyrollerdomain.zone, keyrollerdomain.config.zsk_algo))
+                            logger.info(
+                                "Starting {} {} keyroll for {} ({} algo)".format(
+                                    "pre-publish", "KSK", keyrollerdomain.zone, keyrollerdomain.config.zsk_algo
+                                )
+                            )
                             roll = PrePublishKeyRoll()
-                            roll.initiate(keyrollerdomain.zone, keyrollerdomain.api, 'ksk', keyrollerdomain.config.ksk_algo)
+                            roll.initiate(
+                                keyrollerdomain.zone, keyrollerdomain.api, "ksk", keyrollerdomain.config.ksk_algo
+                            )
                             keyrollerdomain.state.current_roll = roll
                             domainstate.to_api(keyrollerdomain.zone, keyrollerdomain.api, keyrollerdomain.state)
                         except Exception as e:
index c809fef207f16ef66e934186fd7408babb68f9e2..45e7db98323e9a20acf2e986cace6cf010cc47bb 100644 (file)
@@ -3,10 +3,11 @@ from pdnskeyroller import PDNSKEYROLLER_CONFIG_metadata_kind
 from pytimeparse.timeparse import timeparse
 import pdnsapi.metadata
 import json_tricks.nonp as json_tricks
-from pdnskeyroller.util import (parse_algo)
+from pdnskeyroller.util import parse_algo
 
 DOMAINCONFIG_VERSION = 1
 
+
 def from_api(zone, api):
     """
     Retrieves a keyroller configuration for zone ``zone`` from the api ``api``
@@ -18,7 +19,7 @@ def from_api(zone, api):
     :raises: FileNotFoundError if ``zone`` does not have a roller config
     """
     if not isinstance(api, pdnsapi.api.PDNSApi):
-        raise Exception('api is not a PDNSApi')
+        raise Exception("api is not a PDNSApi")
 
     metadata = api.get_zone_metadata(zone, PDNSKEYROLLER_CONFIG_metadata_kind)
 
@@ -26,8 +27,9 @@ def from_api(zone, api):
         raise FileNotFoundError
 
     if len(metadata.metadata) > 1:
-        raise Exception("More than one {} Domain Metadata found for {}!".format(PDNSKEYROLLER_CONFIG_metadata_kind,
-                                                                                zone))
+        raise Exception(
+            "More than one {} Domain Metadata found for {}!".format(PDNSKEYROLLER_CONFIG_metadata_kind, zone)
+        )
     try:
         state = json_tricks.loads(metadata.metadata[0])
     except Exception as e:
@@ -35,6 +37,7 @@ def from_api(zone, api):
 
     return DomainConfig(**state)
 
+
 def to_api(zone, api, config):
     """
 
@@ -44,9 +47,9 @@ def to_api(zone, api, config):
     :return:
     """
     if not isinstance(api, pdnsapi.api.PDNSApi):
-        raise Exception('api must be a PDNSApi instance, not a {}'.format(type(api)))
+        raise Exception("api must be a PDNSApi instance, not a {}".format(type(api)))
     if not isinstance(config, DomainConfig):
-        raise Exception('config must be a DomainConfig instance, not a {}'.format(type(config)))
+        raise Exception("config must be a DomainConfig instance, not a {}".format(type(config)))
 
     api.set_zone_metadata(zone, PDNSKEYROLLER_CONFIG_metadata_kind, str(config))
 
@@ -63,8 +66,20 @@ class DomainConfig:
     __zsk_method = "prepublish"
     __key_style = "split"
 
-    def __init__(self, version=DOMAINCONFIG_VERSION, ksk_frequency=0, ksk_algo=13, ksk_keysize=3096, ksk_method="prepublish",
-                 zsk_frequency="6w", zsk_algo=13, zsk_keysize=3096, zsk_method="prepublish", key_style="split", **kwargs):
+    def __init__(
+        self,
+        version=DOMAINCONFIG_VERSION,
+        ksk_frequency=0,
+        ksk_algo=13,
+        ksk_keysize=3096,
+        ksk_method="prepublish",
+        zsk_frequency="6w",
+        zsk_algo=13,
+        zsk_keysize=3096,
+        zsk_method="prepublish",
+        key_style="split",
+        **kwargs,
+    ):
 
         self.version = version
 
@@ -80,8 +95,7 @@ class DomainConfig:
 
         self.key_style = key_style
         if kwargs:
-            logger.warning('Unknown keys passed: {}'.format(', '.join(
-                [k for k, v in kwargs.items()])))
+            logger.warning("Unknown keys passed: {}".format(", ".join([k for k, v in kwargs.items()])))
 
     @property
     def ksk_frequency(self):
@@ -164,8 +178,8 @@ class DomainConfig:
 
     @key_style.setter
     def key_style(self, value):
-        if value not in ('single', 'split'):
-            raise Exception('Invalid key_style: {}'. format(value))
+        if value not in ("single", "split"):
+            raise Exception("Invalid key_style: {}".format(value))
         self.__key_style = value
 
     @property
@@ -175,24 +189,42 @@ class DomainConfig:
     @version.setter
     def version(self, val):
         if val != 1:
-            raise Exception('{} is not a valid version!')
+            raise Exception("{} is not a valid version!")
         self.__version = val
 
     def __repr__(self):
-        return 'DomainConfig({})'.format(
-            ', '.join(['{} = "{}"'.format(k, self.__getattribute__(k)) for k in
-                       ["version", "ksk_frequency", "ksk_algo", "ksk_keysize", "ksk_method", "zsk_frequency",
-                        "zsk_algo", "zsk_keysize", "zsk_method", "key_style"]]))
+        return "DomainConfig({})".format(
+            ", ".join(
+                [
+                    '{} = "{}"'.format(k, self.__getattribute__(k))
+                    for k in [
+                        "version",
+                        "ksk_frequency",
+                        "ksk_algo",
+                        "ksk_keysize",
+                        "ksk_method",
+                        "zsk_frequency",
+                        "zsk_algo",
+                        "zsk_keysize",
+                        "zsk_method",
+                        "key_style",
+                    ]
+                ]
+            )
+        )
+
     def __str__(self):
-        return(json_tricks.dumps({
-            'version': self.version,
-            'ksk_frequency': self.ksk_frequency,
-            'ksk_algo': self.ksk_algo,
-            'ksk_keysize': self.ksk_keysize,
-            'ksk_method': self.ksk_method,
-            'zsk_frequency': self.zsk_frequency,
-            'zsk_algo': self.zsk_algo,
-            'zsk_keysize': self.zsk_keysize,
-            'zsk_method': self.zsk_method,
-            'key_style': self.key_style,
-        }))
+        return json_tricks.dumps(
+            {
+                "version": self.version,
+                "ksk_frequency": self.ksk_frequency,
+                "ksk_algo": self.ksk_algo,
+                "ksk_keysize": self.ksk_keysize,
+                "ksk_method": self.ksk_method,
+                "zsk_frequency": self.zsk_frequency,
+                "zsk_algo": self.zsk_algo,
+                "zsk_keysize": self.zsk_keysize,
+                "zsk_method": self.zsk_method,
+                "key_style": self.key_style,
+            }
+        )
index c5034ff031fb615d1352b046e9c9964a5e2d48aa..f757500e5faa62c3705ca94039808115e46ed4e3 100644 (file)
@@ -21,14 +21,14 @@ def from_api(zone, api):
     :raises: ValueError if the JSON from the domain metadata cannot be unpacked
     """
     if not isinstance(api, pdnsapi.api.PDNSApi):
-        raise Exception('api must be a PDNSApi instance, not a {}'.format(type(api)))
+        raise Exception("api must be a PDNSApi instance, not a {}".format(type(api)))
     tmp_state = api.get_zone_metadata(zone, PDNSKEYROLLER_STATE_metadata_kind).metadata
 
     if not tmp_state:
         return DomainState()
 
     if len(tmp_state) > 1:
-        raise Exception('More than one {} metadata found!'.format(PDNSKEYROLLER_STATE_metadata_kind))
+        raise Exception("More than one {} metadata found!".format(PDNSKEYROLLER_STATE_metadata_kind))
 
     try:
         state = json_tricks.loads(tmp_state[0])
@@ -47,9 +47,9 @@ def to_api(zone, api, state):
     :return:
     """
     if not isinstance(api, pdnsapi.api.PDNSApi):
-        raise Exception('api must be a PDNSApi instance, not a {}'.format(type(api)))
+        raise Exception("api must be a PDNSApi instance, not a {}".format(type(api)))
     if not isinstance(state, DomainState):
-        raise Exception('state must be a DomainState instance, not a {}'.format(type(state)))
+        raise Exception("state must be a DomainState instance, not a {}".format(type(state)))
 
     if state.current_roll.complete:
         state.set_last_roll_date(state.current_roll.keytype, state.current_roll.step_datetimes[-1])
@@ -64,16 +64,29 @@ class DomainState:
     __current_roll = None
     __version = DOMAINSTATE_VERSION
 
-    def __init__(self, version=DOMAINSTATE_VERSION, last_ksk_roll_datetime=datetime.min,
-                 last_zsk_roll_datetime=datetime.min, current_roll=KeyRoll(), **kwargs):
+    def __init__(
+        self,
+        version=DOMAINSTATE_VERSION,
+        last_ksk_roll_datetime=datetime.min,
+        last_zsk_roll_datetime=datetime.min,
+        current_roll=KeyRoll(),
+        **kwargs,
+    ):
 
         self.version = version
-        self.last_ksk_roll_datetime = last_ksk_roll_datetime if isinstance(last_ksk_roll_datetime, datetime) else datetime.fromtimestamp(last_ksk_roll_datetime)
-        self.last_zsk_roll_datetime = last_zsk_roll_datetime if isinstance(last_zsk_roll_datetime, datetime) else datetime.fromtimestamp(last_zsk_roll_datetime)
+        self.last_ksk_roll_datetime = (
+            last_ksk_roll_datetime
+            if isinstance(last_ksk_roll_datetime, datetime)
+            else datetime.fromtimestamp(last_ksk_roll_datetime)
+        )
+        self.last_zsk_roll_datetime = (
+            last_zsk_roll_datetime
+            if isinstance(last_zsk_roll_datetime, datetime)
+            else datetime.fromtimestamp(last_zsk_roll_datetime)
+        )
         self.current_roll = current_roll
         if kwargs:
-            logger.warning('Unknown keys passed: {}'.format(', '.join(
-                [k for k, v in kwargs.items()])))
+            logger.warning("Unknown keys passed: {}".format(", ".join([k for k, v in kwargs.items()])))
 
     @property
     def last_zsk_roll_datetime(self):
@@ -82,7 +95,7 @@ class DomainState:
     @last_zsk_roll_datetime.setter
     def last_zsk_roll_datetime(self, val):
         if not isinstance(val, datetime):
-            raise Exception('Can not set last_zsk_roll_datetime: not a datetime object')
+            raise Exception("Can not set last_zsk_roll_datetime: not a datetime object")
         self.__last_zsk_roll_datetime = val
 
     @property
@@ -92,17 +105,16 @@ class DomainState:
     @last_ksk_roll_datetime.setter
     def last_ksk_roll_datetime(self, val):
         if not isinstance(val, datetime):
-            raise Exception('Can not set last_ksk_roll_datetime: not a datetime object')
+            raise Exception("Can not set last_ksk_roll_datetime: not a datetime object")
         self.__last_ksk_roll_datetime = val
 
     @property
     def last_ksk_roll_str(self):
-        return "never" if self.last_ksk_roll_datetime == datetime.min else \
-            str(self.last_ksk_roll_datetime)
+        return "never" if self.last_ksk_roll_datetime == datetime.min else str(self.last_ksk_roll_datetime)
+
     @property
     def last_zsk_roll_str(self):
-        return "never" if self.last_zsk_roll_datetime == datetime.min else \
-            str(self.last_zsk_roll_datetime)
+        return "never" if self.last_zsk_roll_datetime == datetime.min else str(self.last_zsk_roll_datetime)
 
     @property
     def current_roll(self):
@@ -111,7 +123,7 @@ class DomainState:
     @current_roll.setter
     def current_roll(self, val):
         if not isinstance(val, (KeyRoll, PrePublishKeyRoll)):
-            raise Exception('Roll is not a KeyRoll')
+            raise Exception("Roll is not a KeyRoll")
         self.__current_roll = val
 
     @property
@@ -121,32 +133,53 @@ class DomainState:
     @version.setter
     def version(self, val):
         if val != 1:
-            raise Exception('{} is not a valid version!')
+            raise Exception("{} is not a valid version!")
         self.__version = val
 
     def __repr__(self):
-        return 'DomainState({})'.format(
-            ', '.join(['{}={}'.format(k, v) for k, v in [
-                ('version', self.version),
-                ('last_ksk_roll_datetime', self.last_ksk_roll_datetime.timestamp() if self.last_ksk_roll_datetime > datetime.fromtimestamp(0) else 0),
-                ('last_zsk_roll_datetime', self.last_zsk_roll_datetime.timestamp() if self.last_zsk_roll_datetime > datetime.fromtimestamp(0) else 0),
-                ('current_roll', self.current_roll),
-            ]])
+        return "DomainState({})".format(
+            ", ".join(
+                [
+                    "{}={}".format(k, v)
+                    for k, v in [
+                        ("version", self.version),
+                        (
+                            "last_ksk_roll_datetime",
+                            self.last_ksk_roll_datetime.timestamp()
+                            if self.last_ksk_roll_datetime > datetime.fromtimestamp(0)
+                            else 0,
+                        ),
+                        (
+                            "last_zsk_roll_datetime",
+                            self.last_zsk_roll_datetime.timestamp()
+                            if self.last_zsk_roll_datetime > datetime.fromtimestamp(0)
+                            else 0,
+                        ),
+                        ("current_roll", self.current_roll),
+                    ]
+                ]
+            )
         )
 
     def __str__(self):
-        return(json_tricks.dumps({
-            'version': self.version,
-            'last_ksk_roll_datetime': self.last_ksk_roll_datetime.timestamp() if self.last_ksk_roll_datetime > datetime.fromtimestamp(0) else 0,
-            'last_zsk_roll_datetime': self.last_zsk_roll_datetime.timestamp() if self.last_zsk_roll_datetime > datetime.fromtimestamp(0) else 0,
-            'current_roll': self.current_roll,
-        }))
+        return json_tricks.dumps(
+            {
+                "version": self.version,
+                "last_ksk_roll_datetime": self.last_ksk_roll_datetime.timestamp()
+                if self.last_ksk_roll_datetime > datetime.fromtimestamp(0)
+                else 0,
+                "last_zsk_roll_datetime": self.last_zsk_roll_datetime.timestamp()
+                if self.last_zsk_roll_datetime > datetime.fromtimestamp(0)
+                else 0,
+                "current_roll": self.current_roll,
+            }
+        )
 
     def set_last_roll_date(self, keytype, date):
-        self.__setattr__('last_{}_roll_datetime'.format(keytype), date)
+        self.__setattr__("last_{}_roll_datetime".format(keytype), date)
 
     def last_roll_date(self, keytype):
-        return self.__getattribute__('last_{}_roll_datetime'.format(keytype))
+        return self.__getattribute__("last_{}_roll_datetime".format(keytype))
 
     @property
     def is_rolling(self):
index 59b205f11aea43ddf32fa5edd650174229bfeae3..f45e551513a5e3f97e1eefa310d1b48a518050e6 100644 (file)
@@ -1,6 +1,6 @@
 class KeyRoll:
     def __init__(self, **kwargs):
-        self.rolltype = kwargs.get('rolltype')
+        self.rolltype = kwargs.get("rolltype")
         self.complete = False
 
     def initiate(self, zone, api, **kwargs):
@@ -13,7 +13,7 @@ class KeyRoll:
         raise NotImplementedError()
 
     def __str__(self):
-        return ''
+        return ""
 
     def __repr__(self):
         raise NotImplementedError()
index f09d38d1d178ae421c487bdf4e3ce1c2cffdb753..656625e880d8a11cae3ebbc806c5f48a399ed2d3 100644 (file)
@@ -7,10 +7,11 @@ import datetime
 
 logger = logging.getLogger(__name__)
 
+
 class KeyrollerDomain:
     def __init__(self, zone, api, config=None, state=None):
         if not isinstance(api, PDNSApi):
-            raise Exception('api is not a PDNSApi')
+            raise Exception("api is not a PDNSApi")
 
         self.zone = zone
         self.api = api
@@ -18,7 +19,7 @@ class KeyrollerDomain:
             config = pdnskeyroller.domainconfig.from_api(zone, api)
 
         if not isinstance(config, pdnskeyroller.domainconfig.DomainConfig):
-            raise Exception('config is not a DomainConfig')
+            raise Exception("config is not a DomainConfig")
 
         self.config = config
 
@@ -26,20 +27,24 @@ class KeyrollerDomain:
             state = pdnskeyroller.domainstate.from_api(zone, api)
 
         if not isinstance(state, pdnskeyroller.domainstate.DomainState):
-            raise Exception('state is not a DomainState')
+            raise Exception("state is not a DomainState")
 
         self.state = state
 
     def next_ksk_roll(self):
         if not self.state.is_rolling:
-            if self.config.ksk_frequency != 0 :
-                return self.state.last_roll_date('ksk') + datetime.timedelta(seconds=timeparse(self.config.ksk_frequency))
+            if self.config.ksk_frequency != 0:
+                return self.state.last_roll_date("ksk") + datetime.timedelta(
+                    seconds=timeparse(self.config.ksk_frequency)
+                )
         return None
 
     def next_zsk_roll(self):
         if not self.state.is_rolling:
             if self.config.zsk_frequency != 0:
-                return self.state.last_roll_date('zsk') + datetime.timedelta(seconds=timeparse(self.config.zsk_frequency))
+                return self.state.last_roll_date("zsk") + datetime.timedelta(
+                    seconds=timeparse(self.config.zsk_frequency)
+                )
         return None
 
     @property
@@ -80,8 +85,5 @@ class KeyrollerDomain:
             return ret[0]
         return None
 
-
     def __repr__(self):
-        return 'keyrollerDomain("{}", {}, {}, {})'.format(
-            self.zone, self.api, self.config, self.state
-        )
+        return 'keyrollerDomain("{}", {}, {}, {})'.format(self.zone, self.api, self.config, self.state)
index d9ebbca941e3dbdc10ae8274ec4481b30ffde892..0462c5db95887e70fd18206ff37baa9ba08485d3 100644 (file)
@@ -1,57 +1,58 @@
 import pdnsapi.api
 import json_tricks.nonp as json_tricks
-from pdnskeyroller.util import (get_keys_of_type, DNSKEY_ALGO_TO_MNEMONIC, DNSKEY_MNEMONIC_TO_ALGO, validate_api)
+from pdnskeyroller.util import get_keys_of_type, DNSKEY_ALGO_TO_MNEMONIC, DNSKEY_MNEMONIC_TO_ALGO, validate_api
 from datetime import datetime, timedelta
 from pdnskeyroller.keyroll import KeyRoll
 
 _step_to_name = {
-    0: 'initial',
-    1: 'new DNSKEY',
-    2: 'new DS/new RRSIGs',
-    3: 'DNSKEY removal',
+    0: "initial",
+    1: "new DNSKEY",
+    2: "new DS/new RRSIGs",
+    3: "DNSKEY removal",
 }
 
 
 class PrePublishKeyRoll(KeyRoll):
     def __init__(self, **kwargs):
-        super().__init__(rolltype='prepublish')
-        self.current_step = kwargs.get('current_step', 0)
-        self.complete = kwargs.get('complete', False)
-        self.step_datetimes = list(map(lambda x: datetime.fromtimestamp(x), kwargs.get('step_datetimes', [])))
-        self.current_step_datetime = datetime.fromtimestamp(kwargs.get('current_step_datetime', datetime.now().timestamp()))
-        self.keytype = kwargs.get('keytype')
-        self.algo = kwargs.get('algo')
-        self.old_keyids = kwargs.get('old_keyids')
-        self.new_keyid = kwargs.get('new_keyid')
+        super().__init__(rolltype="prepublish")
+        self.current_step = kwargs.get("current_step", 0)
+        self.complete = kwargs.get("complete", False)
+        self.step_datetimes = list(map(lambda x: datetime.fromtimestamp(x), kwargs.get("step_datetimes", [])))
+        self.current_step_datetime = datetime.fromtimestamp(
+            kwargs.get("current_step_datetime", datetime.now().timestamp())
+        )
+        self.keytype = kwargs.get("keytype")
+        self.algo = kwargs.get("algo")
+        self.old_keyids = kwargs.get("old_keyids")
+        self.new_keyid = kwargs.get("new_keyid")
 
     def initiate(self, zone, api, keytype, algo, bits=None, published=True):
         """
-        Initiate a pre-publish rollover (:rfc:`RFC 6781 Â§4.1.1.1 <6781#section-4.1.1.1>`) for the ``keytype`` key of algorithm
-    ``algo`` for ``zone``.
+            Initiate a pre-publish rollover (:rfc:`RFC 6781 Â§4.1.1.1 <6781#section-4.1.1.1>`) for the ``keytype`` key of algorithm
+        ``algo`` for ``zone``.
 
-        The roll will **only** be initiated if there exists a ``keytype`` key of algorithm ``algo`` for the domain ``zone``.
+            The roll will **only** be initiated if there exists a ``keytype`` key of algorithm ``algo`` for the domain ``zone``.
 
-        :param string zone: The zone to roll for
-        :param pdnsapi.api.PDNSApi api: The API endpoint to use
-        :param string keytype: The keytype to roll, must be one of 'ksk', 'zsk' or 'csk'
-        :param string algo: The algorithm to roll the ``keytype`` for
-        :param int bits: If needed, use this many bits for the new key for ``algo``
+            :param string zone: The zone to roll for
+            :param pdnsapi.api.PDNSApi api: The API endpoint to use
+            :param string keytype: The keytype to roll, must be one of 'ksk', 'zsk' or 'csk'
+            :param string algo: The algorithm to roll the ``keytype`` for
+            :param int bits: If needed, use this many bits for the new key for ``algo``
         """
         if self.started:
-            raise Exception('Already rolling the {} for {}'.format(
-                self.keytype, zone))
+            raise Exception("Already rolling the {} for {}".format(self.keytype, zone))
         validate_api(api)
 
         keytype = keytype.lower()
-        if keytype not in ('ksk', 'zsk'):
-            raise Exception('Invalid key type: {}'.format(keytype))
+        if keytype not in ("ksk", "zsk"):
+            raise Exception("Invalid key type: {}".format(keytype))
 
         current_keys = get_keys_of_type(zone, api, keytype)
         algo = DNSKEY_ALGO_TO_MNEMONIC.get(algo, algo)
         if not current_keys:
-            raise Exception('There are no keys of type {} in zone {}, cannot roll!'.format(keytype, zone))
+            raise Exception("There are no keys of type {} in zone {}, cannot roll!".format(keytype, zone))
         if not any([k.algo == algo and k.keytype == keytype for k in current_keys]):
-            raise Exception('No keys for algorithm {} in zone {}, cannot roll!'.format(algo, zone))
+            raise Exception("No keys for algorithm {} in zone {}, cannot roll!".format(algo, zone))
 
         active = True
         published = True
@@ -68,7 +69,7 @@ class PrePublishKeyRoll(KeyRoll):
         httl = self._get_highest_ttl(zone, api)
         self.current_step_datetime = datetime.now() + timedelta(seconds=httl)
 
-        api.bump_soa(zone);
+        api.bump_soa(zone)
 
     def _get_highest_ttl(self, zone, api, zoneobject=None):
         if zoneobject is None:
@@ -92,11 +93,14 @@ class PrePublishKeyRoll(KeyRoll):
         """
         validate_api(api)
         if not self.validate(zone, api):
-            raise Exception('Keys for zone {}  do not match keys initially found. Refusing to continue'.format(zone))
+            raise Exception("Keys for zone {}  do not match keys initially found. Refusing to continue".format(zone))
 
         if not self.started:
-            raise Exception('Can not go to the next step in phase "{}", did you mean to call initialize()?'.format(
-                self.current_step_name))
+            raise Exception(
+                'Can not go to the next step in phase "{}", did you mean to call initialize()?'.format(
+                    self.current_step_name
+                )
+            )
 
         # make sure we are passed the expected datetime
         if self.current_step_datetime > datetime.now():
@@ -109,8 +113,7 @@ class PrePublishKeyRoll(KeyRoll):
                 for keyid in self.old_keyids:
                     api.set_cryptokey_active(zone, keyid, active=False)
 
-                api.bump_soa(zone);
-
+                api.bump_soa(zone)
                 httl = self._get_highest_ttl(zone, api)
                 self.current_step_datetime = datetime.now() + timedelta(seconds=httl)
                 self.step_datetimes.append(datetime.now())
@@ -127,18 +130,17 @@ class PrePublishKeyRoll(KeyRoll):
                 # remove the old keys
                 for keyid in self.old_keyids:
                     api.delete_cryptokey(zone, keyid)
-                api.bump_soa(zone);
+                api.bump_soa(zone)
                 # rollover is finished
                 self.complete = True
                 self.step_datetimes.append(datetime.now())
 
-
         elif self.current_step == 3:
             if self.keytype == "ksk":
                 # remove the old keys
                 for keyid in self.old_keyids:
                     api.delete_cryptokey(zone, keyid)
-                api.bump_soa(zone);
+                api.bump_soa(zone)
                 # rollover is finished
                 self.complete = True
                 self.step_datetimes.append(datetime.now())
@@ -158,58 +160,70 @@ class PrePublishKeyRoll(KeyRoll):
         validate_api(api)
         to_match = self.old_keyids.copy()
         to_match.append(self.new_keyid)
-        return all([k.id in to_match for k in api.get_cryptokeys(zone)
-                    if k.algo == self.algo and k.keytype == self.keytype])
+        return all(
+            [k.id in to_match for k in api.get_cryptokeys(zone) if k.algo == self.algo and k.keytype == self.keytype]
+        )
 
     def __str__(self):
-        return json_tricks.dumps({
-            'rolltype': 'prepublish',
-            'current_step': self.current_step,
-            'complete': self.complete,
-            'current_step_datetime': self.current_step_datetime.timestamp(),
-            'step_datetimes': list(map(lambda d: d.timestamp(), self.step_datetimes)),
-            'keytype': self.keytype,
-            'algo': self.algo,
-            'old_keyids': self.old_keyids,
-            'new_keyid': self.new_keyid,
-        })
+        return json_tricks.dumps(
+            {
+                "rolltype": "prepublish",
+                "current_step": self.current_step,
+                "complete": self.complete,
+                "current_step_datetime": self.current_step_datetime.timestamp(),
+                "step_datetimes": list(map(lambda d: d.timestamp(), self.step_datetimes)),
+                "keytype": self.keytype,
+                "algo": self.algo,
+                "old_keyids": self.old_keyids,
+                "new_keyid": self.new_keyid,
+            }
+        )
+
     def __json_encode__(self):
         # should return primitive, serializable types like dict, list, int, string, float...
         return {
-            'rolltype': 'prepublish',
-            'current_step': self.current_step,
-            'complete': self.complete,
-            'current_step_datetime': self.current_step_datetime.timestamp(),
-            'step_datetimes': list(map(lambda d: d.timestamp(), self.step_datetimes)),
-            'keytype': self.keytype,
-            'algo': self.algo,
-            'old_keyids': self.old_keyids,
-            'new_keyid': self.new_keyid,
+            "rolltype": "prepublish",
+            "current_step": self.current_step,
+            "complete": self.complete,
+            "current_step_datetime": self.current_step_datetime.timestamp(),
+            "step_datetimes": list(map(lambda d: d.timestamp(), self.step_datetimes)),
+            "keytype": self.keytype,
+            "algo": self.algo,
+            "old_keyids": self.old_keyids,
+            "new_keyid": self.new_keyid,
         }
 
     def __json_decode__(self, **kwargs):
-        super().__init__(rolltype='prepublish')
-        self.current_step = kwargs.get('current_step', 0)
-        self.complete = kwargs.get('complete', False)
-        self.step_datetimes = list(map(lambda x: datetime.fromtimestamp(x), kwargs.get('step_datetimes', [])))
-        self.current_step_datetime = datetime.fromtimestamp(kwargs.get('current_step_datetime', datetime.now().timestamp()))
-        self.keytype = kwargs.get('keytype')
-        self.algo = kwargs.get('algo')
-        self.old_keyids = kwargs.get('old_keyids')
-        self.new_keyid = kwargs.get('new_keyid')
+        super().__init__(rolltype="prepublish")
+        self.current_step = kwargs.get("current_step", 0)
+        self.complete = kwargs.get("complete", False)
+        self.step_datetimes = list(map(lambda x: datetime.fromtimestamp(x), kwargs.get("step_datetimes", [])))
+        self.current_step_datetime = datetime.fromtimestamp(
+            kwargs.get("current_step_datetime", datetime.now().timestamp())
+        )
+        self.keytype = kwargs.get("keytype")
+        self.algo = kwargs.get("algo")
+        self.old_keyids = kwargs.get("old_keyids")
+        self.new_keyid = kwargs.get("new_keyid")
 
     def __repr__(self):
-        return 'PrePublishRoll({})'.format(
-            ', '.join(['{}={}'.format(k, v) for k, v in [
-                ('current_step', self.current_step),
-                ('complete', self.complete),
-                ('current_step_datetime', self.current_step_datetime.timestamp()),
-                ('step_datetimes', list(map(lambda d: d.timestamp(), self.step_datetimes))),
-                ('keytype', self.keytype),
-                ('algo', self.algo),
-                ('old_keyids', self.old_keyids),
-                ('new_keyid', self.new_keyid),
-            ]]))
+        return "PrePublishRoll({})".format(
+            ", ".join(
+                [
+                    "{}={}".format(k, v)
+                    for k, v in [
+                        ("current_step", self.current_step),
+                        ("complete", self.complete),
+                        ("current_step_datetime", self.current_step_datetime.timestamp()),
+                        ("step_datetimes", list(map(lambda d: d.timestamp(), self.step_datetimes))),
+                        ("keytype", self.keytype),
+                        ("algo", self.algo),
+                        ("old_keyids", self.old_keyids),
+                        ("new_keyid", self.new_keyid),
+                    ]
+                ]
+            )
+        )
 
     @property
     def started(self):
index 50bcd6667b2adf8edb2b0447584eec08dd86469d..427700b1e235718ca5d177ad656b17713780d1a7 100644 (file)
@@ -8,23 +8,24 @@ Helper functions for the keyrollers and the daemon
 """
 
 DNSKEY_ALGO_TO_MNEMONIC = {
-        1: "RSAMD5",
-        2: "DH",
-        3: "DSA",
-        5: "RSASHA1",
-        6: "DSA-NSEC3-SHA1",
-        7: "RSASHA1-NSEC3-SHA1",
-        8: "RSASHA256",
-        10: "RSASHA512",
-        12: "ECC-GOST",
-        13: "ECDSAP256",
-        14: "ECDSAP384",
-        15: "ED25519",
-        16: "ED448",
-    }
+    1: "RSAMD5",
+    2: "DH",
+    3: "DSA",
+    5: "RSASHA1",
+    6: "DSA-NSEC3-SHA1",
+    7: "RSASHA1-NSEC3-SHA1",
+    8: "RSASHA256",
+    10: "RSASHA512",
+    12: "ECC-GOST",
+    13: "ECDSAP256",
+    14: "ECDSAP384",
+    15: "ED25519",
+    16: "ED448",
+}
 
 DNSKEY_MNEMONIC_TO_ALGO = {v: k for k, v in DNSKEY_ALGO_TO_MNEMONIC.items()}
 
+
 def parse_algo(algo):
     res = 0
     try:
@@ -33,19 +34,20 @@ def parse_algo(algo):
         res = DNSKEY_MNEMONIC_TO_ALGO.get(algo.upper())
 
     if DNSKEY_ALGO_TO_MNEMONIC.get(res) is None:
-        raise Exception('Unknown key algorithm {}'.format(algo))
+        raise Exception("Unknown key algorithm {}".format(algo))
 
     return res
 
 
 def validate_api(api):
     if not isinstance(api, pdnsapi.api.PDNSApi):
-        raise Exception('api is not a PDNSApi')
+        raise Exception("api is not a PDNSApi")
+
 
 def validate_keytype(keytype):
     keytype = keytype.lower()
-    if keytype not in ('ksk', 'zsk', 'csk'):
-        raise Exception('{} is not a valid key type'.format(keytype))
+    if keytype not in ("ksk", "zsk", "csk"):
+        raise Exception("{} is not a valid key type".format(keytype))
 
 
 def get_keystyle(zone, api):
@@ -66,18 +68,18 @@ def get_keystyle(zone, api):
     cryptokeys = api.get_cryptokeys(zone)
 
     if not len(cryptokeys):
-        raise Exception('No cryptokeys for zone {}'.format(zone))
+        raise Exception("No cryptokeys for zone {}".format(zone))
 
-    got_ksk = any([cryptokey.keytype.lower() == 'ksk' for cryptokey in cryptokeys])
-    got_zsk = any([cryptokey.keytype.lower() == 'zsk' for cryptokey in cryptokeys])
-    got_csk = any([cryptokey.keytype.lower() == 'csk' for cryptokey in cryptokeys])
+    got_ksk = any([cryptokey.keytype.lower() == "ksk" for cryptokey in cryptokeys])
+    got_zsk = any([cryptokey.keytype.lower() == "zsk" for cryptokey in cryptokeys])
+    got_csk = any([cryptokey.keytype.lower() == "csk" for cryptokey in cryptokeys])
 
     if got_csk and not any([got_ksk, got_zsk]):
-        return 'single'
+        return "single"
     if all([got_ksk, got_zsk]) and not got_csk:
-        return 'split'
+        return "split"
     if all([got_ksk, got_zsk, got_csk]):
-        return 'mixed'
+        return "mixed"
 
 
 def get_keys_of_type(zone, api, keytype):
index 7d65b4b4f9028196af0c80ddcfe7871dbe33ec80..bd5c7843ca28e2640a3056081e072cacfe8c1442 100644 (file)
@@ -2,6 +2,7 @@ import os
 import pathlib
 from setuptools import setup, find_packages
 
+
 # reads requirements.txt file and extracts package_name and version (if set)
 def read_requirements_file(fname):
     reqs = []
@@ -10,8 +11,8 @@ def read_requirements_file(fname):
         for line in f:
             line = line.strip()
             # do not consider comments, hashes and remove trailing "\" if needed
-            if line and not line.startswith(('#', '-')):
-                reqs.append(line.rstrip('\\').strip())
+            if line and not line.startswith(("#", "-")):
+                reqs.append(line.rstrip("\\").strip())
 
     return reqs
 
@@ -25,29 +26,28 @@ def exists(fname):
 # README file and 2) it's easier to type in the README file than to put a raw
 # string in below ...
 def read(fname):
-    with open(os.path.join(os.path.dirname(__file__), fname),
-              'r', encoding='utf-8') as f:
+    with open(os.path.join(os.path.dirname(__file__), fname), "r", encoding="utf-8") as f:
         return f.read()
 
 
-version = os.environ.get('BUILDER_VERSION', '0.0.0')
+version = os.environ.get("BUILDER_VERSION", "0.0.0")
 
-if exists('version.txt'):
-    version = read('version.txt').strip()
+if exists("version.txt"):
+    version = read("version.txt").strip()
 
 setup(
-    name = "pdns-keyroller",
-    version = version,
-    author = "PowerDNS.COM BV",
-    author_email = "powerdns.support@powerdns.com",
-    description = ("PowerDNS keyroller"),
-    license = "GNU GPLv2",
-    keywords = "PowerDNS keyroller",
-    url = "https://www.powerdns.com/",
-    packages = find_packages(),
+    name="pdns-keyroller",
+    version=version,
+    author="PowerDNS.COM BV",
+    author_email="powerdns.support@powerdns.com",
+    description=("PowerDNS keyroller"),
+    license="GNU GPLv2",
+    keywords="PowerDNS keyroller",
+    url="https://www.powerdns.com/",
+    packages=find_packages(),
     install_requires=read_requirements_file("requirements.txt"),
-    include_package_data = True,
-    scripts=['pdns-keyroller.py', 'pdns-keyroller-ctl.py'],
-    long_description=read('README.md'),
+    include_package_data=True,
+    scripts=["pdns-keyroller.py", "pdns-keyroller-ctl.py"],
+    long_description=read("README.md"),
     classifiers=[],
 )
index 237ea32eb2a5831a2afaaf1c7755fdfd2d75ce74..a3a821160846afa9fa430a4334176a3bc50f4c96 100644 (file)
@@ -28,42 +28,48 @@ import guzzle_sphinx_theme
 #
 # needs_sphinx = '1.0'
 
-sys.path.append(str(Path('.').resolve()))
+sys.path.append(str(Path(".").resolve()))
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-#extensions = []
-#extensions = ['redjack.sphinx.lua', 'sphinxcontrib.httpdomain', 'sphinxjsondomain']
-extensions = ['redjack.sphinx.lua', 'sphinxcontrib.httpdomain', 'sphinxjsondomain',
-              'sphinxcontrib.fulltoc', 'changelog', 'depfile']
-primary_domain = 'lua'
+# extensions = []
+# extensions = ['redjack.sphinx.lua', 'sphinxcontrib.httpdomain', 'sphinxjsondomain']
+extensions = [
+    "redjack.sphinx.lua",
+    "sphinxcontrib.httpdomain",
+    "sphinxjsondomain",
+    "sphinxcontrib.fulltoc",
+    "changelog",
+    "depfile",
+]
+primary_domain = "lua"
 
 # Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
 
 # The suffix(es) of source filenames.
 # You can specify multiple suffix as a list of string:
 #
 # source_suffix = ['.rst', '.md']
-source_suffix = '.rst'
+source_suffix = ".rst"
 
 # The master toctree document.
-master_doc = 'indexTOC'
+master_doc = "indexTOC"
 
 # General information about the project.
-project = 'PowerDNS Recursor'
-copyright = 'PowerDNS.COM BV'
-author = 'PowerDNS.COM BV'
+project = "PowerDNS Recursor"
+copyright = "PowerDNS.COM BV"
+author = "PowerDNS.COM BV"
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-#version = '4.1'
+# version = '4.1'
 # The full version, including alpha/beta/rc tags.
-#release = '4.1.0-alpha1'
+# release = '4.1.0-alpha1'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -75,15 +81,20 @@ language = None
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This patterns also effect to html_static_path and html_extra_path
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.venv',
-                    'http-api/override.rst',
-                    'common/zonemetadata.rst',
-                    'common/endpoint-servers-config.rst',
-                    'common/secpoll.rst',
-                    'common/api/zone.rst']
+exclude_patterns = [
+    "_build",
+    "Thumbs.db",
+    ".DS_Store",
+    ".venv",
+    "http-api/override.rst",
+    "common/zonemetadata.rst",
+    "common/endpoint-servers-config.rst",
+    "common/secpoll.rst",
+    "common/api/zone.rst",
+]
 
 # The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = "sphinx"
 
 # If true, `todo` and `todoList` produce output, else they produce nothing.
 todo_include_todos = False
@@ -95,8 +106,8 @@ changelog_render_ticket = "https://github.com/PowerDNS/pdns/issues/%s"
 changelog_render_pullreq = "https://github.com/PowerDNS/pdns/pull/%s"
 changelog_render_changeset = "https://github.com/PowerDNS/pdns/commit/%s"
 
-changelog_sections = ['New Features', 'Improvements', 'Bug Fixes', 'Removals']
-changelog_inner_tag_sort = ['General', 'DNSSEC', 'Protobuf', 'RPZ']
+changelog_sections = ["New Features", "Improvements", "Bug Fixes", "Removals"]
+changelog_inner_tag_sort = ["General", "DNSSEC", "Protobuf", "RPZ"]
 
 changelog_hide_tags_in_entry = True
 
@@ -106,7 +117,7 @@ changelog_hide_tags_in_entry = True
 # a list of builtin themes.
 #
 html_theme_path = guzzle_sphinx_theme.html_theme_path()
-html_theme = 'guzzle_sphinx_theme'
+html_theme = "guzzle_sphinx_theme"
 
 extensions.append("guzzle_sphinx_theme")
 
@@ -114,7 +125,7 @@ html_theme_options = {
     # Set the name of the project to appear in the sidebar
     "project_nav_name": "PowerDNS Recursor",
 }
-html_favicon = 'common/favicon.ico'
+html_favicon = "common/favicon.ico"
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
@@ -125,15 +136,15 @@ html_favicon = 'common/favicon.ico'
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-html_style = 'pdns.css'
+html_static_path = ["_static"]
+html_style = "pdns.css"
 
-html_sidebars = { '**': ['logo-text.html', 'searchbox.html', 'relations.html', 'localtoc.html', 'sourcelink.html'] }
+html_sidebars = {"**": ["logo-text.html", "searchbox.html", "relations.html", "localtoc.html", "sourcelink.html"]}
 
 # -- Options for HTMLHelp output ------------------------------------------
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = 'PowerDNSRecursordoc'
+htmlhelp_basename = "PowerDNSRecursordoc"
 
 
 # -- Options for LaTeX output ---------------------------------------------
@@ -141,16 +152,13 @@ htmlhelp_basename = 'PowerDNSRecursordoc'
 latex_elements = {
     # The paper size ('letterpaper' or 'a4paper').
     #
-    'papersize': 'a4paper',
-
+    "papersize": "a4paper",
     # The font size ('10pt', '11pt' or '12pt').
     #
     # 'pointsize': '10pt',
-
     # Additional stuff for the LaTeX preamble.
     #
     # 'preamble': '',
-
     # Latex figure (float) alignment
     #
     # 'figure_align': 'htbp',
@@ -160,11 +168,10 @@ latex_elements = {
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
 latex_documents = [
-    (master_doc, 'PowerDNS-Recursor.tex', 'PowerDNS Recursor Documentation',
-     'PowerDNS.COM BV', 'manual'),
+    (master_doc, "PowerDNS-Recursor.tex", "PowerDNS Recursor Documentation", "PowerDNS.COM BV", "manual"),
 ]
 
-latex_logo = 'common/powerdns-logo-500px.png'
+latex_logo = "common/powerdns-logo-500px.png"
 
 
 # -- Options for manual page output ---------------------------------------
@@ -172,8 +179,8 @@ latex_logo = 'common/powerdns-logo-500px.png'
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    ('manpages/rec_control.1', 'rec_control', 'Command line tool to control a running Recursor', [author], 1),
-    ('manpages/pdns_recursor.1', 'pdns_recursor', 'The PowerDNS Recursor binary', [author], 1)
+    ("manpages/rec_control.1", "rec_control", "Command line tool to control a running Recursor", [author], 1),
+    ("manpages/pdns_recursor.1", "pdns_recursor", "The PowerDNS Recursor binary", [author], 1),
 ]
 
 
@@ -182,12 +189,11 @@ man_pages = [
 # Grouping the document tree into Texinfo files. List of tuples
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
-#texinfo_documents = [
+# texinfo_documents = [
 #    (master_doc, 'PowerDNSRecursor', 'PowerDNS Recursor Documentation',
 #     author, 'PowerDNSRecursor', 'One line description of project.',
 #     'Miscellaneous'),
-#]
-
+# ]
 
 
 # -- Options for Epub output ----------------------------------------------
@@ -208,7 +214,7 @@ epub_copyright = copyright
 # epub_uid = ''
 
 # A list of files that should not be packed into the epub file.
-epub_exclude_files = ['search.html']
+epub_exclude_files = ["search.html"]
 
-depfile = 'sphinx.d'
-depfile_stamp = 'sphinx.stamp'
+depfile = "sphinx.d"
+depfile_stamp = "sphinx.stamp"
index 492233a46cabf6589802278cdb7e88f38966e957..8c52095b2f30ca5c8cf8a7bc772aab2136bab00a 100755 (executable)
@@ -4,23 +4,25 @@ import os
 import shutil
 import os.path
 
-for extdir in ['yahttp', 'json11', 'probds']:
+for extdir in ["yahttp", "json11", "probds"]:
     try:
-        shutil.rmtree(os.path.join('ext', extdir))
+        shutil.rmtree(os.path.join("ext", extdir))
     except OSError:
         pass
 
     try:
-        os.rmdir(os.path.join('ext', extdir))
+        os.rmdir(os.path.join("ext", extdir))
     except OSError:
         pass
 
-    for root, dirs, files in os.walk(os.path.join('../../ext', extdir)):
-        stripped_root = root.replace('../', '')
+    for root, dirs, files in os.walk(os.path.join("../../ext", extdir)):
+        stripped_root = root.replace("../", "")
         os.mkdir(stripped_root)
-        num_dirs = len(root.split('/')) - root.split('/').count('..')
+        num_dirs = len(root.split("/")) - root.split("/").count("..")
         for dirfile in files:
-            if dirfile == '.gitignore':
-                shutil.copyfile(os.path.join(num_dirs * '../', stripped_root, dirfile), os.path.join(stripped_root, dirfile))
+            if dirfile == ".gitignore":
+                shutil.copyfile(
+                    os.path.join(num_dirs * "../", stripped_root, dirfile), os.path.join(stripped_root, dirfile)
+                )
             else:
-                os.symlink(os.path.join(num_dirs * '../', root, dirfile), os.path.join(stripped_root, dirfile))
+                os.symlink(os.path.join(num_dirs * "../", root, dirfile), os.path.join(stripped_root, dirfile))
index 63d004eccdee26678513f5d2c31db8f2cb1f9d3e..98fc8c8edb64521ea92e032597ba8378f5bde9da 100644 (file)
@@ -6,8 +6,8 @@ import metrics_table
 # default: 'type': uint64
 # ptype: "'counter' (vs gauge')
 
-srcdir = '.'
-builddir = '.'
+srcdir = "."
+builddir = "."
 if len(sys.argv) == 3:
     print("metrics.py: using srcdir and builddir from arguments")
     srcdir = sys.argv[1]
@@ -18,138 +18,140 @@ print("metrics.py cwd: " + os.getcwd())
 print("metrics.py srcdir: " + srcdir + " = " + os.path.realpath(srcdir))
 print("metrics.py builddir: " + builddir + " = " + os.path.realpath(builddir))
 
+
 def dedashForSNMP(name):
     cap = False
-    ret = ''
+    ret = ""
     for ch in name:
-        if ch == '-':
+        if ch == "-":
             cap = True
         elif cap:
             ret += ch.upper()
             cap = False
         else:
             ret += ch
-    ret = ret.replace('Nsec', 'NSEC')
+    ret = ret.replace("Nsec", "NSEC")
     return ret
 
+
 table = metrics_table.table
 
 #
 # We create various files in the srcdir but copy them into the builddir if needed to satisfy meson
 # FIXME: only generate in builddir once autotools have been dropped
 #
-with open(srcdir + '/rec-oids-gen.h', 'w', encoding='utf-8') as file:
-    file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n')
+with open(srcdir + "/rec-oids-gen.h", "w", encoding="utf-8") as file:
+    file.write("// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n")
     for entry in table:
-        if 'snmp' not in entry:
+        if "snmp" not in entry:
             continue
-        if 'ifdef' in entry:
-            ifdef = entry['ifdef']
-            file.write(f'#ifdef {ifdef}\n')
-        name = dedashForSNMP(entry['name'])
-        snmp = entry['snmp']
-        file.write(f'static const oid10 {name}OID = {{RECURSOR_STATS_OID, {snmp}}};\n')
-        if 'ifdef' in entry:
-            file.write(f'#endif\n')
+        if "ifdef" in entry:
+            ifdef = entry["ifdef"]
+            file.write(f"#ifdef {ifdef}\n")
+        name = dedashForSNMP(entry["name"])
+        snmp = entry["snmp"]
+        file.write(f"static const oid10 {name}OID = {{RECURSOR_STATS_OID, {snmp}}};\n")
+        if "ifdef" in entry:
+            file.write(f"#endif\n")
 if srcdir != builddir:
-    shutil.copy(srcdir + '/rec-oids-gen.h', builddir)
+    shutil.copy(srcdir + "/rec-oids-gen.h", builddir)
 
-with open(srcdir + '/rec-snmp-gen.h', 'w', encoding='utf-8') as file:
-    file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n')
+with open(srcdir + "/rec-snmp-gen.h", "w", encoding="utf-8") as file:
+    file.write("// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n")
     for entry in table:
-        if 'snmp' not in entry:
+        if "snmp" not in entry:
             continue
-        name = entry['name']
+        name = entry["name"]
         dname = dedashForSNMP(name)
-        if 'ifdef' in entry:
-            ifdef = entry['ifdef']
-            file.write(f'#ifdef {ifdef}\n')
+        if "ifdef" in entry:
+            ifdef = entry["ifdef"]
+            file.write(f"#ifdef {ifdef}\n")
         file.write(f'registerCounter64Stat("{name}", {dname}OID);\n')
-        if 'ifdef' in entry:
-            file.write(f'#endif\n')
+        if "ifdef" in entry:
+            file.write(f"#endif\n")
 if srcdir != builddir:
-    shutil.copy(srcdir + '/rec-snmp-gen.h', builddir)
+    shutil.copy(srcdir + "/rec-snmp-gen.h", builddir)
 
-with open(srcdir + '/rec-prometheus-gen.h', 'w', encoding='utf-8') as file:
-    file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n')
+with open(srcdir + "/rec-prometheus-gen.h", "w", encoding="utf-8") as file:
+    file.write("// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n")
     for entry in table:
-        name = entry['name']
-        if 'pname' in entry:
-            name = entry['pname']
-        desc = ''
-        desc = entry['desc']
-        if 'pdesc' in entry:
-            desc = entry['pdesc']
-            if desc == '':
+        name = entry["name"]
+        if "pname" in entry:
+            name = entry["pname"]
+        desc = ""
+        desc = entry["desc"]
+        if "pdesc" in entry:
+            desc = entry["pdesc"]
+            if desc == "":
                 continue
-        ptype = 'counter'
-        if 'ptype' in entry:
-          ptype = entry['ptype']
+        ptype = "counter"
+        if "ptype" in entry:
+            ptype = entry["ptype"]
         file.write(f'{{"{name}", MetricDefinition(PrometheusMetricType::{ptype}, "{desc}")}},\n')
 if srcdir != builddir:
-    shutil.copy(srcdir + '/rec-prometheus-gen.h', builddir)
+    shutil.copy(srcdir + "/rec-prometheus-gen.h", builddir)
 
-with open(srcdir + '/rec-metrics-gen.h', 'w', encoding='utf-8') as file:
-    file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n')
+with open(srcdir + "/rec-metrics-gen.h", "w", encoding="utf-8") as file:
+    file.write("// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n")
     for entry in table:
-        name = entry['name']
-        if 'lambda' not in entry:
+        name = entry["name"]
+        if "lambda" not in entry:
             continue
-        lam = entry['lambda']
-        if 'ifdef' in entry:
-            ifdef = entry['ifdef']
-            file.write(f'#ifdef {ifdef}\n')
-        if 'if' in entry:
-            iff = entry['if']
-            file.write(f'if ({iff}) {{\n')
+        lam = entry["lambda"]
+        if "ifdef" in entry:
+            ifdef = entry["ifdef"]
+            file.write(f"#ifdef {ifdef}\n")
+        if "if" in entry:
+            iff = entry["if"]
+            file.write(f"if ({iff}) {{\n")
         file.write(f'addGetStat("{name}", {lam});\n')
-        if 'if' in entry:
-            file.write(f'}}\n')
-        if 'ifdef' in entry:
-            file.write(f'#endif\n')
+        if "if" in entry:
+            file.write(f"}}\n")
+        if "ifdef" in entry:
+            file.write(f"#endif\n")
 if srcdir != builddir:
-    shutil.copy(srcdir + '/rec-metrics-gen.h', builddir)
+    shutil.copy(srcdir + "/rec-metrics-gen.h", builddir)
 
-if os.path.isdir(srcdir + '/docs'):
-    with open(srcdir + '/docs/rec-metrics-gen.rst', 'w', encoding='utf-8') as file:
-        file.write('.. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n')
-        sortedtable = sorted(table, key = lambda value: value['name'])
-        file.write('.. csv-table:: **Metrics**\n')
+if os.path.isdir(srcdir + "/docs"):
+    with open(srcdir + "/docs/rec-metrics-gen.rst", "w", encoding="utf-8") as file:
+        file.write(".. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n")
+        sortedtable = sorted(table, key=lambda value: value["name"])
+        file.write(".. csv-table:: **Metrics**\n")
         file.write('    :header: "rec_control name", "Description", "SNMP Object and OID"\n')
-        file.write('    :widths: 20, 50, 20\n\n')
+        file.write("    :widths: 20, 50, 20\n\n")
         for entry in sortedtable:
-            name = entry['name']
-            desc = entry['desc']
-            if not desc.endswith('.'):
-                desc += '.'
-            if 'longdesc' in entry:
-                desc = desc + ' ' + entry['longdesc'].strip()
-            if not desc.endswith('.'):
-                desc += '.'
+            name = entry["name"]
+            desc = entry["desc"]
+            if not desc.endswith("."):
+                desc += "."
+            if "longdesc" in entry:
+                desc = desc + " " + entry["longdesc"].strip()
+            if not desc.endswith("."):
+                desc += "."
             file.write(f'    "**{name}**", ')
             file.write(f'"{desc}"')
-            if 'snmp' in entry:
-                snmp = entry['snmp']
+            if "snmp" in entry:
+                snmp = entry["snmp"]
                 snmpname = dedashForSNMP(name)
-                if 'snmpname' in entry:
-                    name = entry['snmpname']
+                if "snmpname" in entry:
+                    name = entry["snmpname"]
                 file.write(f', "{snmpname} ({snmp})"')
             else:
-                file.write(',')
-            file.write('\n')
+                file.write(",")
+            file.write("\n")
 
-str1 = ''
+str1 = ""
 for entry in table:
-    if 'snmp' not in entry:
+    if "snmp" not in entry:
         continue
-    name = dedashForSNMP(entry['name'])
-    if 'snmpname' in entry:
-        name = entry['snmpname']
-    snmp = entry['snmp']
-    desc = entry['desc']
-    type = 'Counter64'
-    if 'ptype' in entry and entry['ptype'] == 'gauge':
-        type = 'CounterBasedGauge64'
+    name = dedashForSNMP(entry["name"])
+    if "snmpname" in entry:
+        name = entry["snmpname"]
+    snmp = entry["snmp"]
+    desc = entry["desc"]
+    type = "Counter64"
+    if "ptype" in entry and entry["ptype"] == "gauge":
+        type = "CounterBasedGauge64"
     str1 += f'''
 {name} OBJECT-TYPE
     SYNTAX {type}
@@ -160,21 +162,21 @@ for entry in table:
     ::= {{ stats {snmp} }}
 '''
 
-str2 = '        trapReason'
+str2 = "        trapReason"
 for entry in table:
-    if 'snmp' not in entry:
+    if "snmp" not in entry:
         continue
-    name = dedashForSNMP(entry['name'])
-    if 'snmpname' in entry:
-        name = entry['snmpname']
-    str2 += f',\n        {name}'
+    name = dedashForSNMP(entry["name"])
+    if "snmpname" in entry:
+        name = entry["snmpname"]
+    str2 += f",\n        {name}"
 
 
-with open(srcdir + '/RECURSOR-MIB.in', mode='r', encoding='utf-8') as file:
+with open(srcdir + "/RECURSOR-MIB.in", mode="r", encoding="utf-8") as file:
     text = file.read()
-    text = text.replace('REPL_OBJECTS1', str1)
-    text = text.replace('REPL_OBJECTS2', str2)
-    with open(srcdir + '/RECURSOR-MIB.txt', 'w', encoding='utf-8') as file2:
+    text = text.replace("REPL_OBJECTS1", str1)
+    text = text.replace("REPL_OBJECTS2", str2)
+    with open(srcdir + "/RECURSOR-MIB.txt", "w", encoding="utf-8") as file2:
         file2.write(text)
 if srcdir != builddir:
-    shutil.copy(srcdir + '/RECURSOR-MIB.txt', builddir) 
+    shutil.copy(srcdir + "/RECURSOR-MIB.txt", builddir)
index f7d23e5119940e472ea7a4719887368a20b5b5b3..f8c167839dbb2a903a1ee2c883d484fb44f9adee 100644 (file)
 
 table = [
     {
-        'name': 'questions',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::qcounter); }',
-        'desc':  'Number of questions',
-        'longdesc': 'Counts all end-user initiated queries with the RD bit set',
-        'snmp': 1,
+        "name": "questions",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::qcounter); }",
+        "desc": "Number of questions",
+        "longdesc": "Counts all end-user initiated queries with the RD bit set",
+        "snmp": 1,
     },
     {
-        'name': 'ipv6-questions',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::ipv6qcounter); }',
-        'desc': 'Number of IPv6 questions',
-        'longdesc': 'Counts all end-user initiated queries with the RD bit set, received over IPv6 UDP',
-        'snmp': 2,
+        "name": "ipv6-questions",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::ipv6qcounter); }",
+        "desc": "Number of IPv6 questions",
+        "longdesc": "Counts all end-user initiated queries with the RD bit set, received over IPv6 UDP",
+        "snmp": 2,
     },
     {
-        'name': 'tcp-questions',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::tcpqcounter); }',
-        'desc': 'Number of TCP questions',
-        'snmp': 3,
+        "name": "tcp-questions",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::tcpqcounter); }",
+        "desc": "Number of TCP questions",
+        "snmp": 3,
     },
     {
-        'name': 'cache-hits',
-        'lambda': '[]() { return g_recCache->getCacheHits(); }',
-        'desc': 'Number of cache hits',
-        'longdesc': 'This does *not* include hits that got answered from the packet-cache',
-        'snmp': 4,
+        "name": "cache-hits",
+        "lambda": "[]() { return g_recCache->getCacheHits(); }",
+        "desc": "Number of cache hits",
+        "longdesc": "This does *not* include hits that got answered from the packet-cache",
+        "snmp": 4,
     },
     {
-        'name': 'cache-misses',
-        'lambda': '[]() { return g_recCache->getCacheMisses(); }',
-        'desc': 'Number of cache misses',
-        'longdesc': 'This does *not* include hits that got answered from the packet-cache',
-        'snmp': 5,
+        "name": "cache-misses",
+        "lambda": "[]() { return g_recCache->getCacheMisses(); }",
+        "desc": "Number of cache misses",
+        "longdesc": "This does *not* include hits that got answered from the packet-cache",
+        "snmp": 5,
     },
     {
-        'name': 'cache-entries',
-        'lambda': 'doGetCacheSize',
-        'ptype': 'gauge',
-        'desc': 'Number of record cache entries',
-        'snmp': 6,
+        "name": "cache-entries",
+        "lambda": "doGetCacheSize",
+        "ptype": "gauge",
+        "desc": "Number of record cache entries",
+        "snmp": 6,
     },
     {
-        'name': 'max-cache-entries',
-        'lambda': '[]() { return g_maxCacheEntries.load(); }',
-        'desc': 'Currently configured maximum number of cache entries',
-        'ptype': 'gauge',
+        "name": "max-cache-entries",
+        "lambda": "[]() { return g_maxCacheEntries.load(); }",
+        "desc": "Currently configured maximum number of cache entries",
+        "ptype": "gauge",
         # No SNMP
     },
     {
-        'name': 'max-packetcache-entries',
-        'lambda': '[]() { return g_maxPacketCacheEntries.load(); }',
-        'desc': 'Currently configured maximum number of packet cache entries',
-        'ptype': 'gauge',
+        "name": "max-packetcache-entries",
+        "lambda": "[]() { return g_maxPacketCacheEntries.load(); }",
+        "desc": "Currently configured maximum number of packet cache entries",
+        "ptype": "gauge",
         # No SNMP
     },
     {
-        'name': 'cache-bytes',
-        'lambda': 'doGetCacheBytes',
-        'ptype': 'gauge',
-        'desc': 'Size of the cache in bytes',
-        'longdesc': '''Since version 5.3.0 this metric computes a rough estimate of the number of bytes allocated by the record cache. Older versions return a number that cannot be relied upon. Disabled by default, as computing this number is CPU intensive, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`.''',
-        'snmp': 7,
+        "name": "cache-bytes",
+        "lambda": "doGetCacheBytes",
+        "ptype": "gauge",
+        "desc": "Size of the cache in bytes",
+        "longdesc": """Since version 5.3.0 this metric computes a rough estimate of the number of bytes allocated by the record cache. Older versions return a number that cannot be relied upon. Disabled by default, as computing this number is CPU intensive, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`.""",
+        "snmp": 7,
     },
     {
-        'name': 'packetcache-hits',
-        'lambda': '[] { return g_packetCache ? g_packetCache->getHits() : 0; }',
-        'desc': 'Number of packetcache hits',
-        'snmp': 8,
+        "name": "packetcache-hits",
+        "lambda": "[] { return g_packetCache ? g_packetCache->getHits() : 0; }",
+        "desc": "Number of packetcache hits",
+        "snmp": 8,
     },
     {
-        'name': 'packetcache-misses',
-        'lambda': '[] { return g_packetCache ? g_packetCache->getMisses() : 0; }',
-        'desc': 'Number of packetcache misses',
-        'snmp': 9,
+        "name": "packetcache-misses",
+        "lambda": "[] { return g_packetCache ? g_packetCache->getMisses() : 0; }",
+        "desc": "Number of packetcache misses",
+        "snmp": 9,
     },
     {
-        'name': 'packetcache-entries',
-        'lambda': '[] { return g_packetCache ? g_packetCache->size() : 0; }',
-        'desc': 'Number of packetcache entries',
-        'ptype': 'gauge',
-        'snmp': 10,
+        "name": "packetcache-entries",
+        "lambda": "[] { return g_packetCache ? g_packetCache->size() : 0; }",
+        "desc": "Number of packetcache entries",
+        "ptype": "gauge",
+        "snmp": 10,
     },
     {
-        'name': 'packetcache-bytes',
-        'lambda': '[] { return g_packetCache ? g_packetCache->bytes() : 0; }',
-        'ptype': 'gauge',
-        'desc': 'Size of the packetcache in bytes',
-        'longdesc': '''Disabled by default, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`. This metric is currently broken, it always is 0.''',
-        'snmp': 11,
+        "name": "packetcache-bytes",
+        "lambda": "[] { return g_packetCache ? g_packetCache->bytes() : 0; }",
+        "ptype": "gauge",
+        "desc": "Size of the packetcache in bytes",
+        "longdesc": """Disabled by default, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`. This metric is currently broken, it always is 0.""",
+        "snmp": 11,
     },
     {
-        'name': 'malloc-bytes',
-        'lambda': 'doGetMallocated',
-        'ptype': 'gauge',
-        'desc': 'Number of bytes allocated by malloc',
-        'longdesc': 'Broken, always returns 0',
-        'snmp': 12,
+        "name": "malloc-bytes",
+        "lambda": "doGetMallocated",
+        "ptype": "gauge",
+        "desc": "Number of bytes allocated by malloc",
+        "longdesc": "Broken, always returns 0",
+        "snmp": 12,
     },
     {
-        'name': 'servfail-answers',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::servFails); }',
-        'desc': 'Number of servfail answers',
-        'snmp': 13,
+        "name": "servfail-answers",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::servFails); }",
+        "desc": "Number of servfail answers",
+        "snmp": 13,
     },
     {
-        'name': 'nxdomain-answers',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::nxDomains); }',
-        'desc': 'Number of nxdomain answers',
-        'snmp': 14,
+        "name": "nxdomain-answers",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::nxDomains); }",
+        "desc": "Number of nxdomain answers",
+        "snmp": 14,
     },
     {
-        'name': 'noerror-answers',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::noErrors); }',
-        'desc': 'Number of noerror answers',
-        'snmp': 15,
+        "name": "noerror-answers",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::noErrors); }",
+        "desc": "Number of noerror answers",
+        "snmp": 15,
     },
     {
-        'name': 'unauthorized-udp',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::unauthorizedUDP); }',
-        'desc': 'Number of unauthorized UDP queries',
-        'snmp': 16,
+        "name": "unauthorized-udp",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::unauthorizedUDP); }",
+        "desc": "Number of unauthorized UDP queries",
+        "snmp": 16,
     },
     {
-        'name': 'unauthorized-tcp',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::unauthorizedTCP); }',
-        'desc': 'Number of unauthorized TCP queries',
-        'snmp': 17,
+        "name": "unauthorized-tcp",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::unauthorizedTCP); }",
+        "desc": "Number of unauthorized TCP queries",
+        "snmp": 17,
     },
     {
-        'name': 'tcp-client-overflow',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::tcpClientOverflow); }',
-        'desc': 'Number of TCP client connections refused because of too many connections',
-        'snmp': 18,
+        "name": "tcp-client-overflow",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::tcpClientOverflow); }",
+        "desc": "Number of TCP client connections refused because of too many connections",
+        "snmp": 18,
     },
     {
-        'name': 'client-parse-errors',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::clientParseError); }',
-        'desc': 'Number of client parse errors',
-        'snmp': 19,
+        "name": "client-parse-errors",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::clientParseError); }",
+        "desc": "Number of client parse errors",
+        "snmp": 19,
     },
     {
-        'name': 'server-parse-errors',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::serverParseError); }',
-        'desc': 'Number of server parse errors',
-        'snmp': 20,
+        "name": "server-parse-errors",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::serverParseError); }",
+        "desc": "Number of server parse errors",
+        "snmp": 20,
     },
     {
-        'name': 'too-old-drops',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::tooOldDrops); }',
-        'desc': 'Number of queries dropped because of a timeout',
-        'snmp': 21,
+        "name": "too-old-drops",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::tooOldDrops); }",
+        "desc": "Number of queries dropped because of a timeout",
+        "snmp": 21,
     },
     {
-        'name': 'answers0-1',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::answers).getCount(0); }',
-        'desc': 'Number of queries answered in less than 1 ms',
-        'snmp': 22,
+        "name": "answers0-1",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::answers).getCount(0); }",
+        "desc": "Number of queries answered in less than 1 ms",
+        "snmp": 22,
     },
     {
-        'name': 'answers1-10',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::answers).getCount(1); }',
-        'desc': 'Number of queries answered in 1-10 ms',
-        'snmp': 23,
+        "name": "answers1-10",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::answers).getCount(1); }",
+        "desc": "Number of queries answered in 1-10 ms",
+        "snmp": 23,
     },
     {
-        'name': 'answers10-100',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::answers).getCount(2); }',
-        'desc': 'Number of queries answered in 10-100 ms',
-        'snmp': 24,
+        "name": "answers10-100",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::answers).getCount(2); }",
+        "desc": "Number of queries answered in 10-100 ms",
+        "snmp": 24,
     },
     {
-        'name': 'answers100-1000',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::answers).getCount(3); }',
-        'desc': 'Number of queries answered in 100-1000 ms',
-        'snmp': 25,
+        "name": "answers100-1000",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::answers).getCount(3); }",
+        "desc": "Number of queries answered in 100-1000 ms",
+        "snmp": 25,
     },
     {
-        'name': 'answers-slow',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::answers).getCount(4); }',
-        'desc': 'Number of queries answered in more than 1000 ms',
-        'snmp': 26,
+        "name": "answers-slow",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::answers).getCount(4); }",
+        "desc": "Number of queries answered in more than 1000 ms",
+        "snmp": 26,
     },
     {
-        'name': 'x-ourtime0-1',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(0); }',
-        'desc': 'Counts responses where between 0 and 1 milliseconds was spent within the Recursor',
-        'longdesc': 'Not yet proven to be reliable'
+        "name": "x-ourtime0-1",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(0); }",
+        "desc": "Counts responses where between 0 and 1 milliseconds was spent within the Recursor",
+        "longdesc": "Not yet proven to be reliable",
     },
     {
-        'name': 'x-ourtime1-2',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(1); }',
-        'desc': 'Counts responses where between 1 and 2 milliseconds was spent within the Recursor',
-        'longdesc': 'Not yet proven to be reliable'
+        "name": "x-ourtime1-2",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(1); }",
+        "desc": "Counts responses where between 1 and 2 milliseconds was spent within the Recursor",
+        "longdesc": "Not yet proven to be reliable",
     },
     {
-        'name': 'x-ourtime2-4',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(2); }',
-        'desc': 'Counts responses where between 16 and 32 milliseconds was spent within the Recursor',
-        'longdesc': 'Not yet proven to be reliable'
+        "name": "x-ourtime2-4",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(2); }",
+        "desc": "Counts responses where between 16 and 32 milliseconds was spent within the Recursor",
+        "longdesc": "Not yet proven to be reliable",
     },
     {
-        'name': 'x-ourtime4-8',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(3); }',
-        'desc': 'Counts responses where between 4 and 8 milliseconds was spent within the Recursor',
-        'longdesc': 'Not yet proven to be reliable'
+        "name": "x-ourtime4-8",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(3); }",
+        "desc": "Counts responses where between 4 and 8 milliseconds was spent within the Recursor",
+        "longdesc": "Not yet proven to be reliable",
     },
     {
-        'name': 'x-ourtime8-16',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(4); }',
-        'desc': 'Counts responses where between 8 and 16 milliseconds was spent within the Recursor',
-        'longdesc': 'Not yet proven to be reliable'
+        "name": "x-ourtime8-16",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(4); }",
+        "desc": "Counts responses where between 8 and 16 milliseconds was spent within the Recursor",
+        "longdesc": "Not yet proven to be reliable",
     },
     {
-        'name': 'x-ourtime16-32',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(5); }',
-        'desc': 'Counts responses where between 16 and 32 milliseconds was spent within the Recursor',
-        'longdesc': 'Not yet proven to be reliable'
+        "name": "x-ourtime16-32",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(5); }",
+        "desc": "Counts responses where between 16 and 32 milliseconds was spent within the Recursor",
+        "longdesc": "Not yet proven to be reliable",
     },
     {
-        'name': 'x-ourtime-slow',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(6); }',
-        'desc': 'Counts responses where more than 32 milliseconds was spent within the Recursor',
-        'longdesc': 'Not yet proven to be reliable'
+        "name": "x-ourtime-slow",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(6); }",
+        "desc": "Counts responses where more than 32 milliseconds was spent within the Recursor",
+        "longdesc": "Not yet proven to be reliable",
     },
     {
-        'name': 'auth4-answers0-1',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(0); }',
-        'desc': 'Number of IPv4 queries answered in less than 1 ms',
-        'snmp': 27,
+        "name": "auth4-answers0-1",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(0); }",
+        "desc": "Number of IPv4 queries answered in less than 1 ms",
+        "snmp": 27,
     },
     {
-        'name': 'auth4-answers1-10',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(1); }',
-        'desc': 'Number of IPv4 queries answered in 1-10 ms',
-        'snmp': 28,
+        "name": "auth4-answers1-10",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(1); }",
+        "desc": "Number of IPv4 queries answered in 1-10 ms",
+        "snmp": 28,
     },
     {
-        'name': 'auth4-answers10-100',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(2); }',
-        'desc': 'Number of IPv4 queries answered in 10-100 ms',
-        'snmp': 29,
+        "name": "auth4-answers10-100",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(2); }",
+        "desc": "Number of IPv4 queries answered in 10-100 ms",
+        "snmp": 29,
     },
     {
-        'name': 'auth4-answers100-1000',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(3); }',
-        'desc': 'Number of IPv4 queries answered in 100-1000 ms',
-        'snmp': 30,
+        "name": "auth4-answers100-1000",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(3); }",
+        "desc": "Number of IPv4 queries answered in 100-1000 ms",
+        "snmp": 30,
     },
     {
-        'name': 'auth4-answers-slow',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(4); }',
-        'desc': 'Number of IPv4 queries answered in more than 1000 ms',
-        'snmp': 31,
-        'snmpname': 'auth4Answersslow',
+        "name": "auth4-answers-slow",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(4); }",
+        "desc": "Number of IPv4 queries answered in more than 1000 ms",
+        "snmp": 31,
+        "snmpname": "auth4Answersslow",
     },
     {
-        'name': 'auth6-answers0-1',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(0); }',
-        'desc': 'Number of IPv6 queries answered in less than 1 ms',
-        'snmp': 32,
+        "name": "auth6-answers0-1",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(0); }",
+        "desc": "Number of IPv6 queries answered in less than 1 ms",
+        "snmp": 32,
     },
     {
-        'name': 'auth6-answers1-10',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(1); }',
-        'desc': 'Number of IPv6 queries answered in 1-10 ms',
-        'snmp': 33,
+        "name": "auth6-answers1-10",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(1); }",
+        "desc": "Number of IPv6 queries answered in 1-10 ms",
+        "snmp": 33,
     },
     {
-        'name': 'auth6-answers10-100',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(2); }',
-        'desc': 'Number of IPv6 queries answered in 10-100 ms',
-        'snmp': 34,
+        "name": "auth6-answers10-100",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(2); }",
+        "desc": "Number of IPv6 queries answered in 10-100 ms",
+        "snmp": 34,
     },
     {
-        'name': 'auth6-answers100-1000',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(3); }',
-        'desc': 'Number of IPv6 queries answered in 100-1000 ms',
-        'snmp': 35,
+        "name": "auth6-answers100-1000",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(3); }",
+        "desc": "Number of IPv6 queries answered in 100-1000 ms",
+        "snmp": 35,
     },
     {
-        'name': 'auth6-answers-slow',
-        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(4); }',
-        'desc': 'Number of IPv6 queries answered in more than 1000 ms',
-        'snmp': 36,
+        "name": "auth6-answers-slow",
+        "lambda": "[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(4); }",
+        "desc": "Number of IPv6 queries answered in more than 1000 ms",
+        "snmp": 36,
     },
     {
-        'name': 'qa-latency',
-        'lambda': '[]() { return round(g_Counters.avg(rec::DoubleWAvgCounter::avgLatencyUsec)); }',
-        'ptype': 'gauge',
-        'desc': 'Shows the current latency average, in microseconds, exponentially weighted over past \'latency-statistic-size\' packets',
-        'snmp': 37,
+        "name": "qa-latency",
+        "lambda": "[]() { return round(g_Counters.avg(rec::DoubleWAvgCounter::avgLatencyUsec)); }",
+        "ptype": "gauge",
+        "desc": "Shows the current latency average, in microseconds, exponentially weighted over past 'latency-statistic-size' packets",
+        "snmp": 37,
     },
     {
-        'name': 'x-our-latency',
-        'lambda': '[]() { return round(g_Counters.avg(rec::DoubleWAvgCounter::avgLatencyOursUsec)); }',
-        'ptype': 'gauge',
-        'desc': 'Shows the averaged time spent within PowerDNS, in microseconds, exponentially weighted over past \'latency-statistic-size\' packets',
+        "name": "x-our-latency",
+        "lambda": "[]() { return round(g_Counters.avg(rec::DoubleWAvgCounter::avgLatencyOursUsec)); }",
+        "ptype": "gauge",
+        "desc": "Shows the averaged time spent within PowerDNS, in microseconds, exponentially weighted over past 'latency-statistic-size' packets",
     },
     {
-        'name': 'unexpected-packets',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::unexpectedCount); }',
-        'desc': 'Number of unexpected packets',
-        'snmp': 38,
+        "name": "unexpected-packets",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::unexpectedCount); }",
+        "desc": "Number of unexpected packets",
+        "snmp": 38,
     },
     {
-        'name': 'case-mismatches',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::caseMismatchCount); }',
-        'desc': 'Number of case mismatches',
-        'snmp': 39,
+        "name": "case-mismatches",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::caseMismatchCount); }",
+        "desc": "Number of case mismatches",
+        "snmp": 39,
     },
     {
-        'name': 'spoof-prevents',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::spoofCount); }',
-        'desc': 'Number of spoof prevents',
-        'snmp': 40,
+        "name": "spoof-prevents",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::spoofCount); }",
+        "desc": "Number of spoof prevents",
+        "snmp": 40,
     },
     {
-        'name': 'nsset-invalidations',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::nsSetInvalidations); }',
-        'desc': 'Number of nsset invalidations',
-        'snmp': 41,
+        "name": "nsset-invalidations",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::nsSetInvalidations); }",
+        "desc": "Number of nsset invalidations",
+        "snmp": 41,
     },
     {
-        'name': 'resource-limits',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::resourceLimits); }',
-        'desc': 'Number of resolution aborted because of a local resource limit',
-        'snmp': 42,
+        "name": "resource-limits",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::resourceLimits); }",
+        "desc": "Number of resolution aborted because of a local resource limit",
+        "snmp": 42,
     },
     {
-        'name': 'over-capacity-drops',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::overCapacityDrops); }',
-        'desc': 'Number of queries dropped because the threads limit was reached',
-        'snmp': 43,
+        "name": "over-capacity-drops",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::overCapacityDrops); }",
+        "desc": "Number of queries dropped because the threads limit was reached",
+        "snmp": 43,
     },
     {
-        'name': 'policy-drops',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::policyDrops); }',
-        'desc': 'Number of queries dropped because of a policy',
-        'snmp': 44,
+        "name": "policy-drops",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::policyDrops); }",
+        "desc": "Number of queries dropped because of a policy",
+        "snmp": 44,
     },
     {
-        'name': 'no-packet-error',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::noPacketError); }',
-        'desc': 'Number of calls to recvmsg() that returned no packet even though the socket was ready',
-        'snmp': 45,
+        "name": "no-packet-error",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::noPacketError); }",
+        "desc": "Number of calls to recvmsg() that returned no packet even though the socket was ready",
+        "snmp": 45,
     },
     {
-        'name': 'dlg-only-drops',
-        'desc': 'Obsolete',
-        'snmp': 46,
+        "name": "dlg-only-drops",
+        "desc": "Obsolete",
+        "snmp": 46,
     },
     {
-        'name': 'ignored-packets',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::ignoredCount); }',
-        'desc': 'Number of ignored packets',
-        'snmp': 47,
+        "name": "ignored-packets",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::ignoredCount); }",
+        "desc": "Number of ignored packets",
+        "snmp": 47,
     },
     {
-        'name': 'max-mthread-stack',
-        'lambda': '[] { return g_Counters.max(rec::Counter::maxMThreadStackUsage); }',
-        'ptype': 'counter',
-        'desc': 'Maximum amount of the mthread stack ever used',
-        'snmp': 48,
+        "name": "max-mthread-stack",
+        "lambda": "[] { return g_Counters.max(rec::Counter::maxMThreadStackUsage); }",
+        "ptype": "counter",
+        "desc": "Maximum amount of the mthread stack ever used",
+        "snmp": 48,
     },
     {
-        'name': 'negcache-entries',
-        'lambda': 'getNegCacheSize',
-        'ptype': 'gauge',
-        'snmp': 49,
-        'desc': 'Number of negcache entries',
+        "name": "negcache-entries",
+        "lambda": "getNegCacheSize",
+        "ptype": "gauge",
+        "snmp": 49,
+        "desc": "Number of negcache entries",
     },
     {
-        'name': 'throttle-entries',
-        'lambda': 'SyncRes::getThrottledServersSize',
-        'ptype': 'gauge',
-        'snmp': 50,
-        'desc': 'Number of throttle entries',
+        "name": "throttle-entries",
+        "lambda": "SyncRes::getThrottledServersSize",
+        "ptype": "gauge",
+        "snmp": 50,
+        "desc": "Number of throttle entries",
     },
     {
-        'name': 'nsspeeds-entries',
-        'lambda': 'SyncRes::getNSSpeedsSize',
-        'ptype': 'gauge',
-        'snmp': 51,
-        'desc': 'Number of nsspeeds entries',
+        "name": "nsspeeds-entries",
+        "lambda": "SyncRes::getNSSpeedsSize",
+        "ptype": "gauge",
+        "snmp": 51,
+        "desc": "Number of nsspeeds entries",
     },
     {
-        'name': 'failed-host-entries',
-        'lambda': 'SyncRes::getFailedServersSize',
-        'ptype': 'gauge',
-        'snmp': 52,
-        'desc': 'Number of entries in the failed NS cache',
+        "name": "failed-host-entries",
+        "lambda": "SyncRes::getFailedServersSize",
+        "ptype": "gauge",
+        "snmp": 52,
+        "desc": "Number of entries in the failed NS cache",
     },
     {
-        'name': 'concurrent-queries',
-        'lambda': 'getConcurrentQueries',
-        'ptype': 'gauge',
-        'snmp': 53,
-        'desc': 'Number of concurrent queries',
+        "name": "concurrent-queries",
+        "lambda": "getConcurrentQueries",
+        "ptype": "gauge",
+        "snmp": 53,
+        "desc": "Number of concurrent queries",
     },
     {
-        'name': 'security-status',
-        'lambda': '&g_security_status',
-        'ptype': 'gauge',
-        'snmp': 54,
-        'desc': 'Current security status',
+        "name": "security-status",
+        "lambda": "&g_security_status",
+        "ptype": "gauge",
+        "snmp": 54,
+        "desc": "Current security status",
     },
     {
-        'name': 'outgoing-timeouts',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::outgoingtimeouts); }',
-        'snmp': 55,
-        'desc': 'Number of outgoing timeouts',
+        "name": "outgoing-timeouts",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::outgoingtimeouts); }",
+        "snmp": 55,
+        "desc": "Number of outgoing timeouts",
     },
     {
-        'name': 'outgoing4-timeouts',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::outgoing4timeouts); }',
-        'snmp': 56,
-        'desc': 'Number of IPv4 outgoing timeouts',
+        "name": "outgoing4-timeouts",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::outgoing4timeouts); }",
+        "snmp": 56,
+        "desc": "Number of IPv4 outgoing timeouts",
     },
     {
-        'name': 'outgoing6-timeouts',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::outgoing6timeouts); }',
-        'snmp': 57,
-        'desc': 'Number of IPv6 outgoing timeouts',
+        "name": "outgoing6-timeouts",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::outgoing6timeouts); }",
+        "snmp": 57,
+        "desc": "Number of IPv6 outgoing timeouts",
     },
     {
-        'name': 'auth-zone-queries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::authzonequeries); }',
-        'desc': 'Number of queries to locally hosted authoritative zones (\'setting-auth-zones\')',
+        "name": "auth-zone-queries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::authzonequeries); }",
+        "desc": "Number of queries to locally hosted authoritative zones ('setting-auth-zones')",
     },
     {
-        'name': 'tcp-outqueries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::tcpoutqueries); }',
-        'snmp': 58,
-        'desc': 'Number of outgoing TCP queries sent',
+        "name": "tcp-outqueries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::tcpoutqueries); }",
+        "snmp": 58,
+        "desc": "Number of outgoing TCP queries sent",
     },
     {
-        'name': 'all-outqueries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::outqueries); }',
-        'snmp': 59,
-        'desc': 'Number of outgoing queries',
+        "name": "all-outqueries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::outqueries); }",
+        "snmp": 59,
+        "desc": "Number of outgoing queries",
     },
     {
-        'name': 'ipv6-outqueries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::ipv6queries); }',
-        'snmp': 60,
-        'desc': 'Number of IPv6 outgoing queries sent',
+        "name": "ipv6-outqueries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::ipv6queries); }",
+        "snmp": 60,
+        "desc": "Number of IPv6 outgoing queries sent",
     },
     {
-        'name': 'throttled-outqueries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::throttledqueries); }',
-        'snmp': 61,
-        'desc': 'Number of throttled outgoing queries',
+        "name": "throttled-outqueries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::throttledqueries); }",
+        "snmp": 61,
+        "desc": "Number of throttled outgoing queries",
     },
     {
-        'name': 'dont-outqueries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::dontqueries); }',
-        'snmp': 62,
-        'desc': 'Number of outgoing queries not sent because of a \'dont-query\' setting',
+        "name": "dont-outqueries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::dontqueries); }",
+        "snmp": 62,
+        "desc": "Number of outgoing queries not sent because of a 'dont-query' setting",
     },
     {
-        'name': 'throttled-out',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::throttledqueries); }',
-        'desc': 'Number of throttled outgoing queries',
+        "name": "throttled-out",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::throttledqueries); }",
+        "desc": "Number of throttled outgoing queries",
     },
     {
-        'name': 'unreachables',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::unreachables); }',
-        'snmp': 63,
-        'desc': 'Number of errors due to an unreachable server',
+        "name": "unreachables",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::unreachables); }",
+        "snmp": 63,
+        "desc": "Number of errors due to an unreachable server",
     },
     {
-        'name': 'ecs-queries',
-        'lambda': '&SyncRes::s_ecsqueries',
-        'desc': 'Number of outgoing queries adorned with an EDNS Client Subnet option',
+        "name": "ecs-queries",
+        "lambda": "&SyncRes::s_ecsqueries",
+        "desc": "Number of outgoing queries adorned with an EDNS Client Subnet option",
     },
     {
-        'name': 'ecs-responses',
-        'lambda': '&SyncRes::s_ecsresponses',
-        'desc': 'Number of responses received from authoritative servers with an EDNS Client Subnet option we used',
+        "name": "ecs-responses",
+        "lambda": "&SyncRes::s_ecsresponses",
+        "desc": "Number of responses received from authoritative servers with an EDNS Client Subnet option we used",
     },
     {
-        'name': 'chain-resends',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::chainResends); }',
-        'snmp': 64,
-        'desc': 'Number of chain resends',
+        "name": "chain-resends",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::chainResends); }",
+        "snmp": 64,
+        "desc": "Number of chain resends",
     },
     {
-        'name': 'tcp-clients',
-        'lambda': '[] { return TCPConnection::getCurrentConnections(); }',
-        'ptype': 'gauge',
-        'snmp': 65,
-        'desc': 'Number of TCP clients',
+        "name": "tcp-clients",
+        "lambda": "[] { return TCPConnection::getCurrentConnections(); }",
+        "ptype": "gauge",
+        "snmp": 65,
+        "desc": "Number of TCP clients",
     },
     {
-        'name': 'udp-recvbuf-errors',
-        'lambda': '[] { return udpErrorStats("udp-recvbuf-errors"); }',
-        'ifdef': '__linux',
-        'snmp': 66,
-        'desc': 'Number of UDP recvbuf errors (Linux only)',
+        "name": "udp-recvbuf-errors",
+        "lambda": '[] { return udpErrorStats("udp-recvbuf-errors"); }',
+        "ifdef": "__linux",
+        "snmp": 66,
+        "desc": "Number of UDP recvbuf errors (Linux only)",
     },
     {
-        'name': 'udp-sndbuf-errors',
-        'lambda': '[] { return udpErrorStats("udp-sndbuf-errors"); }',
-        'snmp': 67,
-        'ifdef': '__linux',
-        'desc': 'Number of UDP sndbuf errors (Linux only)',
+        "name": "udp-sndbuf-errors",
+        "lambda": '[] { return udpErrorStats("udp-sndbuf-errors"); }',
+        "snmp": 67,
+        "ifdef": "__linux",
+        "desc": "Number of UDP sndbuf errors (Linux only)",
     },
     {
-        'name': 'udp-noport-errors',
-        'lambda': '[] { return udpErrorStats("udp-noport-errors"); }',
-        'ifdef': '__linux',
-        'snmp': 68,
-        'desc': 'Number of UDP noport errors (Linux only)',
+        "name": "udp-noport-errors",
+        "lambda": '[] { return udpErrorStats("udp-noport-errors"); }',
+        "ifdef": "__linux",
+        "snmp": 68,
+        "desc": "Number of UDP noport errors (Linux only)",
     },
     {
-        'name': 'udp-in-errors',
-        'lambda': '[] { return udpErrorStats("udp-in-errors"); }',
-        'ifdef': '__linux',
-        'snmp': 69,
-        'snmpname': 'udpinErrors',
-        'desc': 'Number of UDP in errors (Linux only)',
+        "name": "udp-in-errors",
+        "lambda": '[] { return udpErrorStats("udp-in-errors"); }',
+        "ifdef": "__linux",
+        "snmp": 69,
+        "snmpname": "udpinErrors",
+        "desc": "Number of UDP in errors (Linux only)",
     },
     {
-        'name': 'edns-ping-matches',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::ednsPingMatches); }',
-        'snmp': 70,
-        'desc': 'Number of EDNS Ping matches',
+        "name": "edns-ping-matches",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::ednsPingMatches); }",
+        "snmp": 70,
+        "desc": "Number of EDNS Ping matches",
     },
     {
-        'name': 'edns-ping-mismatches',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::ednsPingMismatches); }',
-        'snmp': 71,
-        'desc': 'Number of EDNS Ping mismatches',
+        "name": "edns-ping-mismatches",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::ednsPingMismatches); }",
+        "snmp": 71,
+        "desc": "Number of EDNS Ping mismatches",
     },
     {
-        'name': 'dnssec-queries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::dnssecQueries); }',
-        'snmp': 72,
-        'desc': 'Number of DNSSEC queries',
+        "name": "dnssec-queries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::dnssecQueries); }",
+        "snmp": 72,
+        "desc": "Number of DNSSEC queries",
     },
     {
-        'name': 'noping-outqueries', # XXX obsolete?
-        'lambda': '[] { return g_Counters.sum(rec::Counter::noPingOutQueries); }',
-        'snmp': 73,
-        'desc': 'Number of outgoing queries without ping',
+        "name": "noping-outqueries",  # XXX obsolete?
+        "lambda": "[] { return g_Counters.sum(rec::Counter::noPingOutQueries); }",
+        "snmp": 73,
+        "desc": "Number of outgoing queries without ping",
     },
     {
-        'name': 'noedns-outqueries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::noEdnsOutQueries); }',
-        'snmp': 74,
-        'desc': 'Number of outgoing queries without EDNS',
+        "name": "noedns-outqueries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::noEdnsOutQueries); }",
+        "snmp": 74,
+        "desc": "Number of outgoing queries without EDNS",
     },
     {
-        'name': 'uptime',
-        'lambda': '[] { return time(nullptr) - s_startupTime; }',
-        'snmp': 75,
-        'desc': 'Process uptime in seconds',
+        "name": "uptime",
+        "lambda": "[] { return time(nullptr) - s_startupTime; }",
+        "snmp": 75,
+        "desc": "Process uptime in seconds",
     },
     {
-        'name': 'real-memory-usage',
-        'lambda': '[] { return getRealMemoryUsage(string()); }',
-        'ptype': 'gauge',
-        'snmp': 76,
-        'desc': 'Memory usage',
+        "name": "real-memory-usage",
+        "lambda": "[] { return getRealMemoryUsage(string()); }",
+        "ptype": "gauge",
+        "snmp": 76,
+        "desc": "Memory usage",
     },
     {
-        'name': 'fd-usage',
-        'lambda': '[] { return getOpenFileDescriptors(string()); }',
-        'ptype': 'gauge',
-        'snmp': 77,
-        'desc': 'File descriptors usage',
+        "name": "fd-usage",
+        "lambda": "[] { return getOpenFileDescriptors(string()); }",
+        "ptype": "gauge",
+        "snmp": 77,
+        "desc": "File descriptors usage",
     },
-
     {
-        'name': 'user-msec',
-        'lambda': 'getUserTimeMsec',
-        'ptype': 'counter',
-        'snmp': 78,
-        'desc': 'CPU usage (user) in ms',
+        "name": "user-msec",
+        "lambda": "getUserTimeMsec",
+        "ptype": "counter",
+        "snmp": 78,
+        "desc": "CPU usage (user) in ms",
     },
     {
-        'name': 'sys-msec',
-        'lambda': 'getSysTimeMsec',
-        'ptype': 'counter',
-        'snmp': 79,
-        'desc': 'CPU usage (system) in ms',
+        "name": "sys-msec",
+        "lambda": "getSysTimeMsec",
+        "ptype": "counter",
+        "snmp": 79,
+        "desc": "CPU usage (system) in ms",
     },
     {
-        'name': 'dnssec-validations',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::dnssecValidations); }',
-        'snmp': 80,
-        'desc': 'Number of responses sent, packet-cache hits excluded, for which a DNSSEC validation was requested by either the client or the configuration',
+        "name": "dnssec-validations",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::dnssecValidations); }",
+        "snmp": 80,
+        "desc": "Number of responses sent, packet-cache hits excluded, for which a DNSSEC validation was requested by either the client or the configuration",
     },
     {
-        'name': 'dnssec-result-insecure',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Insecure); }',
-        'snmp': 81,
-        'desc': 'Number of responses sent, excluding packet-cache hits, that were in the DNSSEC insecure state',
+        "name": "dnssec-result-insecure",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Insecure); }",
+        "snmp": 81,
+        "desc": "Number of responses sent, excluding packet-cache hits, that were in the DNSSEC insecure state",
     },
     {
-        'name': 'dnssec-result-secure',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Secure); }',
-        'snmp': 82,
-        'desc': 'Number of responses sent, excluding packet-cache hits, that were in the DNSSEC secure state',
+        "name": "dnssec-result-secure",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Secure); }",
+        "snmp": 82,
+        "desc": "Number of responses sent, excluding packet-cache hits, that were in the DNSSEC secure state",
     },
     {
-        'name': 'dnssec-result-bogus',
-        'lambda': '''[]() {
+        "name": "dnssec-result-bogus",
+        "lambda": """[]() {
             std::set<vState> const bogusStates = {vState::BogusNoValidDNSKEY, vState::BogusInvalidDenial, vState::BogusUnableToGetDSs, vState::BogusUnableToGetDNSKEYs, vState::BogusSelfSignedDS, vState::BogusNoRRSIG, vState::BogusNoValidRRSIG, vState::BogusMissingNegativeIndication, vState::BogusSignatureNotYetValid, vState::BogusSignatureExpired, vState::BogusUnsupportedDNSKEYAlgo, vState::BogusUnsupportedDSDigestType, vState::BogusNoZoneKeyBitSet, vState::BogusRevokedDNSKEY, vState::BogusInvalidDNSKEYProtocol};
             auto counts = g_Counters.sum(rec::DNSSECHistogram::dnssec);
             uint64_t total = 0;
@@ -640,377 +639,377 @@ table = [
               total += counts.at(state);
             }
             return total;
-          }''',
-        'snmp': 83,
-        'desc': 'Number of responses sent, excluding packet-cache hits, that were in the DNSSEC bogus state',
+          }""",
+        "snmp": 83,
+        "desc": "Number of responses sent, excluding packet-cache hits, that were in the DNSSEC bogus state",
     },
     {
-        'name': 'dnssec-result-indeterminate',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Indeterminate); }',
-        'snmp': 84,
-        'desc': 'Number of responses sent, excluding packet-cache hits, that were in the DNSSEC indeterminate state',
+        "name": "dnssec-result-indeterminate",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Indeterminate); }",
+        "snmp": 84,
+        "desc": "Number of responses sent, excluding packet-cache hits, that were in the DNSSEC indeterminate state",
     },
     {
-        'name': 'dnssec-result-nta',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::NTA); }',
-        'snmp': 85,
-        'desc': 'Number of responses sent, excluding packet-cache hits, that were in the DNSSEC NTA state',
+        "name": "dnssec-result-nta",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::NTA); }",
+        "snmp": 85,
+        "desc": "Number of responses sent, excluding packet-cache hits, that were in the DNSSEC NTA state",
     },
     {
-        'name': 'policy-result-noaction',
-        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NoAction); }',
-        'snmp': 86,
-        'desc': 'Number of policy-mandated no-action results',
+        "name": "policy-result-noaction",
+        "lambda": "[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NoAction); }",
+        "snmp": 86,
+        "desc": "Number of policy-mandated no-action results",
     },
     {
-        'name': 'policy-result-drop',
-        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Drop); }',
-        'snmp': 87,
-        'desc': 'Number of policy-mandated drops',
+        "name": "policy-result-drop",
+        "lambda": "[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Drop); }",
+        "snmp": 87,
+        "desc": "Number of policy-mandated drops",
     },
     {
-        'name': 'policy-result-nxdomain',
-        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NXDOMAIN); }',
-        'snmp': 88,
-        'desc': 'Number of policy-mandated NXdomain results',
+        "name": "policy-result-nxdomain",
+        "lambda": "[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NXDOMAIN); }",
+        "snmp": 88,
+        "desc": "Number of policy-mandated NXdomain results",
     },
     {
-        'name': 'policy-result-nodata',
-        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NODATA); }',
-        'snmp': 89,
-        'desc': 'Number of policy-mandated nodata results',
+        "name": "policy-result-nodata",
+        "lambda": "[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NODATA); }",
+        "snmp": 89,
+        "desc": "Number of policy-mandated nodata results",
     },
     {
-        'name': 'policy-result-truncate',
-        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Truncate); }',
-        'snmp': 90,
-        'desc': 'Number of policy-mandated truncate results',
+        "name": "policy-result-truncate",
+        "lambda": "[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Truncate); }",
+        "snmp": 90,
+        "desc": "Number of policy-mandated truncate results",
     },
     {
-        'name': 'policy-result-custom',
-        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Custom); }',
-        'snmp': 91,
-        'desc': 'Number of policy-mandated custom results',
+        "name": "policy-result-custom",
+        "lambda": "[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Custom); }",
+        "snmp": 91,
+        "desc": "Number of policy-mandated custom results",
     },
     {
-        'name': 'query-pipe-full-drops',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::queryPipeFullDrops); }',
-        'desc': 'Number of queries dropped because the query distribution pipe was full',
-        'snmp': 92,
+        "name": "query-pipe-full-drops",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::queryPipeFullDrops); }",
+        "desc": "Number of queries dropped because the query distribution pipe was full",
+        "snmp": 92,
     },
     {
-        'name': 'truncated-drops',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::truncatedDrops); }',
-        'desc': 'Number of queries dropped because they were larger than 512 bytes',
-        'snmp': 93,
+        "name": "truncated-drops",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::truncatedDrops); }",
+        "desc": "Number of queries dropped because they were larger than 512 bytes",
+        "snmp": 93,
     },
     {
-        'name': 'empty-queries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::emptyQueriesCount); }',
-        'desc': 'Number of queries dropped because they had a QD count of 0',
-        'snmp': 94,
+        "name": "empty-queries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::emptyQueriesCount); }",
+        "desc": "Number of queries dropped because they had a QD count of 0",
+        "snmp": 94,
     },
     {
-        'name': 'dnssec-authentic-data-queries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::dnssecAuthenticDataQueries); }',
-        'snmp': 95,
-        'desc': 'Number of queries received with the AD bit set',
+        "name": "dnssec-authentic-data-queries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::dnssecAuthenticDataQueries); }",
+        "snmp": 95,
+        "desc": "Number of queries received with the AD bit set",
     },
     {
-        'name': 'dnssec-check-disabled-queries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::dnssecCheckDisabledQueries); }',
-        'snmp': 96,
-        'desc': 'Number of queries received with the CD bit set',
+        "name": "dnssec-check-disabled-queries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::dnssecCheckDisabledQueries); }",
+        "snmp": 96,
+        "desc": "Number of queries received with the CD bit set",
     },
     {
-        'name': 'variable-responses',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::variableResponses); }',
-        'snmp': 97,
-        'desc': 'Number of variable responses',
+        "name": "variable-responses",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::variableResponses); }",
+        "snmp": 97,
+        "desc": "Number of variable responses",
     },
     {
-        'name': 'special-memory-usage',
-        'lambda': '[] { return getSpecialMemoryUsage(string()); }',
-        'ptype': 'gauge',
-        'snmp': 98,
-        'desc': 'Memory usage (more precise but expensive to retrieve)',
+        "name": "special-memory-usage",
+        "lambda": "[] { return getSpecialMemoryUsage(string()); }",
+        "ptype": "gauge",
+        "snmp": 98,
+        "desc": "Memory usage (more precise but expensive to retrieve)",
     },
     {
-        'name': 'rebalanced-queries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::rebalancedQueries); }',
-        'snmp': 99,
-        'desc': 'Number of queries re-distributed because the first selected worker thread was above the target load',
+        "name": "rebalanced-queries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::rebalancedQueries); }",
+        "snmp": 99,
+        "desc": "Number of queries re-distributed because the first selected worker thread was above the target load",
     },
     {
-        'name': 'qname-min-fallback-success',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::qnameminfallbacksuccess); }',
-        'snmp': 100,
-        'desc': 'Number of successful queries due to fallback mechanism within \'qname-minimization\' setting',
+        "name": "qname-min-fallback-success",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::qnameminfallbacksuccess); }",
+        "snmp": 100,
+        "desc": "Number of successful queries due to fallback mechanism within 'qname-minimization' setting",
     },
     {
-        'name': 'proxy-protocol-invalid',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::proxyProtocolInvalidCount); }',
-        'snmp': 101,
-        'desc': 'Number of invalid proxy protocol headers received',
+        "name": "proxy-protocol-invalid",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::proxyProtocolInvalidCount); }",
+        "snmp": 101,
+        "desc": "Number of invalid proxy protocol headers received",
     },
     {
-        'name': 'record-cache-contended',
-        'lambda': '[]() { return g_recCache->stats().first; }',
-        'desc': 'Number of contended record cache lock acquisitions',
-        'snmp': 102,
+        "name": "record-cache-contended",
+        "lambda": "[]() { return g_recCache->stats().first; }",
+        "desc": "Number of contended record cache lock acquisitions",
+        "snmp": 102,
     },
     {
-        'name': 'record-cache-acquired',
-        'lambda': '[]() { return g_recCache->stats().second; }',
-        'desc': 'Number of record cache lock acquisitions',
-        'snmp': 103,
+        "name": "record-cache-acquired",
+        "lambda": "[]() { return g_recCache->stats().second; }",
+        "desc": "Number of record cache lock acquisitions",
+        "snmp": 103,
     },
     {
-        'name': 'nod-lookups-dropped-oversize',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::nodLookupsDroppedOversize); }',
-        'snmp': 104,
-        'desc': 'Number of NOD lookups dropped because they would exceed the maximum name length',
+        "name": "nod-lookups-dropped-oversize",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::nodLookupsDroppedOversize); }",
+        "snmp": 104,
+        "desc": "Number of NOD lookups dropped because they would exceed the maximum name length",
     },
     {
-        'name': 'taskqueue-pushed',
-        'lambda': '[]() { return getTaskPushes(); }',
-        'snmp': 105,
-        'snmpname': 'taskQueuePushed',
-        'desc': 'Number of tasks pushed to the taskqueues',
+        "name": "taskqueue-pushed",
+        "lambda": "[]() { return getTaskPushes(); }",
+        "snmp": 105,
+        "snmpname": "taskQueuePushed",
+        "desc": "Number of tasks pushed to the taskqueues",
     },
     {
-        'name': 'taskqueue-expired',
-        'lambda': '[]() { return getTaskExpired(); }',
-        'snmp': 106,
-        'snmpname': 'taskQueueExpired',
-        'desc': 'Number of tasks expired before they could be run',
+        "name": "taskqueue-expired",
+        "lambda": "[]() { return getTaskExpired(); }",
+        "snmp": 106,
+        "snmpname": "taskQueueExpired",
+        "desc": "Number of tasks expired before they could be run",
     },
     {
-        'name': 'taskqueue-size',
-        'lambda': '[]() { return getTaskSize(); }',
-        'ptype': 'gauge',
-        'snmp': 107,
-        'snmpname': 'taskQueueSize',
-        'desc': 'Number of tasks currently in the taskqueues',
+        "name": "taskqueue-size",
+        "lambda": "[]() { return getTaskSize(); }",
+        "ptype": "gauge",
+        "snmp": 107,
+        "snmpname": "taskQueueSize",
+        "desc": "Number of tasks currently in the taskqueues",
     },
     {
-        'name': 'aggressive-nsec-cache-entries',
-        'lambda': '[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getEntriesCount() : 0; }',
-        'desc': 'Number of entries in the aggressive NSEC cache',
-        'snmp': 108,
+        "name": "aggressive-nsec-cache-entries",
+        "lambda": "[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getEntriesCount() : 0; }",
+        "desc": "Number of entries in the aggressive NSEC cache",
+        "snmp": 108,
     },
     {
-        'name': 'aggressive-nsec-cache-nsec-hits',
-        'lambda': '[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSECHits() : 0; }',
-        'desc': 'Number of NSEC-related hits from the aggressive NSEC cache',
-        'snmp': 109,
+        "name": "aggressive-nsec-cache-nsec-hits",
+        "lambda": "[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSECHits() : 0; }",
+        "desc": "Number of NSEC-related hits from the aggressive NSEC cache",
+        "snmp": 109,
     },
     {
-        'name': 'aggressive-nsec-cache-nsec3-hits',
-        'lambda': '[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSEC3Hits() : 0; }',
-        'desc': 'Number of NSEC3-related hits from the aggressive NSEC cache',
-        'snmp': 110,
+        "name": "aggressive-nsec-cache-nsec3-hits",
+        "lambda": "[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSEC3Hits() : 0; }",
+        "desc": "Number of NSEC3-related hits from the aggressive NSEC cache",
+        "snmp": 110,
     },
     {
-        'name': 'aggressive-nsec-cache-nsec-wc-hits',
-        'lambda': '[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSECWildcardHits() : 0; }',
-        'desc': 'Number of answers synthesized from the NSEC aggressive cache',
-        'snmp': 111
+        "name": "aggressive-nsec-cache-nsec-wc-hits",
+        "lambda": "[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSECWildcardHits() : 0; }",
+        "desc": "Number of answers synthesized from the NSEC aggressive cache",
+        "snmp": 111,
     },
     {
-        'name': 'aggressive-nsec-cache-nsec3-wc-hits',
-        'lambda': '[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSEC3WildcardHits() : 0; }',
-        'desc': 'Number of answers synthesized from the NSEC3 aggressive cache',
-        'snmp': 112
+        "name": "aggressive-nsec-cache-nsec3-wc-hits",
+        "lambda": "[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSEC3WildcardHits() : 0; }",
+        "desc": "Number of answers synthesized from the NSEC3 aggressive cache",
+        "snmp": 112,
     },
     {
-        'name': 'dot-outqueries',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::dotoutqueries); }',
-        'snmp': 113,
-        'desc': 'Number of outgoing DoT queries',
+        "name": "dot-outqueries",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::dotoutqueries); }",
+        "snmp": 113,
+        "desc": "Number of outgoing DoT queries",
     },
     {
-        'name': 'dns64-prefix-answers',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::dns64prefixanswers); }',
-        'snmp': 114,
-        'desc': 'Number of answers generated by dns64-prefix matching',
+        "name": "dns64-prefix-answers",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::dns64prefixanswers); }",
+        "snmp": 114,
+        "desc": "Number of answers generated by dns64-prefix matching",
     },
     {
-         'name': 'almost-expired-pushed',
-         'lambda': '[]() { return getAlmostExpiredTasksPushed(); }',
-         'snmp': 115,
-         'desc': 'Number of almost-expired tasks pushed',
+        "name": "almost-expired-pushed",
+        "lambda": "[]() { return getAlmostExpiredTasksPushed(); }",
+        "snmp": 115,
+        "desc": "Number of almost-expired tasks pushed",
     },
     {
-         'name': 'almost-expired-run',
-         'lambda': '[]() { return getAlmostExpiredTasksRun(); }',
-         'snmp': 116,
-         'desc': 'Number of almost-expired tasks run to completion',
+        "name": "almost-expired-run",
+        "lambda": "[]() { return getAlmostExpiredTasksRun(); }",
+        "snmp": 116,
+        "desc": "Number of almost-expired tasks run to completion",
     },
     {
-         'name': 'almost-expired-exceptions',
-         'lambda': '[]() { return getAlmostExpiredTaskExceptions(); }',
-         'snmp': 117,
-         'desc': 'Number of almost-expired tasks that caused an exception',
+        "name": "almost-expired-exceptions",
+        "lambda": "[]() { return getAlmostExpiredTaskExceptions(); }",
+        "snmp": 117,
+        "desc": "Number of almost-expired tasks that caused an exception",
     },
     {
-        'name': 'udp-in-csum-errors',
-        'lambda': '[] { return udpErrorStats("udp-in-csum-errors"); }',
-        'ifdef': '__linux',
-        'snmp': 118,
-        'desc': 'Number of UDP in checksum errors (Linux only)',
+        "name": "udp-in-csum-errors",
+        "lambda": '[] { return udpErrorStats("udp-in-csum-errors"); }',
+        "ifdef": "__linux",
+        "snmp": 118,
+        "desc": "Number of UDP in checksum errors (Linux only)",
     },
     {
-        'name': 'udp6-recvbuf-errors',
-        'lambda': '[] { return udp6ErrorStats("udp6-recvbuf-errors"); }',
-        'ifdef': '__linux',
-        'snmp': 119,
-        'desc': 'Number of UDP6 recvbuf errors (Linux only)',
+        "name": "udp6-recvbuf-errors",
+        "lambda": '[] { return udp6ErrorStats("udp6-recvbuf-errors"); }',
+        "ifdef": "__linux",
+        "snmp": 119,
+        "desc": "Number of UDP6 recvbuf errors (Linux only)",
     },
     {
-        'name': 'udp6-sndbuf-errors',
-        'lambda': '[] { return udp6ErrorStats("udp6-sndbuf-errors"); }',
-        'ifdef': '__linux',
-        'snmp': 120,
-        'desc': 'Number of UDP6 sndbuf errors (Linux only)',
+        "name": "udp6-sndbuf-errors",
+        "lambda": '[] { return udp6ErrorStats("udp6-sndbuf-errors"); }',
+        "ifdef": "__linux",
+        "snmp": 120,
+        "desc": "Number of UDP6 sndbuf errors (Linux only)",
     },
     {
-        'name': 'udp6-noport-errors',
-        'lambda': '[] { return udp6ErrorStats("udp6-noport-errors"); }',
-        'ifdef': '__linux',
-        'snmp': 121,
-        'desc': 'Number of UDP6 noport errors (Linux only)',
+        "name": "udp6-noport-errors",
+        "lambda": '[] { return udp6ErrorStats("udp6-noport-errors"); }',
+        "ifdef": "__linux",
+        "snmp": 121,
+        "desc": "Number of UDP6 noport errors (Linux only)",
     },
     {
-        'name': 'udp6-in-errors',
-        'lambda': '[] { return udp6ErrorStats("udp6-in-errors"); }',
-        'ifdef': '__linux',
-        'snmp': 122,
-        'snmpname': 'udp6inErrors',
-        'desc': 'Number of UDP6 in errors (Linux only)',
+        "name": "udp6-in-errors",
+        "lambda": '[] { return udp6ErrorStats("udp6-in-errors"); }',
+        "ifdef": "__linux",
+        "snmp": 122,
+        "snmpname": "udp6inErrors",
+        "desc": "Number of UDP6 in errors (Linux only)",
     },
     {
-        'name': 'udp6-in-csum-errors',
-        'ifdef': '__linux',
-        'lambda': '[] { return udp6ErrorStats("udp6-in-csum-errors"); }',
-        'snmp': 123,
-        'desc': 'Number of UDP6 in checksum errors (Linux only)',
+        "name": "udp6-in-csum-errors",
+        "ifdef": "__linux",
+        "lambda": '[] { return udp6ErrorStats("udp6-in-csum-errors"); }',
+        "snmp": 123,
+        "desc": "Number of UDP6 in checksum errors (Linux only)",
     },
     {
-        'name': 'cpu-iowait',
-        'lambda': '[] { return getCPUIOWait(string()); }',
-        'ifdef': '__linux',
-        'desc': 'Time spent waiting for I/O to complete by the whole system, in units of USER_HZ.'
+        "name": "cpu-iowait",
+        "lambda": "[] { return getCPUIOWait(string()); }",
+        "ifdef": "__linux",
+        "desc": "Time spent waiting for I/O to complete by the whole system, in units of USER_HZ.",
     },
     {
-        'name': 'cpu-steal',
-        'lambda': '[] { return getCPUSteal(string()); }',
-        'ifdef': '__linux',
-        'desc': 'Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ',
+        "name": "cpu-steal",
+        "lambda": "[] { return getCPUSteal(string()); }",
+        "ifdef": "__linux",
+        "desc": "Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ",
     },
     {
-        'name': 'cpu-msec-thread-n',
-        'lambda': '[]() { return toCPUStatsMap("cpu-msec"); }',
-        'desc': 'Number of milliseconds spent in thread n',
-        'ptype': 'multicounter',
-        'pname': 'cpu-msec-thread-0',
+        "name": "cpu-msec-thread-n",
+        "lambda": '[]() { return toCPUStatsMap("cpu-msec"); }',
+        "desc": "Number of milliseconds spent in thread n",
+        "ptype": "multicounter",
+        "pname": "cpu-msec-thread-0",
     },
     {
-        'name': 'memory-allocs',
-        'lambda': '[] { return g_mtracer->getAllocs(string()); }',
-        'ifdef': 'MALLOC_TRACE',
-        'desc': 'Only relevant for development and if malloc tracing is enabled',
+        "name": "memory-allocs",
+        "lambda": "[] { return g_mtracer->getAllocs(string()); }",
+        "ifdef": "MALLOC_TRACE",
+        "desc": "Only relevant for development and if malloc tracing is enabled",
     },
     {
-        'name': 'memory-alloc-flux',
-        'lambda': '[] { return g_mtracer->getAllocFlux(string()); }',
-        'ifdef': 'MALLOC_TRACE',
-        'desc': 'Only relevant for development and if malloc tracing is enabled',
+        "name": "memory-alloc-flux",
+        "lambda": "[] { return g_mtracer->getAllocFlux(string()); }",
+        "ifdef": "MALLOC_TRACE",
+        "desc": "Only relevant for development and if malloc tracing is enabled",
     },
     {
-        'name': 'memory-allocated',
-        'lambda': '[] { return g_mtracer->getTotAllocated(string()); }',
-        'ifdef': 'MALLOC_TRACE',
-        'desc': 'Only relevant for development and if malloc tracing is enabled',
+        "name": "memory-allocated",
+        "lambda": "[] { return g_mtracer->getTotAllocated(string()); }",
+        "ifdef": "MALLOC_TRACE",
+        "desc": "Only relevant for development and if malloc tracing is enabled",
     },
     {
-        'name': 'dnssec-result-bogus-no-valid-dnskey',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoValidDNSKEY); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be found',
+        "name": "dnssec-result-bogus-no-valid-dnskey",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoValidDNSKEY); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be found",
     },
     {
-        'name': 'dnssec-result-bogus-invalid-denial',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusInvalidDenial); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid denial of existence proof could not be found',
+        "name": "dnssec-result-bogus-invalid-denial",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusInvalidDenial); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid denial of existence proof could not be found",
     },
     {
-        'name': 'dnssec-result-bogus-unable-to-get-dss',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnableToGetDSs); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DS could not be retrieved',
+        "name": "dnssec-result-bogus-unable-to-get-dss",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnableToGetDSs); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DS could not be retrieved",
     },
     {
-        'name': 'dnssec-result-bogus-unable-to-get-dnskeys',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnableToGetDNSKEYs); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be retrieved',
+        "name": "dnssec-result-bogus-unable-to-get-dnskeys",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnableToGetDNSKEYs); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be retrieved",
     },
     {
-        'name': 'dnssec-result-bogus-self-signed-ds',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSelfSignedDS); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS record was signed by itself',
+        "name": "dnssec-result-bogus-self-signed-ds",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSelfSignedDS); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS record was signed by itself",
     },
     {
-        'name': 'dnssec-result-bogus-no-rrsig',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoRRSIG); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because required RRSIG records were not present in an answer',
+        "name": "dnssec-result-bogus-no-rrsig",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoRRSIG); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because required RRSIG records were not present in an answer",
     },
     {
-        'name': 'dnssec-result-bogus-no-valid-rrsig',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoValidRRSIG); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because only invalid RRSIG records were present in an answer',
+        "name": "dnssec-result-bogus-no-valid-rrsig",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoValidRRSIG); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because only invalid RRSIG records were present in an answer",
     },
     {
-        'name': 'dnssec-result-bogus-missing-negative-indication',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusMissingNegativeIndication); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a NODATA or NXDOMAIN answer lacked the required SOA and/or NSEC(3) records',
+        "name": "dnssec-result-bogus-missing-negative-indication",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusMissingNegativeIndication); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a NODATA or NXDOMAIN answer lacked the required SOA and/or NSEC(3) records",
     },
     {
-        'name': 'dnssec-result-bogus-signature-not-yet-valid',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSignatureNotYetValid); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature inception time in the RRSIG was not yet valid',
+        "name": "dnssec-result-bogus-signature-not-yet-valid",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSignatureNotYetValid); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature inception time in the RRSIG was not yet valid",
     },
     {
-        'name': 'dnssec-result-bogus-signature-expired',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSignatureExpired); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature expired time in the RRSIG was in the past',
+        "name": "dnssec-result-bogus-signature-expired",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSignatureExpired); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature expired time in the RRSIG was in the past",
     },
     {
-        'name': 'dnssec-result-bogus-unsupported-dnskey-algo',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnsupportedDNSKEYAlgo); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DNSKEY RRset contained only unsupported DNSSEC algorithms',
+        "name": "dnssec-result-bogus-unsupported-dnskey-algo",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnsupportedDNSKEYAlgo); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DNSKEY RRset contained only unsupported DNSSEC algorithms",
     },
     {
-        'name': 'dnssec-result-bogus-unsupported-ds-digest-type',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnsupportedDSDigestType); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS RRset contained only unsupported digest types',
+        "name": "dnssec-result-bogus-unsupported-ds-digest-type",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnsupportedDSDigestType); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS RRset contained only unsupported digest types",
     },
     {
-        'name': 'dnssec-result-bogus-no-zone-key-bit-set',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoZoneKeyBitSet); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because no DNSKEY with the Zone Key bit set was found',
+        "name": "dnssec-result-bogus-no-zone-key-bit-set",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoZoneKeyBitSet); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because no DNSKEY with the Zone Key bit set was found",
     },
     {
-        'name': 'dnssec-result-bogus-revoked-dnskey',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusRevokedDNSKEY); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs were revoked',
+        "name": "dnssec-result-bogus-revoked-dnskey",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusRevokedDNSKEY); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs were revoked",
     },
     {
-        'name': 'dnssec-result-bogus-invalid-dnskey-protocol',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusInvalidDNSKEYProtocol); }',
-        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs had invalid protocols',
+        "name": "dnssec-result-bogus-invalid-dnskey-protocol",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusInvalidDNSKEYProtocol); }",
+        "desc": "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs had invalid protocols",
     },
     {
-        'name': 'x-dnssec-result-bogus',
-        'lambda': '''[]() {
+        "name": "x-dnssec-result-bogus",
+        "lambda": """[]() {
          std::set<vState> const bogusStates = {vState::BogusNoValidDNSKEY, vState::BogusInvalidDenial, vState::BogusUnableToGetDSs, vState::BogusUnableToGetDNSKEYs, vState::BogusSelfSignedDS, vState::BogusNoRRSIG, vState::BogusNoValidRRSIG, vState::BogusMissingNegativeIndication, vState::BogusSignatureNotYetValid, vState::BogusSignatureExpired, vState::BogusUnsupportedDNSKEYAlgo, vState::BogusUnsupportedDSDigestType, vState::BogusNoZoneKeyBitSet, vState::BogusRevokedDNSKEY, vState::BogusInvalidDNSKEYProtocol};
           auto counts = g_Counters.sum(rec::DNSSECHistogram::xdnssec);
           uint64_t total = 0;
@@ -1018,441 +1017,440 @@ table = [
             total += counts.at(state);
           }
           return total;
-         }''',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+         }""",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-no-valid-dnskey',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidDNSKEY); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-no-valid-dnskey",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidDNSKEY); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-invalid-denial',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDenial); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-invalid-denial",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDenial); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-unable-to-get-dss',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDSs); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-unable-to-get-dss",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDSs); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-unable-to-get-dnskeys',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDNSKEYs); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-unable-to-get-dnskeys",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDNSKEYs); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-self-signed-ds',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSelfSignedDS); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-self-signed-ds",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSelfSignedDS); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-no-rrsig',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoRRSIG); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-no-rrsig",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoRRSIG); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-no-valid-rrsig',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidRRSIG); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-no-valid-rrsig",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidRRSIG); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-missing-negative-indication',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusMissingNegativeIndication); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-missing-negative-indication",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusMissingNegativeIndication); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-signature-not-yet-valid',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureNotYetValid); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-signature-not-yet-valid",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureNotYetValid); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-signature-expired',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureExpired); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-signature-expired",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureExpired); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-unsupported-dnskey-algo',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDNSKEYAlgo); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-unsupported-dnskey-algo",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDNSKEYAlgo); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-unsupported-ds-digest-type',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDSDigestType); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-unsupported-ds-digest-type",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDSDigestType); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-no-zone-key-bit-set',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoZoneKeyBitSet); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-no-zone-key-bit-set",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoZoneKeyBitSet); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-revoked-dnskey',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusRevokedDNSKEY); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-revoked-dnskey",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusRevokedDNSKEY); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-bogus-invalid-dnskey-protocol',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDNSKEYProtocol); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-bogus-invalid-dnskey-protocol",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDNSKEYProtocol); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-indeterminate',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Indeterminate); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-indeterminate",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Indeterminate); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-nta',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::NTA); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-nta",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::NTA); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-insecure',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Insecure); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-insecure",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Insecure); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'x-dnssec-result-secure',
-        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Secure); }',
-        'if': '::arg()["x-dnssec-names"].length() > 0',
-        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.'
+        "name": "x-dnssec-result-secure",
+        "lambda": "[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Secure); }",
+        "if": '::arg()["x-dnssec-names"].length() > 0',
+        "desc": "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.",
     },
     {
-        'name': 'idle-tcpout-connections',
-        'lambda': 'getCurrentIdleTCPConnections',
-        'ptype': 'gauge',
-        'desc': 'Number of connections in the TCP idle outgoing connections pool',
+        "name": "idle-tcpout-connections",
+        "lambda": "getCurrentIdleTCPConnections",
+        "ptype": "gauge",
+        "desc": "Number of connections in the TCP idle outgoing connections pool",
     },
     {
-        'name': 'source-disallowed-notify',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::sourceDisallowedNotify); }',
-        'desc': 'Number of NOTIFY operations not allowed by allow-notify-from',
-        'snmp': 124,
+        "name": "source-disallowed-notify",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::sourceDisallowedNotify); }",
+        "desc": "Number of NOTIFY operations not allowed by allow-notify-from",
+        "snmp": 124,
     },
     {
-        'name': 'zone-disallowed-notify',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::zoneDisallowedNotify); }',
-        'desc': 'Number of NOTIFY operations not allowed by allow-notify-for',
-        'snmp': 125,
+        "name": "zone-disallowed-notify",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::zoneDisallowedNotify); }",
+        "desc": "Number of NOTIFY operations not allowed by allow-notify-for",
+        "snmp": 125,
     },
     {
-        'name': 'non-resolving-nameserver-entries',
-        'lambda': 'SyncRes::getNonResolvingNSSize',
-        'ptype': 'gauge',
-        'snmp': 126,
-        'desc': 'Number of entries in the non-resolving NS name cache',
+        "name": "non-resolving-nameserver-entries",
+        "lambda": "SyncRes::getNonResolvingNSSize",
+        "ptype": "gauge",
+        "snmp": 126,
+        "desc": "Number of entries in the non-resolving NS name cache",
     },
     {
-        'name': 'maintenance-usec',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::maintenanceUsec); }',
-        'snmp': 127,
-        'snmpname': 'maintenanceUSec',
-        'desc': 'Time spent doing internal maintenance, including Lua maintenance',
+        "name": "maintenance-usec",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::maintenanceUsec); }",
+        "snmp": 127,
+        "snmpname": "maintenanceUSec",
+        "desc": "Time spent doing internal maintenance, including Lua maintenance",
     },
     {
-        'name': 'maintenance-calls',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::maintenanceCalls); }',
-        'snmp': 128,
-        'snmpname': 'maintenanceCount',
-        'desc': 'Number of times internal maintenance has been called, including Lua maintenance',
+        "name": "maintenance-calls",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::maintenanceCalls); }",
+        "snmp": 128,
+        "snmpname": "maintenanceCount",
+        "desc": "Number of times internal maintenance has been called, including Lua maintenance",
     },
-
     # Entries for auth-rcode-answers are a bit different than others: separate rec_control and SNMP metrics, but a multicounter entry for Prometheus. The alphabetically first gets a real pname, the others an empty one.
     # We only generate the Prometheus comment for the first one
     {
-        'name': 'auth-noerror-answers',
-        'ptype': 'multicounter',
-        'snmp': 129,
-        'snmpname': 'authrcode0Count',
-        'desc': 'Number of rcode 0 (noerror) answers received',
-        'pdesc': '',
+        "name": "auth-noerror-answers",
+        "ptype": "multicounter",
+        "snmp": 129,
+        "snmpname": "authrcode0Count",
+        "desc": "Number of rcode 0 (noerror) answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-formerr-answers',  # This entry is alphabetically the first, so state the Prometheus HELP text
-        'ptype': 'multicounter',
-        'snmp': 130,
-        'snmpname': 'authrcode1Count',
-        'desc': 'Number of rcode 1 (formerr) answers received',
-        'pdesc':  'Counts the rcodes returned by authoritative servers.'
+        "name": "auth-formerr-answers",  # This entry is alphabetically the first, so state the Prometheus HELP text
+        "ptype": "multicounter",
+        "snmp": 130,
+        "snmpname": "authrcode1Count",
+        "desc": "Number of rcode 1 (formerr) answers received",
+        "pdesc": "Counts the rcodes returned by authoritative servers.",
     },
     {
-        'name': 'auth-servfail-answers',
-        'ptype': 'multicounter',
-        'snmp': 131,
-        'snmpname': 'authrcode2Count',
-        'desc': 'Number of rcode 2 (servfail) answers received',
-        'pdesc': '',
+        "name": "auth-servfail-answers",
+        "ptype": "multicounter",
+        "snmp": 131,
+        "snmpname": "authrcode2Count",
+        "desc": "Number of rcode 2 (servfail) answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-nxdomain-answers',
-        'ptype': 'multicounter',
-        'snmp': 132,
-        'snmpname': 'authrcode3Count',
-        'desc': 'Number of rcode 3 (nxdomain) answers received',
-        'pdesc': '',
+        "name": "auth-nxdomain-answers",
+        "ptype": "multicounter",
+        "snmp": 132,
+        "snmpname": "authrcode3Count",
+        "desc": "Number of rcode 3 (nxdomain) answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-notimp-answers',
-        'ptype': 'multicounter',
-        'snmp': 133,
-        'snmpname': 'authrcode4Count',
-        'desc': 'Number of rcode 4 (notimp) answers received',
-        'pdesc': '',
+        "name": "auth-notimp-answers",
+        "ptype": "multicounter",
+        "snmp": 133,
+        "snmpname": "authrcode4Count",
+        "desc": "Number of rcode 4 (notimp) answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-refused-answers',
-        'ptype': 'multicounter',
-        'snmp': 134,
-        'snmpname': 'authrcode5Count',
-        'desc': 'Number of rcode 5 (refused) answers received',
-        'pdesc': '',
+        "name": "auth-refused-answers",
+        "ptype": "multicounter",
+        "snmp": 134,
+        "snmpname": "authrcode5Count",
+        "desc": "Number of rcode 5 (refused) answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-yxdomain-answers',
-        'ptype': 'multicounter',
-        'snmp': 135,
-        'snmpname': 'authrcode6Count',
-        'desc': 'Number of rcode 6 (yxdomain) answers received',
-        'pdesc': '',
+        "name": "auth-yxdomain-answers",
+        "ptype": "multicounter",
+        "snmp": 135,
+        "snmpname": "authrcode6Count",
+        "desc": "Number of rcode 6 (yxdomain) answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-yxrrset-answers',
-        'ptype': 'multicounter',
-        'snmp': 136,
-        'snmpname': 'authrcode7Count',
-        'desc': 'Number of rcode 7 (yxrrset) answers received',
-        'pdesc': '',
+        "name": "auth-yxrrset-answers",
+        "ptype": "multicounter",
+        "snmp": 136,
+        "snmpname": "authrcode7Count",
+        "desc": "Number of rcode 7 (yxrrset) answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-nxrrset-answers',
-        'ptype': 'multicounter',
-        'snmp': 137,
-        'snmpname': 'authrcode8Count',
-        'desc': 'Number of rcode 8 (nxrrset) answers received',
-        'pdesc': '',
+        "name": "auth-nxrrset-answers",
+        "ptype": "multicounter",
+        "snmp": 137,
+        "snmpname": "authrcode8Count",
+        "desc": "Number of rcode 8 (nxrrset) answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-notauth-answers',
-        'ptype': 'multicounter',
-        'snmp': 138,
-        'snmpname': 'authrcode9Count',
-        'desc': 'Number of rcode 9 (notauth) answers received',
-        'pdesc': '',
+        "name": "auth-notauth-answers",
+        "ptype": "multicounter",
+        "snmp": 138,
+        "snmpname": "authrcode9Count",
+        "desc": "Number of rcode 9 (notauth) answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-rcode10-answers',
-        'ptype': 'multicounter',
-        'snmp': 139,
-        'snmpname': 'authrcode10Count',
-        'desc': 'Number of rcode 10 answers received',
-        'pdesc': '',
+        "name": "auth-rcode10-answers",
+        "ptype": "multicounter",
+        "snmp": 139,
+        "snmpname": "authrcode10Count",
+        "desc": "Number of rcode 10 answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-rcode11-answers',
-        'ptype': 'multicounter',
-        'snmp': 140,
-        'snmpname': 'authrcode11Count',
-        'desc': 'Number of rcode 11 answers received',
-        'pdesc': '',
+        "name": "auth-rcode11-answers",
+        "ptype": "multicounter",
+        "snmp": 140,
+        "snmpname": "authrcode11Count",
+        "desc": "Number of rcode 11 answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-rcode12-answers',
-        'ptype': 'multicounter',
-        'snmp': 141,
-        'snmpname': 'authrcode12Count',
-        'desc': 'Number of rcode 12 answers received',
-        'pdesc': '',
+        "name": "auth-rcode12-answers",
+        "ptype": "multicounter",
+        "snmp": 141,
+        "snmpname": "authrcode12Count",
+        "desc": "Number of rcode 12 answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-rcode13-answers',
-        'ptype': 'multicounter',
-        'snmp': 142,
-        'snmpname': 'authrcode13Count',
-        'desc': 'Number of rcode 13 answers received',
-        'pdesc': '',
+        "name": "auth-rcode13-answers",
+        "ptype": "multicounter",
+        "snmp": 142,
+        "snmpname": "authrcode13Count",
+        "desc": "Number of rcode 13 answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-rcode14-answers',
-        'ptype': 'multicounter',
-        'snmp': 143,
-        'snmpname': 'authrcode14Count',
-        'desc': 'Number of rcode 14 answers received',
-        'pdesc': '',
+        "name": "auth-rcode14-answers",
+        "ptype": "multicounter",
+        "snmp": 143,
+        "snmpname": "authrcode14Count",
+        "desc": "Number of rcode 14 answers received",
+        "pdesc": "",
     },
     {
-        'name': 'auth-rcode15-answers',
-        'ptype': 'multicounter',
-        'snmp': 144,
-        'snmpname': 'authrcode15Count',
-        'desc': 'Number of rcode 15 answers received',
-        'pdesc': '',
+        "name": "auth-rcode15-answers",
+        "ptype": "multicounter",
+        "snmp": 144,
+        "snmpname": "authrcode15Count",
+        "desc": "Number of rcode 15 answers received",
+        "pdesc": "",
     },
     {
-        'name': 'packetcache-contended',
-        'lambda': '[]() { return g_packetCache ? g_packetCache->stats().first : 0; }',
-        'desc': 'Number of contended packet cache lock acquisitions',
-        'snmp': 145,
-        'snmpname': 'packetCacheContended',
+        "name": "packetcache-contended",
+        "lambda": "[]() { return g_packetCache ? g_packetCache->stats().first : 0; }",
+        "desc": "Number of contended packet cache lock acquisitions",
+        "snmp": 145,
+        "snmpname": "packetCacheContended",
     },
     {
-        'name': 'packetcache-acquired',
-        'lambda': '[]() { return g_packetCache ? g_packetCache->stats().second : 0; }',
-        'desc': 'Number of packet cache lock acquisitions',
-        'snmp': 146,
-        'snmpname': 'packetCacheAcquired',
+        "name": "packetcache-acquired",
+        "lambda": "[]() { return g_packetCache ? g_packetCache->stats().second : 0; }",
+        "desc": "Number of packet cache lock acquisitions",
+        "snmp": 146,
+        "snmpname": "packetCacheAcquired",
     },
     {
-        'name': 'nod-events',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::nodCount); }',
-        'snmp': 147,
-        'desc': 'Count of NOD events',
+        "name": "nod-events",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::nodCount); }",
+        "snmp": 147,
+        "desc": "Count of NOD events",
     },
     {
-        'name': 'udr-events',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::udrCount); }',
-        'snmp': 148,
-        'desc': 'Count of UDR events',
+        "name": "udr-events",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::udrCount); }",
+        "snmp": 148,
+        "desc": "Count of UDR events",
     },
     {
-        'name': 'max-chain-length',
-        'lambda': '[] { return g_Counters.max(rec::Counter::maxChainLength); }',
-        'snmp': 149,
-        'desc': 'Maximum chain length',
+        "name": "max-chain-length",
+        "lambda": "[] { return g_Counters.max(rec::Counter::maxChainLength); }",
+        "snmp": 149,
+        "desc": "Maximum chain length",
     },
     {
-        'name': 'max-chain-weight',
-        'lambda': '[] { return g_Counters.max(rec::Counter::maxChainWeight); }',
-        'snmp': 150,
-        'desc': 'Maximum chain weight',
+        "name": "max-chain-weight",
+        "lambda": "[] { return g_Counters.max(rec::Counter::maxChainWeight); }",
+        "snmp": 150,
+        "desc": "Maximum chain weight",
     },
     {
-        'name': 'chain-limits',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::chainLimits); }',
-        'snmp': 151,
-        'desc': 'Chain limits reached',
+        "name": "chain-limits",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::chainLimits); }",
+        "snmp": 151,
+        "desc": "Chain limits reached",
     },
     {
-        'name': 'tcp-overflow',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::tcpOverflow); }',
-        'desc': 'Incoming TCP limits reached',
-        'snmp': 152,
+        "name": "tcp-overflow",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::tcpOverflow); }",
+        "desc": "Incoming TCP limits reached",
+        "snmp": 152,
     },
     {
-        'name': 'ecs-missing',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::ecsMissingCount); }',
-        'desc': 'Number of answers where ECS info was missing',
-        'snmp': 153,
+        "name": "ecs-missing",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::ecsMissingCount); }",
+        "desc": "Number of answers where ECS info was missing",
+        "snmp": 153,
     },
     {
-        'name': 'cookie-malformed',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMalformed); }',
-        'desc': 'Number of malformed cookies received',
-        'snmp': 154,
+        "name": "cookie-malformed",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::cookieMalformed); }",
+        "desc": "Number of malformed cookies received",
+        "snmp": 154,
     },
     {
-        'name': 'cookie-matched',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMatched); }',
-        'desc': 'Number of matching cookies received',
-        'snmp': 155,
+        "name": "cookie-matched",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::cookieMatched); }",
+        "desc": "Number of matching cookies received",
+        "snmp": 155,
     },
     {
-        'name': 'cookie-mismatch-tcp',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMismatchedOverTCP); }',
-        'desc': 'Number of mismatched cookies received over TCP',
-        'snmp': 156,
+        "name": "cookie-mismatch-tcp",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::cookieMismatchedOverTCP); }",
+        "desc": "Number of mismatched cookies received over TCP",
+        "snmp": 156,
     },
     {
-        'name': 'cookie-mismatch-udp',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMismatchedOverUDP); }',
-        'desc': 'Number of mismatched cookies received over UDP',
-        'snmp': 157,
+        "name": "cookie-mismatch-udp",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::cookieMismatchedOverUDP); }",
+        "desc": "Number of mismatched cookies received over UDP",
+        "snmp": 157,
     },
     {
-        'name': 'cookie-not-in-reply',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::cookieNotInReply); }',
-        'desc': 'Number of times an authoritative server sent a reply without a cookie',
-        'snmp': 158,
+        "name": "cookie-not-in-reply",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::cookieNotInReply); }",
+        "desc": "Number of times an authoritative server sent a reply without a cookie",
+        "snmp": 158,
     },
     {
-        'name': 'cookie-retry',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::cookieRetry); }',
-        'desc': 'Number of retries because authoritative server sent a BADCOOKIE reply',
-        'snmp': 159,
+        "name": "cookie-retry",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::cookieRetry); }",
+        "desc": "Number of retries because authoritative server sent a BADCOOKIE reply",
+        "snmp": 159,
     },
     {
-        'name': 'cookies-supported',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::cookieProbeSupported); }',
-        'desc': 'Number of authoritative server cookie probes resulting in success',
-        'snmp': 160,
+        "name": "cookies-supported",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::cookieProbeSupported); }",
+        "desc": "Number of authoritative server cookie probes resulting in success",
+        "snmp": 160,
     },
     {
-        'name': 'cookies-unsupported',
-        'lambda': '[] { return g_Counters.sum(rec::Counter::cookieProbeUnsupported); }',
-        'desc': 'Number of authoritative server cookie probes not resulting in success',
-        'snmp': 161,
+        "name": "cookies-unsupported",
+        "lambda": "[] { return g_Counters.sum(rec::Counter::cookieProbeUnsupported); }",
+        "desc": "Number of authoritative server cookie probes not resulting in success",
+        "snmp": 161,
     },
     {
-        'name': 'remote-logger-count',
-        'lambda':  '''[]() {
+        "name": "remote-logger-count",
+        "lambda": """[]() {
     return toRemoteLoggerStatsMap("remote-logger-count");
-        }''',
-        'desc': 'Number of remote logging events',
-        'ptype': 'multicounter',
-        'pname': 'remote-logger-count-o-0', #  For multicounters, state the first
+        }""",
+        "desc": "Number of remote logging events",
+        "ptype": "multicounter",
+        "pname": "remote-logger-count-o-0",  #  For multicounters, state the first
         # No SNMP
     },
     {
-        'name': 'cumul-clientanswers-x',
+        "name": "cumul-clientanswers-x",
         # No lambda
-        'desc': 'Cumulative counts of answer times of authoritative servers in buckets less than x microseconds.',
-        'longdesc': 'Disabled by default, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`. These metrics are useful for Prometheus and not listed in other outputs by default.',
-        'ptype': 'histogram',
-        'pname': 'cumul-clientanswers-count', # For cumulative histogram, state the xxx_count name where xxx matches the name in rec_channel_rec
+        "desc": "Cumulative counts of answer times of authoritative servers in buckets less than x microseconds.",
+        "longdesc": "Disabled by default, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`. These metrics are useful for Prometheus and not listed in other outputs by default.",
+        "ptype": "histogram",
+        "pname": "cumul-clientanswers-count",  # For cumulative histogram, state the xxx_count name where xxx matches the name in rec_channel_rec
         # No SNMP
     },
     {
-        'name': 'cumul-authanswers-x',
+        "name": "cumul-authanswers-x",
         # No lambda
-        'desc': 'Cumulative counts of answer times to clients in buckets less than x microseconds.',
-        'longdesc': 'Disabled by default, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`. These metrics are useful for Prometheus and not listed in other outputs by default.',
-        'ptype': 'histogram',
-        'pname': 'cumul-authanswers-count4', # For cumulative histogram, state the xxx_count name where xxx matches the name in rec_channel_rec
+        "desc": "Cumulative counts of answer times to clients in buckets less than x microseconds.",
+        "longdesc": "Disabled by default, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`. These metrics are useful for Prometheus and not listed in other outputs by default.",
+        "ptype": "histogram",
+        "pname": "cumul-authanswers-count4",  # For cumulative histogram, state the xxx_count name where xxx matches the name in rec_channel_rec
         # No SNMP
     },
     {
-        'name': 'policy-hits',
+        "name": "policy-hits",
         # No lambda
-        'desc': 'Number of policy decisions based on Lua',
-        'longdesc': '(``type = ""filter""``), or RPZ (``type = ""rpz""``). RPZ hits include the :ref:`rpz-policyName`. These metrics are useful for Prometheus and not listed in other outputs by default.',
-        'ptype': 'multicounter',
-        'pname': 'policy-hits', # For multicounters, state the first
+        "desc": "Number of policy decisions based on Lua",
+        "longdesc": '(``type = ""filter""``), or RPZ (``type = ""rpz""``). RPZ hits include the :ref:`rpz-policyName`. These metrics are useful for Prometheus and not listed in other outputs by default.',
+        "ptype": "multicounter",
+        "pname": "policy-hits",  # For multicounters, state the first
         # No SNMP
     },
     {
-        'name': 'proxy-mapping',
+        "name": "proxy-mapping",
         # No lambda
-        'desc': 'Proxy mappings done',
-        'ptype': 'multicounter',
-        'pname': 'proxy-mapping-total-n-0', # For multicounters, state the first
+        "desc": "Proxy mappings done",
+        "ptype": "multicounter",
+        "pname": "proxy-mapping-total-n-0",  # For multicounters, state the first
         # No SNMP
     },
 ]
index 704eaa086b8feb575408e54bd4e08c2d79797418..8737479a759f8f850be52354924eb4f49825e533 100644 (file)
@@ -1,4 +1,5 @@
 """The Python script that takes table.py and generates C++, Rust ahd .rst code."""
+
 #
 # For C++ it generates cxxsettings-generated.cc containing support for old style
 # settings plus conversion from old style to new style.
@@ -91,8 +92,10 @@ import re
 import sys
 from pathlib import Path
 
+
 class LType(Enum):
     """The type we handle in table.py"""
+
     Bool = auto()
     Command = auto()
     Double = auto()
@@ -106,7 +109,7 @@ class LType(Enum):
     ListNegativeTrustAnchors = auto()
     ListProtobufServers = auto()
     ListProxyMappings = auto()
-    ListRPZs = auto();
+    ListRPZs = auto()
     ListSocketAddresses = auto()
     ListSortLists = auto()
     ListStrings = auto()
@@ -118,284 +121,311 @@ class LType(Enum):
     String = auto()
     Uint64 = auto()
 
-listOfStringTypes = (LType.ListSocketAddresses,  LType.ListStrings, LType.ListSubnets)
-listOfStructuredTypes = (LType.ListAuthZones, LType.ListForwardZones, LType.ListTrustAnchors, LType.ListNegativeTrustAnchors,
-                         LType.ListProtobufServers, LType.ListDNSTapFrameStreamServers, LType.ListDNSTapNODFrameStreamServers,
-                         LType.ListSortLists, LType.ListRPZs, LType.ListZoneToCaches, LType.ListAllowedAdditionalQTypes,
-                         LType.ListProxyMappings, LType.ListForwardingCatalogZones, LType.ListIncomingWSConfigs,
-                         LType.ListOutgoingTLSConfigurations, LType.ListOpenTelemetryTraceConditions)
+
+listOfStringTypes = (LType.ListSocketAddresses, LType.ListStrings, LType.ListSubnets)
+listOfStructuredTypes = (
+    LType.ListAuthZones,
+    LType.ListForwardZones,
+    LType.ListTrustAnchors,
+    LType.ListNegativeTrustAnchors,
+    LType.ListProtobufServers,
+    LType.ListDNSTapFrameStreamServers,
+    LType.ListDNSTapNODFrameStreamServers,
+    LType.ListSortLists,
+    LType.ListRPZs,
+    LType.ListZoneToCaches,
+    LType.ListAllowedAdditionalQTypes,
+    LType.ListProxyMappings,
+    LType.ListForwardingCatalogZones,
+    LType.ListIncomingWSConfigs,
+    LType.ListOutgoingTLSConfigurations,
+    LType.ListOpenTelemetryTraceConditions,
+)
+
 
 def get_olddoc_typename(typ):
     """Given a type from table.py, return the old-style type name"""
     if typ == LType.Bool:
-        return 'Boolean'
+        return "Boolean"
     if typ == LType.Uint64:
-        return 'Integer'
+        return "Integer"
     if typ == LType.Double:
-        return 'Double'
+        return "Double"
     if typ == LType.String:
-        return 'String'
+        return "String"
     if typ == LType.ListSocketAddresses:
-        return 'Comma separated list or IPs of IP:port combinations'
+        return "Comma separated list or IPs of IP:port combinations"
     if typ == LType.ListSubnets:
-        return 'Comma separated list of IP addresses or subnets, negation supported'
+        return "Comma separated list of IP addresses or subnets, negation supported"
     if typ == LType.ListStrings:
-        return 'Comma separated list of strings'
+        return "Comma separated list of strings"
     if typ == LType.ListForwardZones:
-        return 'Comma separated list of \'zonename=IP\' pairs'
+        return "Comma separated list of 'zonename=IP' pairs"
     if typ == LType.ListAuthZones:
-        return 'Comma separated list of \'zonename=filename\' pairs'
-    return 'Unknown1' + str(typ)
+        return "Comma separated list of 'zonename=filename' pairs"
+    return "Unknown1" + str(typ)
+
 
 def get_newdoc_typename(typ):
     """Given a type from table.py, return the new-style type name"""
     if typ == LType.Bool:
-        return 'Boolean'
+        return "Boolean"
     if typ == LType.Uint64:
-        return 'Integer'
+        return "Integer"
     if typ == LType.Double:
-        return 'Double'
+        return "Double"
     if typ == LType.String:
-        return 'String'
+        return "String"
     if typ == LType.ListSocketAddresses:
-        return 'Sequence of `Socket Address`_ (IP or IP:port combinations)'
+        return "Sequence of `Socket Address`_ (IP or IP:port combinations)"
     if typ == LType.ListSubnets:
-        return 'Sequence of `Subnet`_ (IP addresses or subnets, negation supported)'
+        return "Sequence of `Subnet`_ (IP addresses or subnets, negation supported)"
     if typ == LType.ListStrings:
-        return 'Sequence of strings'
+        return "Sequence of strings"
     if typ == LType.ListForwardZones:
-        return 'Sequence of `Forward Zone`_'
+        return "Sequence of `Forward Zone`_"
     if typ == LType.ListAuthZones:
-        return 'Sequence of `Auth Zone`_'
+        return "Sequence of `Auth Zone`_"
     if typ == LType.ListTrustAnchors:
-        return 'Sequence of `TrustAnchor`_'
+        return "Sequence of `TrustAnchor`_"
     if typ == LType.ListNegativeTrustAnchors:
-        return 'Sequence of `NegativeTrustAnchor`_'
+        return "Sequence of `NegativeTrustAnchor`_"
     if typ == LType.ListProtobufServers:
-        return 'Sequence of `ProtobufServer`_'
+        return "Sequence of `ProtobufServer`_"
     if typ == LType.ListDNSTapFrameStreamServers:
-        return 'Sequence of `DNSTapFrameStreamServers`_'
+        return "Sequence of `DNSTapFrameStreamServers`_"
     if typ == LType.ListDNSTapNODFrameStreamServers:
-        return 'Sequence of `DNSTapNODFrameStreamServers`_'
+        return "Sequence of `DNSTapNODFrameStreamServers`_"
     if typ == LType.ListSortLists:
-        return 'Sequence of `Sortlist`_'
+        return "Sequence of `Sortlist`_"
     if typ == LType.ListRPZs:
-        return 'Sequence of `RPZ`_'
+        return "Sequence of `RPZ`_"
     if typ == LType.ListZoneToCaches:
-        return 'Sequence of `ZoneToCache`_'
+        return "Sequence of `ZoneToCache`_"
     if typ == LType.ListAllowedAdditionalQTypes:
-        return 'Sequence of `AllowedAdditionalQType`_'
+        return "Sequence of `AllowedAdditionalQType`_"
     if typ == LType.ListProxyMappings:
-        return 'Sequence of `ProxyMapping`_'
+        return "Sequence of `ProxyMapping`_"
     if typ == LType.ListForwardingCatalogZones:
-        return 'Sequence of `ForwardingCatalogZone`_'
+        return "Sequence of `ForwardingCatalogZone`_"
     if typ == LType.ListIncomingWSConfigs:
-        return 'Sequence of `IncomingWSConfig`_'
+        return "Sequence of `IncomingWSConfig`_"
     if typ == LType.ListOutgoingTLSConfigurations:
-        return 'Sequence of `OutgoingTLSConfiguration`_'
+        return "Sequence of `OutgoingTLSConfiguration`_"
     if typ == LType.ListOpenTelemetryTraceConditions:
-        return 'Sequence of `OpenTelemetryTraceCondition`_'
-    return 'Unknown2' + str(typ)
+        return "Sequence of `OpenTelemetryTraceCondition`_"
+    return "Unknown2" + str(typ)
+
 
 def get_default_olddoc_value(typ, val):
     """Given a type and a value from table.py return the old doc representation of the value"""
     if typ == LType.Bool:
-        if val == 'false':
-            return 'no'
-        return 'yes'
-    if val == '':
-        return '(empty)'
+        if val == "false":
+            return "no"
+        return "yes"
+    if val == "":
+        return "(empty)"
     return val
 
+
 def get_default_newdoc_value(typ, val):
     """Given a type and a value from table.py return the new doc representation of the value"""
     if typ in (LType.Bool, LType.Uint64, LType.Double):
-        return '``' + val + '``'
-    if typ == LType.String and val == '':
-        return '(empty)'
+        return "``" + val + "``"
+    if typ == LType.String and val == "":
+        return "(empty)"
     if typ == LType.String:
-        return '``' + val + '``'
-    parts = re.split('[ \t,]+', val)
+        return "``" + val + "``"
+    parts = re.split("[ \t,]+", val)
     if len(parts) > 0:
-        ret = ''
+        ret = ""
         for part in parts:
-            if part == '':
+            if part == "":
                 continue
-            if ret != '':
-                ret += ', '
-            if ':' in part or '!' in part:
+            if ret != "":
+                ret += ", "
+            if ":" in part or "!" in part:
                 ret += "'" + part + "'"
             else:
                 ret += part
     else:
-        ret = ''
-    return '``[' + ret + ']``'
+        ret = ""
+    return "``[" + ret + "]``"
+
 
 def list_to_base_type(typ):
     typeName = typ.name
-    if typeName.startswith('List') and typeName.endswith('s'):
-        baseName = typeName[4:len(typeName) - 1]
+    if typeName.startswith("List") and typeName.endswith("s"):
+        baseName = typeName[4 : len(typeName) - 1]
         return baseName
-    return 'Unknown3: ' + typeName
+    return "Unknown3: " + typeName
+
 
 def get_rust_type(typ):
     """Determine which Rust type is used for a logical type"""
     if typ == LType.Bool:
-        return 'bool'
+        return "bool"
     if typ == LType.Uint64:
-        return 'u64'
+        return "u64"
     if typ == LType.Double:
-        return 'f64'
+        return "f64"
     if typ == LType.String:
-        return 'String'
+        return "String"
     # These vectors map to Vec<String>
     if typ == LType.ListSocketAddresses:
-        return 'Vec<String>'
+        return "Vec<String>"
     if typ == LType.ListSubnets:
-        return 'Vec<String>'
+        return "Vec<String>"
     if typ == LType.ListStrings:
-        return 'Vec<String>'
+        return "Vec<String>"
     # These vectors map to Vec<Type>
-    return 'Vec<' + list_to_base_type(typ) + '>'
+    return "Vec<" + list_to_base_type(typ) + ">"
+
 
 def quote(arg):
     """Return a quoted string"""
     return '"' + arg + '"'
 
+
 def isEnvVar(name):
-    return name in ('SYSCONFDIR', 'NODCACHEDIRNOD', 'NODCACHEDIRUDR')
+    return name in ("SYSCONFDIR", "NODCACHEDIRNOD", "NODCACHEDIRUDR")
+
 
 def gen_cxx_defineoldsettings(file, entries):
     """Generate C++ code to declare old-style settings"""
-    file.write('void pdns::settings::rec::defineOldStyleSettings()\n{\n')
+    file.write("void pdns::settings::rec::defineOldStyleSettings()\n{\n")
     for entry in entries:
-        helptxt = quote(entry['help'])
-        oldname = quote(entry['oldname'])
-        if entry['type'] == LType.Bool:
-            if entry['default'] == "true":
+        helptxt = quote(entry["help"])
+        oldname = quote(entry["oldname"])
+        if entry["type"] == LType.Bool:
+            if entry["default"] == "true":
                 cxxdef = "yes"
             else:
                 cxxdef = "no"
             cxxdef = quote(cxxdef)
             file.write(f"  ::arg().setSwitch({oldname}, {helptxt}) = {cxxdef};\n")
-        elif entry['type'] == LType.Command:
+        elif entry["type"] == LType.Command:
             file.write(f"  ::arg().setCmd({oldname}, {helptxt});\n")
         else:
-            cxxdef = entry['default'] if isEnvVar(entry['default']) else quote(entry['default'])
+            cxxdef = entry["default"] if isEnvVar(entry["default"]) else quote(entry["default"])
             file.write(f"  ::arg().set({oldname}, {helptxt}) = {cxxdef};\n")
-    file.write('}\n\n')
+    file.write("}\n\n")
+
 
 def gen_cxx_oldstylesettingstobridgestruct(file, entries):
     """Generate C++ code the convert old-style settings to new-style struct"""
-    file.write('void pdns::settings::rec::oldStyleSettingsToBridgeStruct')
-    file.write('(Recursorsettings& settings)\n{\n')
+    file.write("void pdns::settings::rec::oldStyleSettingsToBridgeStruct")
+    file.write("(Recursorsettings& settings)\n{\n")
     for entry in entries:
-        if entry['type'] == LType.Command:
+        if entry["type"] == LType.Command:
             continue
-        if 'skip-yaml' in entry:
+        if "skip-yaml" in entry:
             continue
-        if 'skip-old' in entry:
+        if "skip-old" in entry:
             continue
-        rust_type = get_rust_type(entry['type'])
-        name = entry['name']
-        oldname = entry['oldname']
-        section = entry['section']
-        file.write(f'  settings.{section}.{name} = ')
-        if rust_type == 'bool':
+        rust_type = get_rust_type(entry["type"])
+        name = entry["name"]
+        oldname = entry["oldname"]
+        section = entry["section"]
+        file.write(f"  settings.{section}.{name} = ")
+        if rust_type == "bool":
             file.write(f'arg().mustDo("{oldname}")')
-        elif rust_type == 'u64':
+        elif rust_type == "u64":
             file.write(f'static_cast<uint64_t>(arg().asNum("{oldname}"))')
-        elif rust_type == 'f64':
+        elif rust_type == "f64":
             file.write(f'arg().asDouble("{oldname}")')
-        elif rust_type == 'String':
+        elif rust_type == "String":
             file.write(f'arg()["{oldname}"]')
-        elif rust_type == 'Vec<String>':
+        elif rust_type == "Vec<String>":
             file.write(f'getStrings("{oldname}")')
-        elif rust_type == 'Vec<ForwardZone>':
+        elif rust_type == "Vec<ForwardZone>":
             file.write(f'getForwardZones("{oldname}")')
-        elif rust_type == 'Vec<AuthZone>':
+        elif rust_type == "Vec<AuthZone>":
             file.write(f'getAuthZones("{oldname}")')
         else:
-            file.write(f'Unknown3 type {rust_type}\n')
-        file.write(';\n')
-    file.write('}\n\n')
+            file.write(f"Unknown3 type {rust_type}\n")
+        file.write(";\n")
+    file.write("}\n\n")
+
 
 def gen_cxx_oldkvtobridgestruct(file, entries):
     """Generate C++ code for oldKVToBridgeStruct"""
-    file.write('// Inefficient, but only meant to be used for one-time conversion purposes\n')
-    file.write('bool pdns::settings::rec::oldKVToBridgeStruct(std::string& key, ')
-    file.write('const std::string& value, ::rust::String& section, ::rust::String& fieldname, ')
-    file.write('::rust::String& type_name, pdns::rust::settings::rec::Value& rustvalue)')
-    file.write('{ // NOLINT(readability-function-cognitive-complexity)\n')
-    file.write('  if (const auto& newname = arg().isDeprecated(key); !newname.empty()) {\n')
-    file.write('    key = newname;\n')
-    file.write('  }\n')
+    file.write("// Inefficient, but only meant to be used for one-time conversion purposes\n")
+    file.write("bool pdns::settings::rec::oldKVToBridgeStruct(std::string& key, ")
+    file.write("const std::string& value, ::rust::String& section, ::rust::String& fieldname, ")
+    file.write("::rust::String& type_name, pdns::rust::settings::rec::Value& rustvalue)")
+    file.write("{ // NOLINT(readability-function-cognitive-complexity)\n")
+    file.write("  if (const auto& newname = arg().isDeprecated(key); !newname.empty()) {\n")
+    file.write("    key = newname;\n")
+    file.write("  }\n")
     for entry in entries:
-        if entry['type'] == LType.Command:
+        if entry["type"] == LType.Command:
             continue
-        if 'skip-yaml' in entry:
+        if "skip-yaml" in entry:
             continue
-        if 'skip-old' in entry:
+        if "skip-old" in entry:
             continue
-        rust_type = get_rust_type(entry['type'])
-        extra = ''
-        if entry['oldname'] == 'forward-zones-recurse':
-            extra = ', true'
-        name = entry['name']
-        section = entry['section']
-        oldname = entry['oldname']
+        rust_type = get_rust_type(entry["type"])
+        extra = ""
+        if entry["oldname"] == "forward-zones-recurse":
+            extra = ", true"
+        name = entry["name"]
+        section = entry["section"]
+        oldname = entry["oldname"]
         file.write(f'  if (key == "{oldname}") {{\n')
         file.write(f'    section = "{section}";\n')
         file.write(f'    fieldname = "{name}";\n')
         file.write(f'    type_name = "{rust_type}";\n')
-        if rust_type == 'bool':
-            file.write(f'    to_yaml(rustvalue.bool_val, value{extra});\n')
-            file.write('    return true;\n  }\n')
-        elif rust_type == 'u64':
-            file.write(f'    to_yaml(rustvalue.u64_val, value{extra});\n')
-            file.write('    return true;\n  }\n')
-        elif rust_type == 'f64':
-            file.write(f'    to_yaml(rustvalue.f64_val, value{extra});\n')
-            file.write('    return true;\n  }\n')
-        elif rust_type == 'String':
-            file.write(f'    to_yaml(rustvalue.string_val, value{extra});\n')
-            file.write('    return true;\n  }\n')
-        elif rust_type == 'Vec<String>':
-            file.write(f'    to_yaml(rustvalue.vec_string_val, value{extra});\n')
-            file.write('    return true;\n  }\n')
-        elif rust_type == 'Vec<ForwardZone>':
-            file.write(f'    to_yaml(rustvalue.vec_forwardzone_val, value{extra});\n')
-            file.write('    return true;\n  }\n')
-        elif rust_type == 'Vec<AuthZone>':
-            file.write(f'    to_yaml(rustvalue.vec_authzone_val, value{extra});\n')
-            file.write('    return true;\n  }\n')
+        if rust_type == "bool":
+            file.write(f"    to_yaml(rustvalue.bool_val, value{extra});\n")
+            file.write("    return true;\n  }\n")
+        elif rust_type == "u64":
+            file.write(f"    to_yaml(rustvalue.u64_val, value{extra});\n")
+            file.write("    return true;\n  }\n")
+        elif rust_type == "f64":
+            file.write(f"    to_yaml(rustvalue.f64_val, value{extra});\n")
+            file.write("    return true;\n  }\n")
+        elif rust_type == "String":
+            file.write(f"    to_yaml(rustvalue.string_val, value{extra});\n")
+            file.write("    return true;\n  }\n")
+        elif rust_type == "Vec<String>":
+            file.write(f"    to_yaml(rustvalue.vec_string_val, value{extra});\n")
+            file.write("    return true;\n  }\n")
+        elif rust_type == "Vec<ForwardZone>":
+            file.write(f"    to_yaml(rustvalue.vec_forwardzone_val, value{extra});\n")
+            file.write("    return true;\n  }\n")
+        elif rust_type == "Vec<AuthZone>":
+            file.write(f"    to_yaml(rustvalue.vec_authzone_val, value{extra});\n")
+            file.write("    return true;\n  }\n")
         else:
-            file.write(f'Unknown4 type {rust_type}\n')
-    file.write('  return false;\n')
-    file.write('}\n\n')
+            file.write(f"Unknown4 type {rust_type}\n")
+    file.write("  return false;\n")
+    file.write("}\n\n")
+
 
 def gen_cxx_brigestructtoldstylesettings(file, entries):
     """Generate C++ Code for bridgeStructToOldStyleSettings"""
-    file.write('void pdns::settings::rec::bridgeStructToOldStyleSettings')
-    file.write('(const Recursorsettings& settings)\n{\n')
+    file.write("void pdns::settings::rec::bridgeStructToOldStyleSettings")
+    file.write("(const Recursorsettings& settings)\n{\n")
     for entry in entries:
-        if entry['type'] == LType.Command:
+        if entry["type"] == LType.Command:
             continue
-        if 'skip-yaml' in entry:
+        if "skip-yaml" in entry:
             continue
-        if 'skip-old' in entry:
+        if "skip-old" in entry:
             continue
-        section = entry['section'].lower()
-        name = entry['name']
-        oldname = entry['oldname']
+        section = entry["section"].lower()
+        name = entry["name"]
+        oldname = entry["oldname"]
         file.write(f'  ::arg().set("{oldname}") = ')
-        file.write(f'to_arg(settings.{section}.{name});\n')
-    file.write('}\n')
+        file.write(f"to_arg(settings.{section}.{name});\n")
+    file.write("}\n")
+
 
 def gen_cxx(gendir, entries):
     """Generate the C++ code from the defs in table.py"""
-    with open(gendir + '/cxxsettings-generated.cc', mode='w', encoding="UTF-8") as file:
-        file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n\n')
+    with open(gendir + "/cxxsettings-generated.cc", mode="w", encoding="UTF-8") as file:
+        file.write("// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n\n")
         file.write('#include "arguments.hh"\n')
         file.write('#include "cxxsettings.hh"\n')
         file.write('#include "cxxsettings-private.hh"\n\n')
@@ -404,262 +434,275 @@ def gen_cxx(gendir, entries):
         gen_cxx_oldkvtobridgestruct(file, entries)
         gen_cxx_brigestructtoldstylesettings(file, entries)
 
+
 def is_value_rust_default(typ, value):
     """Is a value (represented as string) the same as its corresponding Rust default?"""
-    if typ == 'bool':
-        return value == 'false'
-    if typ == 'u64':
-        return value in ('0', '')
-    if typ == 'f64':
-        return value == '0.0'
-    if typ == 'String':
-        return value == ''
+    if typ == "bool":
+        return value == "false"
+    if typ == "u64":
+        return value in ("0", "")
+    if typ == "f64":
+        return value == "0.0"
+    if typ == "String":
+        return value == ""
     return False
 
+
 def gen_rust_vec_default_functions(name, typeName, defvalue):
     """Generate Rust code for the default handling of a vector for typeName"""
-    ret = f'// DEFAULT HANDLING for {name}\n'
-    ret += f'fn default_value_{name}() -> Vec<recsettings::{typeName}> {{\n'
+    ret = f"// DEFAULT HANDLING for {name}\n"
+    ret += f"fn default_value_{name}() -> Vec<recsettings::{typeName}> {{\n"
     ret += f'    let msg = "default value defined for `{name}\' should be valid YAML";'
-    ret += f'    let deserialized: Vec<recsettings::{typeName}> = serde_yaml::from_str({quote(defvalue)}).expect(msg);\n'
-    ret += f'    deserialized\n'
-    ret += '}\n'
-    ret += f'fn default_value_equal_{name}(value: &Vec<recsettings::{typeName}>)'
-    ret += '-> bool {\n'
-    ret += f'    let def = default_value_{name}();\n'
-    ret += '    &def == value\n'
-    ret += '}\n\n'
+    ret += (
+        f"    let deserialized: Vec<recsettings::{typeName}> = serde_yaml::from_str({quote(defvalue)}).expect(msg);\n"
+    )
+    ret += f"    deserialized\n"
+    ret += "}\n"
+    ret += f"fn default_value_equal_{name}(value: &Vec<recsettings::{typeName}>)"
+    ret += "-> bool {\n"
+    ret += f"    let def = default_value_{name}();\n"
+    ret += "    &def == value\n"
+    ret += "}\n\n"
     return ret
 
+
 # Example snippet generated
 # fn default_value_general_query_local_address() -> Vec<String> {
 #    vec![String::from("0.0.0.0"), ]
-#}
-#fn default_value_equal_general_query_local_address(value: &Vec<String>) -> bool {
+# }
+# fn default_value_equal_general_query_local_address(value: &Vec<String>) -> bool {
 #    let def = default_value_general_query_local_address();
 #    &def == value
-#}
+# }
 def gen_rust_stringvec_default_functions(entry, name):
     """Generate Rust code for the default handling of a vector for Strings"""
-    ret = f'// DEFAULT HANDLING for {name}\n'
-    ret += f'fn default_value_{name}() -> Vec<String> {{\n'
-    parts = re.split('[ \t,]+', entry['default'])
+    ret = f"// DEFAULT HANDLING for {name}\n"
+    ret += f"fn default_value_{name}() -> Vec<String> {{\n"
+    parts = re.split("[ \t,]+", entry["default"])
     if len(parts) > 0:
-        ret += '    vec![\n'
+        ret += "    vec![\n"
         for part in parts:
-            if part == '':
+            if part == "":
                 continue
-            ret += f'        String::from({quote(part)}),\n'
-        ret += '    ]\n'
+            ret += f"        String::from({quote(part)}),\n"
+        ret += "    ]\n"
     else:
-        ret  += '    vec![]\n'
-    ret += '}\n'
-    ret += f'fn default_value_equal_{name}(value: &Vec<String>) -> bool {{\n'
-    ret += f'    let def = default_value_{name}();\n'
-    ret += '    &def == value\n'
-    ret += '}\n\n'
+        ret += "    vec![]\n"
+    ret += "}\n"
+    ret += f"fn default_value_equal_{name}(value: &Vec<String>) -> bool {{\n"
+    ret += f"    let def = default_value_{name}();\n"
+    ret += "    &def == value\n"
+    ret += "}\n\n"
     return ret
 
+
 def gen_rust_default_functions(entry, name, rust_type):
     """Generate Rust code for the default handling"""
-    defvalue = entry['default']
-    if entry['type'] in listOfStringTypes:
+    defvalue = entry["default"]
+    if entry["type"] in listOfStringTypes:
         return gen_rust_stringvec_default_functions(entry, name)
-    if entry['type'] in listOfStructuredTypes:
-        baseName = list_to_base_type(entry['type'])
+    if entry["type"] in listOfStructuredTypes:
+        baseName = list_to_base_type(entry["type"])
         return gen_rust_vec_default_functions(name, baseName, defvalue)
-    ret = f'// DEFAULT HANDLING for {name}\n'
-    ret += f'fn default_value_{name}() -> {rust_type} {{\n'
+    ret = f"// DEFAULT HANDLING for {name}\n"
+    ret += f"fn default_value_{name}() -> {rust_type} {{\n"
     rustdef = f'env!("{defvalue}")' if isEnvVar(defvalue) else quote(defvalue)
     ret += f"    String::from({rustdef})\n"
-    ret += '}\n'
-    if rust_type == 'String':
-        rust_type = 'str'
-    ret += f'fn default_value_equal_{name}(value: &{rust_type})'
-    ret += '-> bool {\n'
-    ret += f'    value == default_value_{name}()\n'
-    ret += '}\n\n'
+    ret += "}\n"
+    if rust_type == "String":
+        rust_type = "str"
+    ret += f"fn default_value_equal_{name}(value: &{rust_type})"
+    ret += "-> bool {\n"
+    ret += f"    value == default_value_{name}()\n"
+    ret += "}\n\n"
     return ret
 
+
 def write_rust_field(file, entry, default_funcs):
     """Generate Rust code for a field with Serde annotations"""
-    rust_type = get_rust_type(entry['type'])
-    the_default = entry['default']
+    rust_type = get_rust_type(entry["type"])
+    the_default = entry["default"]
     is_rust_default = is_value_rust_default(rust_type, the_default)
     if is_rust_default:
         file.write('        #[serde(default, skip_serializing_if = "crate::is_default")]\n')
     else:
-        if entry['type'] == LType.Bool:
+        if entry["type"] == LType.Bool:
             file.write('        #[serde(default = "crate::Bool::<true>::value", ')
             file.write('skip_serializing_if = "crate::if_true")]\n')
-        elif entry['type'] == LType.Uint64:
+        elif entry["type"] == LType.Uint64:
             file.write(f'        #[serde(default = "crate::U64::<{the_default}>::value", ')
             file.write(f'skip_serializing_if = "crate::U64::<{the_default}>::is_equal")]\n')
         else:
-            basename = entry['section'] + '_' + entry['name']
+            basename = entry["section"] + "_" + entry["name"]
             file.write(f'        #[serde(default = "crate::default_value_{basename}", ')
             file.write(f'skip_serializing_if = "crate::default_value_equal_{basename}")]\n')
             default_funcs.append(gen_rust_default_functions(entry, basename, rust_type))
     file.write(f"        {entry['name']}: {rust_type},\n\n")
 
+
 def write_rust_section(file, section, entries, default_funcs):
     """Generate Rust code for a Section with Serde annotations"""
-    file.write(f'    // SECTION {section.capitalize()}\n')
-    file.write('    #[derive(Deserialize, Serialize, Debug, PartialEq)]\n')
-    file.write('    #[serde(deny_unknown_fields)]\n')
-    file.write(f'    pub struct {section.capitalize()} {{\n')
+    file.write(f"    // SECTION {section.capitalize()}\n")
+    file.write("    #[derive(Deserialize, Serialize, Debug, PartialEq)]\n")
+    file.write("    #[serde(deny_unknown_fields)]\n")
+    file.write(f"    pub struct {section.capitalize()} {{\n")
     for entry in entries:
-        if entry['section'] != section:
+        if entry["section"] != section:
             continue
-        if entry['type'] == LType.Command:
+        if entry["type"] == LType.Command:
             continue
-        if 'skip-yaml' in entry:
+        if "skip-yaml" in entry:
             continue
         write_rust_field(file, entry, default_funcs)
-    file.write(f'    }}\n    // END SECTION {section.capitalize()}\n\n')
+    file.write(f"    }}\n    // END SECTION {section.capitalize()}\n\n")
+
 
 #
 # Each section als has a Default implementation, so that a section with all entries having a default
 # value does not get generated into a yaml section. Such a trait looks like:
 #
-#impl Default for recsettings::ForwardZone {
+# impl Default for recsettings::ForwardZone {
 #    fn default() -> Self {
 #        let deserialized: recsettings::ForwardZone = serde_yaml::from_str("").unwrap();
 #        deserialized
 #    }
-#}
+# }
+
 
 def write_rust_default_trait_impl(file, section):
     """Generate Rust code for the default Trait for a section"""
-    file.write(f'impl Default for recsettings::{section.capitalize()} {{\n')
-    file.write('    fn default() -> Self {\n')
-    file.write('        let deserialized: recsettings::')
+    file.write(f"impl Default for recsettings::{section.capitalize()} {{\n")
+    file.write("    fn default() -> Self {\n")
+    file.write("        let deserialized: recsettings::")
     file.write(f'{section.capitalize()} = serde_yaml::from_str("").unwrap();\n')
-    file.write('        deserialized\n')
-    file.write('    }\n')
-    file.write('}\n\n')
+    file.write("        deserialized\n")
+    file.write("    }\n")
+    file.write("}\n\n")
+
 
 def write_validator(file, section, entries):
     """Generate Rust code for the Validator Trait for a section"""
-    file.write(f'impl Validate for recsettings::{section.capitalize()} {{\n')
-    file.write('    fn validate(&self) -> Result<(), ValidationError> {\n')
+    file.write(f"impl Validate for recsettings::{section.capitalize()} {{\n")
+    file.write("    fn validate(&self) -> Result<(), ValidationError> {\n")
     for entry in entries:
-        if entry['section'] != section:
+        if entry["section"] != section:
             continue
-        name = entry['name'].lower()
-        typ = entry['type']
+        name = entry["name"].lower()
+        typ = entry["type"]
         if typ == LType.ListSubnets:
-            validator = 'validate_subnet'
+            validator = "validate_subnet"
         elif typ == LType.ListSocketAddresses:
-            validator = 'validate_socket_address'
+            validator = "validate_socket_address"
         elif typ in listOfStructuredTypes:
-            validator = '|field, element| element.validate(field)'
+            validator = "|field, element| element.validate(field)"
         else:
             continue
         file.write(f'        let fieldname = "{section.lower()}.{name}".to_string();\n')
-        file.write(f'        validate_vec(&fieldname, &self.{name}, {validator})?;\n')
-    file.write(f'        validate_{section.lower()}(self)\n')
-    file.write('    }\n')
-    file.write('}\n\n')
+        file.write(f"        validate_vec(&fieldname, &self.{name}, {validator})?;\n")
+    file.write(f"        validate_{section.lower()}(self)\n")
+    file.write("    }\n")
+    file.write("}\n\n")
+
 
 def write_rust_merge_trait_impl(file, section, entries):
     """Generate Rust code for the Merge Trait for a section"""
-    file.write(f'impl Merge for recsettings::{section.capitalize()} {{\n')
-    file.write('    fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) {\n')
-    file.write('        if let Some(m) = map {\n')
+    file.write(f"impl Merge for recsettings::{section.capitalize()} {{\n")
+    file.write("    fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) {\n")
+    file.write("        if let Some(m) = map {\n")
     for entry in entries:
-        if entry['section'] != section:
+        if entry["section"] != section:
             continue
-        if 'skip-yaml' in entry:
+        if "skip-yaml" in entry:
             continue
-        rtype = get_rust_type(entry['type'])
-        name = entry['name']
+        rtype = get_rust_type(entry["type"])
+        name = entry["name"]
         file.write(f'            if m.contains_key("{name}") {{\n')
-        if rtype in ('bool', 'u64', 'f64', 'String'):
-            file.write(f'                rhs.{name}.clone_into(&mut self.{name});\n')
+        if rtype in ("bool", "u64", "f64", "String"):
+            file.write(f"                rhs.{name}.clone_into(&mut self.{name});\n")
         else:
             file.write(f'                if is_overriding(m, "{name}") || ')
-            file.write(f'self.{name} == DEFAULT_CONFIG.{section}.{name} {{\n')
-            file.write(f'                    self.{name}.clear();\n')
-            file.write('                }\n')
-            file.write(f'                merge_vec(&mut self.{name}, &mut rhs.{name});\n')
-        file.write('            }\n')
-    file.write('        }\n')
-    file.write('    }\n')
-    file.write('}\n\n')
+            file.write(f"self.{name} == DEFAULT_CONFIG.{section}.{name} {{\n")
+            file.write(f"                    self.{name}.clear();\n")
+            file.write("                }\n")
+            file.write(f"                merge_vec(&mut self.{name}, &mut rhs.{name});\n")
+        file.write("            }\n")
+    file.write("        }\n")
+    file.write("    }\n")
+    file.write("}\n\n")
+
 
 def gen_rust(srcdir, entries):
     """Generate Rust code all entries"""
     def_functions = []
     sections = {}
-    with open(srcdir + '/rust/src/lib.rs', mode='w', encoding='UTF-8') as file:
-        file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n')
-        file.write('// START INCLUDE rust-preamble-in.rs\n')
-        with open(srcdir + '/rust-preamble-in.rs', mode='r', encoding='UTF-8') as pre:
+    with open(srcdir + "/rust/src/lib.rs", mode="w", encoding="UTF-8") as file:
+        file.write("// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n")
+        file.write("// START INCLUDE rust-preamble-in.rs\n")
+        with open(srcdir + "/rust-preamble-in.rs", mode="r", encoding="UTF-8") as pre:
             file.write(pre.read())
-            file.write('// END INCLUDE rust-preamble-in.rs\n\n')
+            file.write("// END INCLUDE rust-preamble-in.rs\n\n")
 
         file.write('#[cxx::bridge(namespace = "pdns::rust::settings::rec")]\n')
-        file.write('mod recsettings {\n')
-        with open(srcdir + '/rust-bridge-in.rs', mode='r', encoding='UTF-8') as bridge:
-            file.write('    // START INCLUDE rust-bridge-in.rs\n')
+        file.write("mod recsettings {\n")
+        with open(srcdir + "/rust-bridge-in.rs", mode="r", encoding="UTF-8") as bridge:
+            file.write("    // START INCLUDE rust-bridge-in.rs\n")
             for line in bridge:
-                file.write('    ' + line)
+                file.write("    " + line)
 
-        file.write('    // END INCLUDE rust-bridge-in.rs\n\n')
+        file.write("    // END INCLUDE rust-bridge-in.rs\n\n")
         for entry in entries:
-            if entry['section'] == 'commands':
+            if entry["section"] == "commands":
                 continue
-            sections[entry['section']] = entry['section']
+            sections[entry["section"]] = entry["section"]
 
         for section in sections:
             write_rust_section(file, section, entries, def_functions)
 
-        file.write('    #[derive(Serialize, Deserialize, Debug)]\n')
-        file.write('    #[serde(deny_unknown_fields)]\n')
-        file.write('    pub struct Recursorsettings {\n')
+        file.write("    #[derive(Serialize, Deserialize, Debug)]\n")
+        file.write("    #[serde(deny_unknown_fields)]\n")
+        file.write("    pub struct Recursorsettings {\n")
         for section in sections:
             file.write('        #[serde(default, skip_serializing_if = "crate::is_default")]\n')
-            file.write(f'        {section.lower()}: {section.capitalize()},\n')
-        file.write('}  // End of generated structs\n')
-        file.write('}\n')
+            file.write(f"        {section.lower()}: {section.capitalize()},\n")
+        file.write("}  // End of generated structs\n")
+        file.write("}\n")
 
         for section in sections:
             write_rust_default_trait_impl(file, section)
-        write_rust_default_trait_impl(file, 'Recursorsettings')
+        write_rust_default_trait_impl(file, "Recursorsettings")
 
         for section in sections:
             write_validator(file, section, entries)
 
-        file.write('impl crate::recsettings::Recursorsettings {\n')
-        file.write('    fn validate(&self) -> Result<(), ValidationError> {\n')
+        file.write("impl crate::recsettings::Recursorsettings {\n")
+        file.write("    fn validate(&self) -> Result<(), ValidationError> {\n")
         for section in sections:
-            file.write(f'        self.{section.lower()}.validate()?;\n')
-        file.write('        Ok(())\n')
-        file.write('    }\n')
-        file.write('}\n\n')
+            file.write(f"        self.{section.lower()}.validate()?;\n")
+        file.write("        Ok(())\n")
+        file.write("    }\n")
+        file.write("}\n\n")
 
         for section in sections:
             write_rust_merge_trait_impl(file, section, entries)
 
-        file.write('impl Merge for crate::recsettings::Recursorsettings {\n')
-        file.write('    fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) {\n')
-        file.write('        if let Some(m) = map {\n')
+        file.write("impl Merge for crate::recsettings::Recursorsettings {\n")
+        file.write("    fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) {\n")
+        file.write("        if let Some(m) = map {\n")
         for section in sections:
             file.write(f'            if let Some(s) = m.get("{section}") {{\n')
-            file.write('                if s.is_mapping() {\n')
-            file.write((f'                    self.{section}.merge(&mut rhs.{section},'
-                       ' s.as_mapping());\n'))
-            file.write('                }\n')
-            file.write('            }\n')
-        file.write('        }\n')
-        file.write('    }\n')
-        file.write('}\n\n')
+            file.write("                if s.is_mapping() {\n")
+            file.write((f"                    self.{section}.merge(&mut rhs.{section}, s.as_mapping());\n"))
+            file.write("                }\n")
+            file.write("            }\n")
+        file.write("        }\n")
+        file.write("    }\n")
+        file.write("}\n\n")
 
         for entry in def_functions:
             file.write(entry)
         file.close()
 
+
 def gen_docs_meta(file, entry, name, is_tuple):
     """Write .. versionadded:: and related entries"""
     if name in entry:
@@ -668,136 +711,139 @@ def gen_docs_meta(file, entry, name, is_tuple):
             val = [val]
         for vers in val:
             if is_tuple:
-                file.write(f'.. {name}:: {vers[0]}\n\n')
-                file.write(f'  {vers[1].strip()}\n')
+                file.write(f".. {name}:: {vers[0]}\n\n")
+                file.write(f"  {vers[1].strip()}\n")
             else:
-                file.write(f'.. {name}:: {vers}\n')
+                file.write(f".. {name}:: {vers}\n")
+
 
 def gen_oldstyle_docs(srcdir, entries):
     """Write old style docs"""
-    with open(srcdir + '/../docs/settings.rst', mode='w', encoding='UTF-8') as file:
-        file.write('.. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n')
-        file.write('   START INCLUDE docs-old-preamble-in.rst\n\n')
-        with open(srcdir + '/docs-old-preamble-in.rst', mode='r', encoding='UTF-8') as pre:
+    with open(srcdir + "/../docs/settings.rst", mode="w", encoding="UTF-8") as file:
+        file.write(".. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n")
+        file.write("   START INCLUDE docs-old-preamble-in.rst\n\n")
+        with open(srcdir + "/docs-old-preamble-in.rst", mode="r", encoding="UTF-8") as pre:
             file.write(pre.read())
-            file.write('.. END INCLUDE docs-old-preamble-in.rst\n\n')
+            file.write(".. END INCLUDE docs-old-preamble-in.rst\n\n")
 
         for entry in entries:
-            if entry['type'] == LType.Command:
+            if entry["type"] == LType.Command:
                 continue
-            if entry['doc'].strip() == 'SKIP':
+            if entry["doc"].strip() == "SKIP":
                 continue
-            if 'skip-old' in entry:
+            if "skip-old" in entry:
                 continue
-            oldname = entry['oldname']
-            section = entry['section']
-            file.write(f'.. _setting-{oldname}:\n\n')
-            file.write(f'``{oldname}``\n')
-            dots = '~' * (len(entry['oldname']) + 4)
-            file.write(f'{dots}\n')
-            gen_docs_meta(file, entry, 'versionadded', False)
-            gen_docs_meta(file, entry, 'versionchanged', True)
-            gen_docs_meta(file, entry, 'deprecated', True)
-            if 'doc-rst' in entry:
-                file.write(entry['doc-rst'].strip())
-                file.write('\n')
-            file.write('\n')
-            typ = get_olddoc_typename(entry['type'])
-            file.write(f'-  {typ}\n')
-            if 'docdefault' in entry:
+            oldname = entry["oldname"]
+            section = entry["section"]
+            file.write(f".. _setting-{oldname}:\n\n")
+            file.write(f"``{oldname}``\n")
+            dots = "~" * (len(entry["oldname"]) + 4)
+            file.write(f"{dots}\n")
+            gen_docs_meta(file, entry, "versionadded", False)
+            gen_docs_meta(file, entry, "versionchanged", True)
+            gen_docs_meta(file, entry, "deprecated", True)
+            if "doc-rst" in entry:
+                file.write(entry["doc-rst"].strip())
+                file.write("\n")
+            file.write("\n")
+            typ = get_olddoc_typename(entry["type"])
+            file.write(f"-  {typ}\n")
+            if "docdefault" in entry:
                 file.write(f"-  Default: {entry['docdefault']}\n\n")
             else:
-                file.write((f"-  Default: "
-                            f"{get_default_olddoc_value(entry['type'], entry['default'])}\n\n"))
-            if 'skip-yaml' in entry:
-                file.write('- YAML setting does not exist\n\n')
+                file.write((f"-  Default: {get_default_olddoc_value(entry['type'], entry['default'])}\n\n"))
+            if "skip-yaml" in entry:
+                file.write("- YAML setting does not exist\n\n")
             else:
                 file.write(f"- YAML setting: :ref:`setting-yaml-{section}.{entry['name']}`\n\n")
-            if 'runtime' in entry:
-                runtime = entry['runtime']
+            if "runtime" in entry:
+                runtime = entry["runtime"]
                 if not isinstance(runtime, list):
                     runtime = [runtime]
                 li = []
                 for v in runtime:
-                    if v == 'reload-yaml':
-                         continue
-                    li.append('``' + v + '``')
+                    if v == "reload-yaml":
+                        continue
+                    li.append("``" + v + "``")
                 file.write(f"- Runtime modifiable using ``rec_control`` {', '.join(f'{w}' for w in li)}\n\n")
-            file.write(entry['doc'].strip())
-            file.write('\n\n')
+            file.write(entry["doc"].strip())
+            file.write("\n\n")
+
 
 def fixxrefs(entries, arg):
     """Docs in table refer to old style names, we modify them to ref to new style"""
-    matches = re.findall(':ref:`setting-(.*?)`', arg)
+    matches = re.findall(":ref:`setting-(.*?)`", arg)
     # We want to replace longest match first, to avoid a short match modifying a long one
-    matches = sorted(matches, key = lambda x: -len(x))
+    matches = sorted(matches, key=lambda x: -len(x))
     for match in matches:
         for entry in entries:
-            if entry['oldname'] == match:
-                key = ':ref:`setting-' + match
-                repl = ':ref:`setting-yaml-' + entry['section'] + '.' + entry['name']
+            if entry["oldname"] == match:
+                key = ":ref:`setting-" + match
+                repl = ":ref:`setting-yaml-" + entry["section"] + "." + entry["name"]
                 arg = arg.replace(key, repl)
     return arg
 
+
 def gen_newstyle_docs(srcdir, argentries):
     """Write new style docs"""
-    entries = sorted(argentries, key = lambda entry: [entry['section'], entry['name']])
-    with open(srcdir + '/../docs/yamlsettings.rst', 'w', encoding='utf-8') as file:
-        file.write('.. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n')
-        file.write('   START INCLUDE docs-new-preamble-in.rst\n\n')
-        with open(srcdir + '/docs-new-preamble-in.rst', mode='r', encoding='utf-8') as pre:
+    entries = sorted(argentries, key=lambda entry: [entry["section"], entry["name"]])
+    with open(srcdir + "/../docs/yamlsettings.rst", "w", encoding="utf-8") as file:
+        file.write(".. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n")
+        file.write("   START INCLUDE docs-new-preamble-in.rst\n\n")
+        with open(srcdir + "/docs-new-preamble-in.rst", mode="r", encoding="utf-8") as pre:
             file.write(pre.read())
-            file.write('.. END INCLUDE docs-new-preamble-in.rst\n\n')
+            file.write(".. END INCLUDE docs-new-preamble-in.rst\n\n")
 
         for entry in entries:
-            if entry['type'] == LType.Command:
+            if entry["type"] == LType.Command:
                 continue
-            if entry['doc'].strip() == 'SKIP':
+            if entry["doc"].strip() == "SKIP":
                 continue
-            if 'skip-yaml' in entry:
+            if "skip-yaml" in entry:
                 continue
-            section = entry['section']
-            name = entry['name']
-            fullname = section + '.' + name
-            file.write(f'.. _setting-yaml-{fullname}:\n\n')
-            file.write(f'``{fullname}``\n')
-            dots = '^' * (len(fullname) + 4)
-            file.write(f'{dots}\n')
-            gen_docs_meta(file, entry, 'versionadded', False)
-            gen_docs_meta(file, entry, 'versionchanged', True)
-            gen_docs_meta(file, entry, 'deprecated', True)
-            if 'doc-rst' in entry:
-                file.write(fixxrefs(entries, entry['doc-rst'].strip()))
-                file.write('\n')
-            file.write('\n')
+            section = entry["section"]
+            name = entry["name"]
+            fullname = section + "." + name
+            file.write(f".. _setting-yaml-{fullname}:\n\n")
+            file.write(f"``{fullname}``\n")
+            dots = "^" * (len(fullname) + 4)
+            file.write(f"{dots}\n")
+            gen_docs_meta(file, entry, "versionadded", False)
+            gen_docs_meta(file, entry, "versionchanged", True)
+            gen_docs_meta(file, entry, "deprecated", True)
+            if "doc-rst" in entry:
+                file.write(fixxrefs(entries, entry["doc-rst"].strip()))
+                file.write("\n")
+            file.write("\n")
             file.write(f"-  {get_newdoc_typename(entry['type'])}\n")
-            if 'docdefault' in entry:
+            if "docdefault" in entry:
                 file.write(f"-  Default: {entry['docdefault']}\n\n")
             else:
-                file.write((f"-  Default: "
-                            f"{get_default_newdoc_value(entry['type'], entry['default'])}\n\n"))
-            if 'skip-old' in entry:
+                file.write((f"-  Default: {get_default_newdoc_value(entry['type'], entry['default'])}\n\n"))
+            if "skip-old" in entry:
                 file.write(f"- {entry['skip-old']}\n\n")
             else:
                 file.write(f"- Old style setting: :ref:`setting-{entry['oldname']}`\n\n")
-            if 'runtime' in entry:
-                runtime = entry['runtime']
+            if "runtime" in entry:
+                runtime = entry["runtime"]
                 if not isinstance(runtime, list):
                     runtime = [runtime]
                 li = []
                 for v in runtime:
-                    vv = '``' + v + '``'
-                    if v == 'reload-yaml':
-                         vv = 'since 5.2.0: ' + vv
+                    vv = "``" + v + "``"
+                    if v == "reload-yaml":
+                        vv = "since 5.2.0: " + vv
                     li.append(vv)
                 file.write(f"- Runtime modifiable using ``rec_control`` {', '.join(f'{w}' for w in li)}\n\n")
-            if 'doc-new' in entry:
-                file.write(fixxrefs(entries, entry['doc-new'].strip()))
+            if "doc-new" in entry:
+                file.write(fixxrefs(entries, entry["doc-new"].strip()))
             else:
-                file.write(fixxrefs(entries, entry['doc'].strip()))
-            file.write('\n\n')
+                file.write(fixxrefs(entries, entry["doc"].strip()))
+            file.write("\n\n")
+
+
+RUNTIME = "*runtime determined*"
 
-RUNTIME = '*runtime determined*'
 
 def unlinkMissingOK(path):
     try:
@@ -805,10 +851,11 @@ def unlinkMissingOK(path):
     except FileNotFoundError:
         pass
 
+
 def generate():
     """Read table, validate and generate C++, Rust and .rst files"""
-    srcdir = '.'
-    gendir = '.'
+    srcdir = "."
+    gendir = "."
     if len(sys.argv) == 3:
         print("Generate: using srcdir and gendir from arguments")
         srcdir = sys.argv[1]
@@ -819,29 +866,28 @@ def generate():
     print("Generate gendir: " + gendir + " = " + os.path.realpath(gendir))
 
     # read table
-    with open(srcdir + '/table.py', mode='r', encoding="utf-8") as file:
+    with open(srcdir + "/table.py", mode="r", encoding="utf-8") as file:
         entries = eval(file.read())
 
     for entry in entries:
-        the_oldname = entry['name'].replace('_', '-')
-        if 'oldname' in entry:
-            if entry['oldname'] == the_oldname:
+        the_oldname = entry["name"].replace("_", "-")
+        if "oldname" in entry:
+            if entry["oldname"] == the_oldname:
                 sys.stderr.write(f"Redundant old name {entry['oldname']}\n")
         else:
-            entry['oldname'] = the_oldname
+            entry["oldname"] = the_oldname
 
     dupcheck1 = {}
     dupcheck2 = {}
     for entry in entries:
-        if entry['oldname'] in dupcheck1:
+        if entry["oldname"] in dupcheck1:
             sys.stderr.write(f"duplicate entries with oldname = {entry['oldname']}\n")
             sys.exit(1)
-        if entry['section'] + '.' + entry['name'] in dupcheck2:
-            sys.stderr.write((f"duplicate entries with section.name = "
-                              f"{entry['section']}.{ entry['name']}\n"))
+        if entry["section"] + "." + entry["name"] in dupcheck2:
+            sys.stderr.write((f"duplicate entries with section.name = {entry['section']}.{entry['name']}\n"))
             sys.exit(1)
-        dupcheck1[entry['oldname']] = True
-        dupcheck2[entry['section'] + '.' + entry['name']] = True
+        dupcheck1[entry["oldname"]] = True
+        dupcheck2[entry["section"] + "." + entry["name"]] = True
     # And generate C++, Rust and docs code based on table
     # C++ code goes int build dir
     gen_cxx(gendir, entries)
@@ -849,22 +895,23 @@ def generate():
     # with mixed sources both in build and src dir
     gen_rust(srcdir, entries)
     # Avoid generating doc files in a sdist based build
-    if os.path.isdir(srcdir + '/../docs'):
+    if os.path.isdir(srcdir + "/../docs"):
         gen_oldstyle_docs(srcdir, entries)
         gen_newstyle_docs(srcdir, entries)
     # Remove cxx generated files, they need to be re-generated after a table change and the rust dependency tracking does
     # not do that in some cases.
-    unlinkMissingOK(Path(gendir, 'rust', 'librecrust.a'))
-    unlinkMissingOK(Path(gendir, 'rust', 'lib.rs.h'))
-    unlinkMissingOK(Path(gendir, 'rust', 'web.rs.h'))
-    unlinkMissingOK(Path(gendir, 'rust', 'cxx.h'))
-    unlinkMissingOK(Path(gendir, 'rust', 'misc.rs.h'))
+    unlinkMissingOK(Path(gendir, "rust", "librecrust.a"))
+    unlinkMissingOK(Path(gendir, "rust", "lib.rs.h"))
+    unlinkMissingOK(Path(gendir, "rust", "web.rs.h"))
+    unlinkMissingOK(Path(gendir, "rust", "cxx.h"))
+    unlinkMissingOK(Path(gendir, "rust", "misc.rs.h"))
     # Path.walk exists only in very recent versions of Python
     # With meson, target is in toplevel build dir
     # With autotools, target exists in rec-rust-lib/rust and this Python script is executed with cwd rec-rust-lib
-    for topdir in ['target', 'rust/target']:
+    for topdir in ["target", "rust/target"]:
         for root, dirs, files in os.walk(topdir, topdown=False):
             for name in files:
                 os.remove(os.path.join(root, name))
 
+
 generate()
index 94109d423614db222f0fbe1737d2a1ec41c441a2..7b0e902ba57889e1a1a81992f43286addbc5b83e 100644 (file)
 
 [
     {
-        'name' : 'aggressive_nsec_cache_size',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '100000',
-        'help' : 'The number of records to cache in the aggressive cache. If set to a value greater than 0, and DNSSEC processing or validation is enabled, the recursor will cache NSEC and NSEC3 records to generate negative answers, as defined in rfc8198',
-        'doc' : '''
+        "name": "aggressive_nsec_cache_size",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "100000",
+        "help": "The number of records to cache in the aggressive cache. If set to a value greater than 0, and DNSSEC processing or validation is enabled, the recursor will cache NSEC and NSEC3 records to generate negative answers, as defined in rfc8198",
+        "doc": """
 The number of records to cache in the aggressive cache. If set to a value greater than 0, the recursor will cache NSEC and NSEC3 records to generate negative answers, as defined in :rfc:`8198`.
 To use this, DNSSEC processing or validation must be enabled by setting :ref:`setting-dnssec` to ``process``, ``log-fail`` or ``validate``.
''',
-        'versionadded': '4.5.0',
-        'runtime': 'set-max-aggr-nsec-cache-size',
""",
+        "versionadded": "4.5.0",
+        "runtime": "set-max-aggr-nsec-cache-size",
     },
     {
-        'name' : 'aggressive_cache_min_nsec3_hit_ratio',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '2000',
-        'help' : 'The minimum expected hit ratio to store NSEC3 records into the aggressive cache',
-        'doc' : '''
+        "name": "aggressive_cache_min_nsec3_hit_ratio",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "2000",
+        "help": "The minimum expected hit ratio to store NSEC3 records into the aggressive cache",
+        "doc": """
 The limit for which to put NSEC3 records into the aggressive cache.
 A value of ``n`` means that an NSEC3 record is only put into the aggressive cache if the estimated probability of a random name hitting the NSEC3 record is higher than ``1/n``.
 A higher ``n`` will cause more records to be put into the aggressive cache, e.g. a value of 4000 will cause records to be put in the aggressive cache even if the estimated probability of hitting them is twice as low as would be the case for ``n=2000``.
@@ -56,16 +56,16 @@ A value of 0 means no NSEC3 records will be put into the aggressive cache.
 
 For large zones the effectiveness of the NSEC3 cache is reduced since each NSEC3 record only covers a randomly distributed subset of all possible names.
 This setting avoids doing unnecessary work for such large zones.
''',
-        'versionadded' : '4.9.0',
""",
+        "versionadded": "4.9.0",
     },
     {
-        'name' : 'allow_from',
-        'section' : 'incoming',
-        'type' : LType.ListSubnets,
-        'default' : '127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10',
-        'help' : 'If set, only allow these comma separated netmasks to recurse',
-        'doc' : '''
+        "name": "allow_from",
+        "section": "incoming",
+        "type": LType.ListSubnets,
+        "default": "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10",
+        "help": "If set, only allow these comma separated netmasks to recurse",
+        "doc": """
 Netmasks (both IPv4 and IPv6) that are allowed to use the server.
 The default allows access only from :rfc:`1918` private IP addresses.
 An empty value means no checking is done, all clients are allowed.
@@ -75,20 +75,20 @@ Questions from IP addresses not listed here are ignored and do not get an answer
 When the Proxy Protocol is enabled (see :ref:`setting-proxy-protocol-from`), the recursor will check the address of the client IP advertised in the Proxy Protocol header instead of the one of the proxy.
 
 Note that specifying an IP address without a netmask uses an implicit netmask of /32 or /128.
''',
-        'runtime': ['reload-acls'],
""",
+        "runtime": ["reload-acls"],
     },
     {
-        'name' : 'allow_from_file',
-        'section' : 'incoming',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'If set, load allowed netmasks from this file',
-        'doc' : '''
+        "name": "allow_from_file",
+        "section": "incoming",
+        "type": LType.String,
+        "default": "",
+        "help": "If set, load allowed netmasks from this file",
+        "doc": """
 Like :ref:`setting-allow-from`, except reading from file.
 Overrides the :ref:`setting-allow-from` setting. To use this feature, supply one netmask per line, with optional comments preceded by a '#'.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Like :ref:`setting-allow-from`, except reading a sequence of `Subnet`_ from file.
 Overrides the :ref:`setting-allow-from` setting. Example content of th specified file:
 
@@ -97,38 +97,38 @@ Overrides the :ref:`setting-allow-from` setting. Example content of th specified
  - 127.0.0.1
  - ::1
 
''',
-        'runtime': ['reload-acls'],
""",
+        "runtime": ["reload-acls"],
     },
     {
-        'name' : 'allow_notify_for',
-        'section' : 'incoming',
-        'type' : LType.ListStrings,
-        'default' : '',
-        'help' : 'If set, NOTIFY requests for these zones will be allowed',
-        'doc' : '''
+        "name": "allow_notify_for",
+        "section": "incoming",
+        "type": LType.ListStrings,
+        "default": "",
+        "help": "If set, NOTIFY requests for these zones will be allowed",
+        "doc": """
 Domain names specified in this list are used to permit incoming
 NOTIFY operations to wipe any cache entries that match the domain
 name. If this list is empty, all NOTIFY operations will be ignored.
 Matching is done using suffix matching, it is allowed to NOTIFY a subdomain of a listed domain.
''',
-        'versionadded': '4.6.0',
-        'runtime': ['reload-acls'],
""",
+        "versionadded": "4.6.0",
+        "runtime": ["reload-acls"],
     },
     {
-        'name' : 'allow_notify_for_file',
-        'section' : 'incoming',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'If set, load NOTIFY-allowed zones from this file',
-        'doc' : '''
+        "name": "allow_notify_for_file",
+        "section": "incoming",
+        "type": LType.String,
+        "default": "",
+        "help": "If set, load NOTIFY-allowed zones from this file",
+        "doc": """
 Like :ref:`setting-allow-notify-for`, except reading from file. To use this
 feature, supply one domain name per line, with optional comments
 preceded by a '#'.
 
 NOTIFY-allowed zones can also be specified using :ref:`setting-forward-zones-file`.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Like :ref:`setting-allow-notify-for`, except reading a sequence of names from file. Example contents of specified file:
 
 .. code-block:: yaml
@@ -136,17 +136,17 @@ Like :ref:`setting-allow-notify-for`, except reading a sequence of names from fi
  - example.com
  - example.org
 
''',
-        'versionadded': '4.6.0',
-        'runtime': ['reload-acls'],
""",
+        "versionadded": "4.6.0",
+        "runtime": ["reload-acls"],
     },
     {
-        'name' : 'allow_notify_from',
-        'section' : 'incoming',
-        'type' : LType.ListSubnets,
-        'default' : '',
-        'help' : 'If set, NOTIFY requests from these comma separated netmasks will be allowed',
-        'doc' : '''
+        "name": "allow_notify_from",
+        "section": "incoming",
+        "type": LType.ListSubnets,
+        "default": "",
+        "help": "If set, NOTIFY requests from these comma separated netmasks will be allowed",
+        "doc": """
 Netmasks (both IPv4 and IPv6) that are allowed to issue NOTIFY operations
 to the server.  NOTIFY operations from IP addresses not listed here are
 ignored and do not get an answer.
@@ -163,8 +163,8 @@ will be accepted and used to wipe any cache entries whose zones match
 the zone specified in the NOTIFY operation, but only if that zone (or
 one of its parents) is included in :ref:`setting-allow-notify-for`,
 :ref:`setting-allow-notify-for-file`, or :ref:`setting-forward-zones-file` with a '^' prefix.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Subnets (both IPv4 and IPv6) that are allowed to issue NOTIFY operations
 to the server.  NOTIFY operations from IP addresses not listed here are
 ignored and do not get an answer.
@@ -181,115 +181,115 @@ will be accepted and used to initiate a freshness check for an RPZ zone or wipe
 the zone specified in the NOTIFY operation, but only if that zone (or
 one of its parents) is included in :ref:`setting-allow-notify-for`,
 :ref:`setting-allow-notify-for-file`, or :ref:`setting-forward-zones-file` with a ``allow_notify`` set to ``true``.
''',
-        'versionadded': '4.6.0',
-        'runtime': ['reload-acls'],
""",
+        "versionadded": "4.6.0",
+        "runtime": ["reload-acls"],
     },
     {
-        'name' : 'allow_notify_from_file',
-        'section' : 'incoming',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'If set, load NOTIFY-allowed netmasks from this file',
-        'doc' : '''
+        "name": "allow_notify_from_file",
+        "section": "incoming",
+        "type": LType.String,
+        "default": "",
+        "help": "If set, load NOTIFY-allowed netmasks from this file",
+        "doc": """
 Like :ref:`setting-allow-notify-from`, except reading from file. To use this
 feature, supply one netmask per line, with optional comments preceded
 by a '#'.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Like :ref:`setting-allow-notify-from`, except reading a sequence of `Subnet`_ from file.
''',
-        'versionadded': '4.6.0',
-        'runtime': ['reload-acls'],
""",
+        "versionadded": "4.6.0",
+        "runtime": ["reload-acls"],
     },
     {
-        'name' : 'allow_no_rd',
-        'section' : 'incoming',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Allow \'no recursion desired (RD=0)\' queries.',
-        'doc' : '''
+        "name": "allow_no_rd",
+        "section": "incoming",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Allow 'no recursion desired (RD=0)' queries.",
+        "doc": """
 Allow ``no recursion desired (RD=0) queries`` to query cache contents.
 If not set (the default), these queries are answered with rcode ``Refused``.
''',
-    'versionadded': '5.0.0'
""",
+        "versionadded": "5.0.0",
     },
     {
-        'name' : 'any_to_tcp',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Answer ANY queries with tc=1, shunting to TCP',
-        'doc' : '''
+        "name": "any_to_tcp",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Answer ANY queries with tc=1, shunting to TCP",
+        "doc": """
 Answer questions for the ANY type on UDP with a truncated packet that refers the remote client to TCP.
 Useful for mitigating ANY reflection attacks.
''',
-    'versionchanged': ('5.4.0', 'Default is enabled now, was disabled before 5.4.0'),
""",
+        "versionchanged": ("5.4.0", "Default is enabled now, was disabled before 5.4.0"),
     },
     {
-        'name' : 'any_to_tcp',
-        'oldname': 'out-any-to-tcp',
-        'section' : 'outgoing',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Use TCP for ANY queries to authoritative servers',
-        'doc' : '''
+        "name": "any_to_tcp",
+        "oldname": "out-any-to-tcp",
+        "section": "outgoing",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Use TCP for ANY queries to authoritative servers",
+        "doc": """
 Send out requests with qtype `ANY` using TCP.
''',
-    'versionadded': '5.4.0',
""",
+        "versionadded": "5.4.0",
     },
     {
-        'name' : 'allow_trust_anchor_query',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Allow queries for trustanchor.server CH TXT and negativetrustanchor.server CH TXT',
-        'doc' : '''
+        "name": "allow_trust_anchor_query",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Allow queries for trustanchor.server CH TXT and negativetrustanchor.server CH TXT",
+        "doc": """
 Allow ``trustanchor.server CH TXT`` and ``negativetrustanchor.server CH TXT`` queries to view the configured :doc:`DNSSEC <dnssec>` (negative) trust anchors.
''',
-    'versionadded': '4.3.0'
""",
+        "versionadded": "4.3.0",
     },
     {
-        'name' : 'api_dir',
-        'section' : 'webservice',
-        'oldname' : 'api-config-dir',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Directory where REST API stores config and zones',
-        'doc' : '''
+        "name": "api_dir",
+        "section": "webservice",
+        "oldname": "api-config-dir",
+        "type": LType.String,
+        "default": "",
+        "help": "Directory where REST API stores config and zones",
+        "doc": """
 Directory where the REST API stores its configuration and zones.
 For configuration updates to work, :ref:`setting-include-dir` should have the same value when using old-style settings.
 When using YAML settings :ref:`setting-yaml-recursor.include_dir` and :ref:`setting-yaml-webservice.api_dir` must have a different value.
''',
-    'versionadded': '4.0.0'
-     },
-    {
-        'name' : 'api_key',
-        'section' : 'webservice',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Static pre-shared authentication key for access to the REST API',
-        'doc' : '''
""",
+        "versionadded": "4.0.0",
+    },
+    {
+        "name": "api_key",
+        "section": "webservice",
+        "type": LType.String,
+        "default": "",
+        "help": "Static pre-shared authentication key for access to the REST API",
+        "doc": """
 Static pre-shared authentication key for access to the REST API. Since 4.6.0 the key can be hashed and salted using ``rec_control hash-password`` instead of being stored in the configuration in plaintext, but the plaintext version is still supported.
''',
-        'versionadded': '4.0.0',
-        'versionchanged': ('4.6.0', 'This setting now accepts a hashed and salted version.')
""",
+        "versionadded": "4.0.0",
+        "versionchanged": ("4.6.0", "This setting now accepts a hashed and salted version."),
     },
     {
-        'name' : 'auth_zones',
-        'section' : 'recursor',
-        'type' : LType.ListAuthZones,
-        'default' : '',
-        'help' : 'Zones for which we have authoritative data, comma separated domain=file pairs',
-        'doc' : '''
+        "name": "auth_zones",
+        "section": "recursor",
+        "type": LType.ListAuthZones,
+        "default": "",
+        "help": "Zones for which we have authoritative data, comma separated domain=file pairs",
+        "doc": """
 Zones read from these files (in BIND format) are served authoritatively (but without the AA bit set in responses).
 DNSSEC is not supported. Example:
 
 .. code-block:: none
 
  auth-zones=example.org=/var/zones/example.org, powerdns.com=/var/zones/powerdns.com
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Zones read from these files (in BIND format) are served authoritatively (but without the AA bit set in responses).
 DNSSEC is not supported. Example:
 
@@ -301,83 +301,83 @@ DNSSEC is not supported. Example:
         file: /var/zones/example.org
       - zone: powerdns.com
         file: /var/zones/powerdns.com
''',
-        'runtime': ['reload-zones'],
""",
+        "runtime": ["reload-zones"],
     },
     {
-        'name' : 'interval',
-        'section' : 'carbon',
-        'oldname' : 'carbon-interval',
-        'type' : LType.Uint64,
-        'default' : '30',
-        'help' : 'Number of seconds between carbon (graphite) updates',
-        'doc' : '''
+        "name": "interval",
+        "section": "carbon",
+        "oldname": "carbon-interval",
+        "type": LType.Uint64,
+        "default": "30",
+        "help": "Number of seconds between carbon (graphite) updates",
+        "doc": """
 If sending carbon updates, this is the interval between them in seconds.
 See :doc:`metrics`.
''',
""",
     },
     {
-        'name' : 'ns',
-        'section' : 'carbon',
-        'oldname' : 'carbon-namespace',
-        'type' : LType.String,
-        'default' : 'pdns',
-        'help' : 'If set overwrites the first part of the carbon string',
-        'doc' : '''
+        "name": "ns",
+        "section": "carbon",
+        "oldname": "carbon-namespace",
+        "type": LType.String,
+        "default": "pdns",
+        "help": "If set overwrites the first part of the carbon string",
+        "doc": """
 Change the namespace or first string of the metric key. The default is pdns.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'ourname',
-        'section' : 'carbon',
-        'oldname' : 'carbon-ourname',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'If set, overrides our reported hostname for carbon stats',
-        'doc' : '''
+        "name": "ourname",
+        "section": "carbon",
+        "oldname": "carbon-ourname",
+        "type": LType.String,
+        "default": "",
+        "help": "If set, overrides our reported hostname for carbon stats",
+        "doc": """
 If sending carbon updates, if set, this will override our hostname.
 Be careful not to include any dots in this setting, unless you know what you are doing.
 See :ref:`metricscarbon`.
''',
""",
     },
     {
-        'name' : 'instance',
-        'section' : 'carbon',
-        'oldname' : 'carbon-instance',
-        'type' : LType.String,
-        'default' : 'recursor',
-        'help' : 'If set overwrites the instance name default',
-        'doc' : '''
+        "name": "instance",
+        "section": "carbon",
+        "oldname": "carbon-instance",
+        "type": LType.String,
+        "default": "recursor",
+        "help": "If set overwrites the instance name default",
+        "doc": """
 Change the instance or third string of the metric key. The default is recursor.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'server',
-        'section' : 'carbon',
-        'oldname' : 'carbon-server',
-        'type' : LType.ListSocketAddresses,
-        'default' : '',
-        'help' : 'If set, send metrics in carbon (graphite) format to this server IP address',
-        'doc' : '''
+        "name": "server",
+        "section": "carbon",
+        "oldname": "carbon-server",
+        "type": LType.ListSocketAddresses,
+        "default": "",
+        "help": "If set, send metrics in carbon (graphite) format to this server IP address",
+        "doc": """
 If set to an IP or IPv6 address, will send all available metrics to this server via the carbon protocol, which is used by graphite and metronome. Moreover you can specify more than one server using a comma delimited list, ex: carbon-server=10.10.10.10,10.10.10.20.
 You may specify an alternate port by appending :port, for example: ``127.0.0.1:2004``.
 See :doc:`metrics`.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Will send all available metrics to these servers via the carbon protocol, which is used by graphite and metronome.
 See :doc:`metrics`.
''',
-        'runtime': 'set-carbon-server',
""",
+        "runtime": "set-carbon-server",
     },
     {
-        'name' : 'chroot',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'switch to chroot jail',
-        'doc' : '''
+        "name": "chroot",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "switch to chroot jail",
+        "doc": """
 If set, chroot to this directory for more security.
 This is not recommended; instead, we recommend containing PowerDNS using operating system features.
 We ship systemd unit files with our packages to make this easy.
@@ -389,58 +389,58 @@ When using ``chroot``, all other paths (except for :ref:`setting-config-dir`) se
 
 When running on a system where systemd manages services, ``chroot`` does not work out of the box, as PowerDNS cannot use the ``NOTIFY_SOCKET``.
 Either do not ``chroot`` on these systems or set the 'Type' of this service to 'simple' instead of 'notify' (refer to the systemd documentation on how to modify unit-files).
''',
""",
     },
     {
-        'name' : 'tcp_timeout',
-        'section' : 'incoming',
-        'oldname' : 'client-tcp-timeout',
-        'type' : LType.Uint64,
-        'default' : '2',
-        'help' : 'Timeout in seconds when talking to TCP clients',
-        'doc' : '''
+        "name": "tcp_timeout",
+        "section": "incoming",
+        "oldname": "client-tcp-timeout",
+        "type": LType.Uint64,
+        "default": "2",
+        "help": "Timeout in seconds when talking to TCP clients",
+        "doc": """
 Time to wait for data from TCP clients.
''',
""",
     },
     {
-        'name' : 'config',
-        'section' : 'commands',
-        'type' : LType.Command,
-        'default' : 'no',
-        'help' : 'Output blank configuration. You can use --config=check to test the config file and command line arguments.',
-        'doc' : '''
-EMPTY?  '''
+        "name": "config",
+        "section": "commands",
+        "type": LType.Command,
+        "default": "no",
+        "help": "Output blank configuration. You can use --config=check to test the config file and command line arguments.",
+        "doc": """
+EMPTY?  """,
     },
     {
-        'name' : 'config_dir',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : 'SYSCONFDIR',
-        'docdefault': 'Determined by distribution',
-        'help' : 'Location of configuration directory (recursor.conf or recursor.yml)',
-        'doc' : '''
+        "name": "config_dir",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "SYSCONFDIR",
+        "docdefault": "Determined by distribution",
+        "help": "Location of configuration directory (recursor.conf or recursor.yml)",
+        "doc": """
 Location of configuration directory (where ``recursor.conf`` or ``recursor.yml`` is stored).
 Usually ``/etc/powerdns``, but this depends on ``SYSCONFDIR`` during compile-time.
 Use default or set on command line.
''',
""",
     },
     {
-        'name' : 'config_name',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Name of this virtual configuration - will rename the binary image',
-        'doc' : '''
+        "name": "config_name",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Name of this virtual configuration - will rename the binary image",
+        "doc": """
 When running multiple recursors on the same server, read settings from :file:`recursor-{name}.conf`, this will also rename the binary image.
''',
""",
     },
     {
-        'name' : 'cpu_map',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs',
-        'doc' : '''
+        "name": "cpu_map",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs",
+        "doc": """
 Set CPU affinity for threads, asking the scheduler to run those threads on a single CPU, or a set of CPUs.
 This parameter accepts a space separated list of thread-id=cpu-id, or thread-id=cpu-id-1,cpu-id-2,...,cpu-id-N.
 For example, to make the worker thread 0 run on CPU id 0 and the worker thread 1 on CPUs 1 and 2::
@@ -456,8 +456,8 @@ This parameter is only available if the OS provides the ``pthread_setaffinity_np
 Note that, depending on the configuration, the Recursor can start more threads.
 Typically these threads will sleep most of the time.
 These threads cannot be specified in this setting as their thread-ids are left unspecified.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Set CPU affinity for threads, asking the scheduler to run those threads on a single CPU, or a set of CPUs.
 This parameter accepts a space separated list of thread-id=cpu-id, or thread-id=cpu-id-1,cpu-id-2,...,cpu-id-N.
 For example, to make the worker thread 0 run on CPU id 0 and the worker thread 1 on CPUs 1 and 2:
@@ -476,42 +476,42 @@ This parameter is only available if the OS provides the ``pthread_setaffinity_np
 Note that, depending on the configuration, the Recursor can start more threads.
 Typically these threads will sleep most of the time.
 These threads cannot be specified in this setting as their thread-ids are left unspecified.
''',
""",
     },
     {
-        'name' : 'daemon',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Operate as a daemon',
-        'doc' : '''
+        "name": "daemon",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Operate as a daemon",
+        "doc": """
 Operate in the background.
''',
-        'versionchanged': ('4.0.0', 'Default is now ``no``, was ``yes`` before.')
""",
+        "versionchanged": ("4.0.0", "Default is now ``no``, was ``yes`` before."),
     },
     {
-        'name' : 'dont_throttle_names',
-        'section' : 'outgoing',
-        'type' : LType.ListStrings,
-        'default' : '',
-        'help' : 'Do not throttle nameservers with this name or suffix',
-        'doc' : '''
+        "name": "dont_throttle_names",
+        "section": "outgoing",
+        "type": LType.ListStrings,
+        "default": "",
+        "help": "Do not throttle nameservers with this name or suffix",
+        "doc": """
 When an authoritative server does not answer a query or sends a reply that the recursor does not like, it is throttled.
 Any servers' name suffix-matching the supplied names will never be throttled.
 
 .. warning::
   Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-names`` could make this load on the upstream server even higher, resulting in further service degradation.
''',
-        'versionadded': '4.2.0',
-        'runtime': ['add-dont-throttle-names', 'clear-dont-throttle-names'],
""",
+        "versionadded": "4.2.0",
+        "runtime": ["add-dont-throttle-names", "clear-dont-throttle-names"],
     },
     {
-        'name' : 'dont_throttle_netmasks',
-        'section' : 'outgoing',
-        'type' : LType.ListSubnets,
-        'default' : '',
-        'help' : 'Do not throttle nameservers with this IP netmask',
-        'doc' : '''
+        "name": "dont_throttle_netmasks",
+        "section": "outgoing",
+        "type": LType.ListSubnets,
+        "default": "",
+        "help": "Do not throttle nameservers with this IP netmask",
+        "doc": """
 When an authoritative server does not answer a query or sends a reply that the recursor does not like, it is throttled.
 Any servers matching the supplied netmasks will never be throttled.
 
@@ -521,8 +521,8 @@ In this case, ``dont-throttle-netmasks`` could be set to ``192.0.2.1``.
 
 .. warning::
   Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-netmasks`` could make this load on the upstream server even higher, resulting in further service degradation.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 When an authoritative server does not answer a query or sends a reply that the recursor does not like, it is throttled.
 Any servers matching the supplied netmasks will never be throttled.
 
@@ -532,48 +532,48 @@ In this case, :ref:`setting-dont-throttle-netmasks` could be set to include ``19
 
 .. warning::
   Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-netmasks`` could make this load on the upstream server even higher, resulting in further service degradation.
''',
-        'versionadded': '4.2.0',
-        'runtime': ['rec_control add-dont-throttle-netmasks', 'rec_control clear-dont-throttle-netmask'],
-    },
-    {
-        'name' : 'devonly_regression_test_mode',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'internal use only',
-        'doc' : 'SKIP',
-    },
-    {
-        'name' : 'disable',
-        'section' : 'packetcache',
-        'oldname' : 'disable-packetcache',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Disable packetcache',
-        'doc' : '''
""",
+        "versionadded": "4.2.0",
+        "runtime": ["rec_control add-dont-throttle-netmasks", "rec_control clear-dont-throttle-netmask"],
+    },
+    {
+        "name": "devonly_regression_test_mode",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "internal use only",
+        "doc": "SKIP",
+    },
+    {
+        "name": "disable",
+        "section": "packetcache",
+        "oldname": "disable-packetcache",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Disable packetcache",
+        "doc": """
 Turn off the packet cache. Useful when running with Lua scripts that modify answers in such a way they cannot be cached, though individual answer caching can be controlled from Lua as well.
''',
""",
     },
     {
-        'name' : 'disable_syslog',
-        'section' : 'logging',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Disable logging to syslog, useful when running inside a supervisor that logs stderr',
-        'doc' : '''
+        "name": "disable_syslog",
+        "section": "logging",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Disable logging to syslog, useful when running inside a supervisor that logs stderr",
+        "doc": """
 Do not log to syslog, only to stderr.
 Use this setting when running inside a supervisor that handles logging (like systemd).
 **Note**: do not use this setting in combination with :ref:`setting-daemon` as all logging will disappear.
''',
""",
     },
     {
-        'name' : 'distribution_load_factor',
-        'section' : 'incoming',
-        'type' : LType.Double,
-        'default' : '0.0',
-        'help' : 'The load factor used when PowerDNS is distributing queries to worker threads',
-        'doc' : '''
+        "name": "distribution_load_factor",
+        "section": "incoming",
+        "type": LType.Double,
+        "default": "0.0",
+        "help": "The load factor used when PowerDNS is distributing queries to worker threads",
+        "doc": """
 If :ref:`setting-pdns-distributes-queries` is set and this setting is set to another value
 than 0, the distributor thread will use a bounded load-balancing algorithm while
 distributing queries to worker threads, making sure that no thread is assigned
@@ -583,82 +583,82 @@ For example, with a value of 1.25, no server should get more than 125 % of the
 average load. This helps making sure that all the workers have roughly the same
 share of queries, even if the incoming traffic is very skewed, with a larger
 number of requests asking for the same qname.
''',
-    'versionadded': '4.1.12'
""",
+        "versionadded": "4.1.12",
     },
     {
-        'name' : 'distribution_pipe_buffer_size',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread',
-        'doc' : '''
+        "name": "distribution_pipe_buffer_size",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread",
+        "doc": """
 Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread.
 Requires support for `F_SETPIPE_SZ` which is present in Linux since 2.6.35. The actual size might be rounded up to
 a multiple of a page size. 0 means that the OS default size is used.
 A large buffer might allow the recursor to deal with very short-lived load spikes during which a worker thread gets
 overloaded, but it will be at the cost of an increased latency.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'distributor_threads',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'docdefault' : '1 if :ref:`setting-pdns-distributes-queries` is set, 0 otherwise',
-        'help' : 'Launch this number of distributor threads, distributing queries to other threads',
-        'doc' : '''
+        "name": "distributor_threads",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "0",
+        "docdefault": "1 if :ref:`setting-pdns-distributes-queries` is set, 0 otherwise",
+        "help": "Launch this number of distributor threads, distributing queries to other threads",
+        "doc": """
 If :ref:`setting-pdns-distributes-queries` is set, spawn this number of distributor threads on startup. Distributor threads
 handle incoming queries and distribute them to other threads based on a hash of the query.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'dot_to_auth_names',
-        'section' : 'outgoing',
-        'type' : LType.ListStrings,
-        'default' : '',
-        'help' : 'Use DoT to authoritative servers with these names or suffixes',
-        'doc' : '''
+        "name": "dot_to_auth_names",
+        "section": "outgoing",
+        "type": LType.ListStrings,
+        "default": "",
+        "help": "Use DoT to authoritative servers with these names or suffixes",
+        "doc": """
 Force DoT to the listed authoritative nameservers. For this to work, DoT support has to be compiled in.
 Currently, the certificate is not checked for validity in any way.
''',
-    'versionadded': '4.6.0'
""",
+        "versionadded": "4.6.0",
     },
     {
-        'name' : 'dot_to_port_853',
-        'section' : 'outgoing',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Force DoT connection to target port 853 if DoT compiled in',
-        'doc' : '''
+        "name": "dot_to_port_853",
+        "section": "outgoing",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Force DoT connection to target port 853 if DoT compiled in",
+        "doc": """
 Enable DoT to forwarders that specify port 853.
''',
-    'versionadded': '4.6.0'
""",
+        "versionadded": "4.6.0",
     },
     {
-        'name' : 'dns64_prefix',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'DNS64 prefix',
-        'doc' : '''
+        "name": "dns64_prefix",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "DNS64 prefix",
+        "doc": """
 Enable DNS64 (:rfc:`6147`) support using the supplied /96 IPv6 prefix. This will generate 'fake' ``AAAA`` records for names
 with only ``A`` records, as well as 'fake' ``PTR`` records to make sure that reverse lookup of DNS64-generated IPv6 addresses
 generate the right name.
 See :doc:`dns64` for more flexible but slower alternatives using Lua.
''',
-    'versionadded': '4.4.0'
""",
+        "versionadded": "4.4.0",
     },
     {
-        'name' : 'validation',
-        'section' : 'dnssec',
-        'oldname' : 'dnssec',
-        'type' : LType.String,
-        'default' : 'process',
-        'help' : 'DNSSEC mode: off/process-no-validate/process (default)/log-fail/validate',
-        'doc' : '''
+        "name": "validation",
+        "section": "dnssec",
+        "oldname": "dnssec",
+        "type": LType.String,
+        "default": "process",
+        "help": "DNSSEC mode: off/process-no-validate/process (default)/log-fail/validate",
+        "doc": """
 One of ``off``, ``process-no-validate``, ``process``, ``log-fail``, ``validate``
 
 Set the mode for DNSSEC processing, as detailed in :doc:`dnssec`.
@@ -677,19 +677,18 @@ Set the mode for DNSSEC processing, as detailed in :doc:`dnssec`.
    Similar behaviour to ``process``, but validate RRSIGs on responses and log bogus responses.
 ``validate``
    Full blown DNSSEC validation. Send SERVFAIL to clients on bogus responses.
- ''',
-        'versionadded': '4.0.0',
-        'versionchanged': ('4.5.0',
-   'The default changed from ``process-no-validate`` to ``process``')
-    },
-    {
-        'name' : 'disabled_algorithms',
-        'section' : 'dnssec',
-        'oldname' : 'dnssec-disabled-algorithms',
-        'type' : LType.ListStrings,
-        'default' : '',
-        'help' : 'List of DNSSEC algorithm numbers that are considered unsupported',
-        'doc' : '''
+ """,
+        "versionadded": "4.0.0",
+        "versionchanged": ("4.5.0", "The default changed from ``process-no-validate`` to ``process``"),
+    },
+    {
+        "name": "disabled_algorithms",
+        "section": "dnssec",
+        "oldname": "dnssec-disabled-algorithms",
+        "type": LType.ListStrings,
+        "default": "",
+        "help": "List of DNSSEC algorithm numbers that are considered unsupported",
+        "doc": """
 A list of DNSSEC algorithm numbers that should be considered disabled.
 These algorithms will not be used to validate DNSSEC signatures.
 Zones (only) signed with these algorithms will be considered ``Insecure``.
@@ -699,184 +698,184 @@ This is done for specific algorithms only, currently algorithms 5 (``RSASHA1``)
 
 This is important on systems that have a default strict crypto policy, like RHEL9 derived systems.
 On such systems not disabling some algorithms (or changing the security policy) will make affected zones to be considered ``Bogus`` as using these algorithms fails.
''',
-    'versionadded': '4.9.0'
""",
+        "versionadded": "4.9.0",
     },
     {
-        'name' : 'log_bogus',
-        'section' : 'dnssec',
-        'oldname' : 'dnssec-log-bogus',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Log DNSSEC bogus validations',
-        'doc' : '''
+        "name": "log_bogus",
+        "section": "dnssec",
+        "oldname": "dnssec-log-bogus",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Log DNSSEC bogus validations",
+        "doc": """
 Log every DNSSEC validation failure.
 **Note**: This is not logged per-query but every time records are validated as Bogus.
''',
-        'runtime': 'set-dnssec-log-bogus',
""",
+        "runtime": "set-dnssec-log-bogus",
     },
     {
-        'name' : 'dont_query',
-        'section' : 'outgoing',
-        'type' : LType.ListSubnets,
-        'default' : '127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10, 0.0.0.0/8, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::/96, ::ffff:0:0/96, 100::/64, 2001:db8::/32',
-        'help' : 'If set, do not query these netmasks for DNS data',
-        'doc' : '''
+        "name": "dont_query",
+        "section": "outgoing",
+        "type": LType.ListSubnets,
+        "default": "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10, 0.0.0.0/8, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::/96, ::ffff:0:0/96, 100::/64, 2001:db8::/32",
+        "help": "If set, do not query these netmasks for DNS data",
+        "doc": """
 The DNS is a public database, but sometimes contains delegations to private IP addresses, like for example 127.0.0.1.
 This can have odd effects, depending on your network, and may even be a security risk.
 Therefore, the PowerDNS Recursor by default does not query private space IP addresses.
 This setting can be used to expand or reduce the limitations.
 
 Queries for names in forward zones and to addresses as configured in any of the settings :ref:`setting-forward-zones`, :ref:`setting-forward-zones-file` or :ref:`setting-forward-zones-recurse` are performed regardless of these limitations. However, if NS records are learned from :ref:`setting-forward-zones` and the IP addresses of the nameservers learned in that way are included in :ref:`setting-dont-query`, lookups relying on these nameservers will fail with SERVFAIL.
''',
""",
     },
     {
-        'name' : 'add_for',
-        'section' : 'ecs',
-        'oldname' : 'ecs-add-for',
-        'type' : LType.ListSubnets,
-        'default' : '0.0.0.0/0, ::/0, !127.0.0.0/8, !10.0.0.0/8, !100.64.0.0/10, !169.254.0.0/16, !192.168.0.0/16, !172.16.0.0/12, !::1/128, !fc00::/7, !fe80::/10',
-        'help' : 'List of client netmasks for which EDNS Client Subnet will be added',
-        'doc' : '''
+        "name": "add_for",
+        "section": "ecs",
+        "oldname": "ecs-add-for",
+        "type": LType.ListSubnets,
+        "default": "0.0.0.0/0, ::/0, !127.0.0.0/8, !10.0.0.0/8, !100.64.0.0/10, !169.254.0.0/16, !192.168.0.0/16, !172.16.0.0/12, !::1/128, !fc00::/7, !fe80::/10",
+        "help": "List of client netmasks for which EDNS Client Subnet will be added",
+        "doc": """
 List of requestor netmasks for which the requestor IP Address should be used as the :rfc:`EDNS Client Subnet <7871>` for outgoing queries. Outgoing queries for requestors that do not match this list will use the :ref:`setting-ecs-scope-zero-address` instead.
 Valid incoming ECS values from :ref:`setting-use-incoming-edns-subnet` are not replaced.
 
 Regardless of the value of this setting, ECS values are only sent for outgoing queries matching the conditions in the :ref:`setting-edns-subnet-allow-list` setting. This setting only controls the actual value being sent.
 
 This defaults to not using the requestor address inside RFC1918 and similar 'private' IP address spaces.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'ipv4_bits',
-        'section' : 'ecs',
-        'oldname' : 'ecs-ipv4-bits',
-        'type' : LType.Uint64,
-        'default' : '24',
-        'help' : 'Number of bits of IPv4 address to pass for EDNS Client Subnet',
-        'doc' : '''
+        "name": "ipv4_bits",
+        "section": "ecs",
+        "oldname": "ecs-ipv4-bits",
+        "type": LType.Uint64,
+        "default": "24",
+        "help": "Number of bits of IPv4 address to pass for EDNS Client Subnet",
+        "doc": """
 Number of bits of client IPv4 address to pass when sending EDNS Client Subnet address information.
''',
-        'versionadded': '4.1.0',
""",
+        "versionadded": "4.1.0",
     },
     {
-        'name' : 'ipv4_cache_bits',
-        'section' : 'ecs',
-        'oldname' : 'ecs-ipv4-cache-bits',
-        'type' : LType.Uint64,
-        'default' : '24',
-        'help' : 'Maximum number of bits of IPv4 mask to cache ECS response',
-        'doc' : '''
+        "name": "ipv4_cache_bits",
+        "section": "ecs",
+        "oldname": "ecs-ipv4-cache-bits",
+        "type": LType.Uint64,
+        "default": "24",
+        "help": "Maximum number of bits of IPv4 mask to cache ECS response",
+        "doc": """
 Maximum number of bits of client IPv4 address used by the authoritative server (as indicated by the EDNS Client Subnet scope in the answer) for an answer to be inserted into the record cache. This condition applies in conjunction with ``ecs-cache-limit-ttl``.
 That is, only if both the limits apply, the record will not be cached. This decision can be overridden by ``ecs-ipv4-never-cache`` and ``ecs-ipv6-never-cache``.
''',
-    'versionadded': '4.1.12'
""",
+        "versionadded": "4.1.12",
     },
     {
-        'name' : 'ipv6_bits',
-        'section' : 'ecs',
-        'oldname' : 'ecs-ipv6-bits',
-        'type' : LType.Uint64,
-        'default' : '56',
-        'help' : 'Number of bits of IPv6 address to pass for EDNS Client Subnet',
-        'doc' : '''
+        "name": "ipv6_bits",
+        "section": "ecs",
+        "oldname": "ecs-ipv6-bits",
+        "type": LType.Uint64,
+        "default": "56",
+        "help": "Number of bits of IPv6 address to pass for EDNS Client Subnet",
+        "doc": """
 Number of bits of client IPv6 address to pass when sending EDNS Client Subnet address information.
''',
-    'versionadded': '4.1.0'
""",
+        "versionadded": "4.1.0",
     },
     {
-        'name' : 'ipv6_cache_bits',
-        'section' : 'ecs',
-        'oldname' : 'ecs-ipv6-cache-bits',
-        'type' : LType.Uint64,
-        'default' : '56',
-        'help' : 'Maximum number of bits of IPv6 mask to cache ECS response',
-        'doc' : '''
+        "name": "ipv6_cache_bits",
+        "section": "ecs",
+        "oldname": "ecs-ipv6-cache-bits",
+        "type": LType.Uint64,
+        "default": "56",
+        "help": "Maximum number of bits of IPv6 mask to cache ECS response",
+        "doc": """
 Maximum number of bits of client IPv6 address used by the authoritative server (as indicated by the EDNS Client Subnet scope in the answer) for an answer to be inserted into the record cache. This condition applies in conjunction with ``ecs-cache-limit-ttl``.
 That is, only if both the limits apply, the record will not be cached. This decision can be overridden by ``ecs-ipv4-never-cache`` and ``ecs-ipv6-never-cache``.
''',
-    'versionadded': '4.1.12'
""",
+        "versionadded": "4.1.12",
     },
     {
-        'name' : 'ipv4_never_cache',
-        'section' : 'ecs',
-        'oldname' : 'ecs-ipv4-never-cache',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'If we should never cache IPv4 ECS responses',
-        'doc' : '''
+        "name": "ipv4_never_cache",
+        "section": "ecs",
+        "oldname": "ecs-ipv4-never-cache",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "If we should never cache IPv4 ECS responses",
+        "doc": """
 When set, never cache replies carrying EDNS IPv4 Client Subnet scope in the record cache.
 In this case the decision made by ``ecs-ipv4-cache-bits`` and ``ecs-cache-limit-ttl`` is no longer relevant.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'ipv6_never_cache',
-        'section' : 'ecs',
-        'oldname' : 'ecs-ipv6-never-cache',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'If we should never cache IPv6 ECS responses',
-        'doc' : '''
+        "name": "ipv6_never_cache",
+        "section": "ecs",
+        "oldname": "ecs-ipv6-never-cache",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "If we should never cache IPv6 ECS responses",
+        "doc": """
 When set, never cache replies carrying EDNS IPv6 Client Subnet scope in the record cache.
 In this case the decision made by ``ecs-ipv6-cache-bits`` and ``ecs-cache-limit-ttl`` is no longer relevant.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'minimum_ttl_override',
-        'section' : 'ecs',
-        'oldname' : 'ecs-minimum-ttl-override',
-        'type' : LType.Uint64,
-        'default' : '1',
-        'help' : 'The minimum TTL for records in ECS-specific answers',
-        'doc' : '''
+        "name": "minimum_ttl_override",
+        "section": "ecs",
+        "oldname": "ecs-minimum-ttl-override",
+        "type": LType.Uint64,
+        "default": "1",
+        "help": "The minimum TTL for records in ECS-specific answers",
+        "doc": """
 This setting artificially raises the TTLs of records in the ANSWER section of ECS-specific answers to be at least this long.
 Setting this to a value greater than 1 technically is an RFC violation, but might improve performance a lot.
 Using a value of 0 impacts performance of TTL 0 records greatly, since it forces the recursor to contact
 authoritative servers every time a client requests them.
''',
-        'versionchanged': ('4.5.0', 'Old versions used default 0.'),
-        'runtime': 'set-ecs-minimum-ttl',
-    },
-    {
-        'name' : 'cache_limit_ttl',
-        'section' : 'ecs',
-        'oldname' : 'ecs-cache-limit-ttl',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Minimum TTL to cache ECS response',
-        'doc' : '''
""",
+        "versionchanged": ("4.5.0", "Old versions used default 0."),
+        "runtime": "set-ecs-minimum-ttl",
+    },
+    {
+        "name": "cache_limit_ttl",
+        "section": "ecs",
+        "oldname": "ecs-cache-limit-ttl",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Minimum TTL to cache ECS response",
+        "doc": """
 The minimum TTL for an ECS-specific answer to be inserted into the record cache. This condition applies in conjunction with ``ecs-ipv4-cache-bits`` or ``ecs-ipv6-cache-bits``.
 That is, only if both the limits apply, the record will not be cached. This decision can be overridden by ``ecs-ipv4-never-cache`` and ``ecs-ipv6-never-cache``.
''',
-    'versionadded': '4.1.12'
""",
+        "versionadded": "4.1.12",
     },
     {
-        'name' : 'scope_zero_address',
-        'section' : 'ecs',
-        'oldname' : 'ecs-scope-zero-address',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Address to send to allow-listed authoritative servers for incoming queries with ECS prefix-length source of 0',
-        'doc' : '''
+        "name": "scope_zero_address",
+        "section": "ecs",
+        "oldname": "ecs-scope-zero-address",
+        "type": LType.String,
+        "default": "",
+        "help": "Address to send to allow-listed authoritative servers for incoming queries with ECS prefix-length source of 0",
+        "doc": """
 The IP address sent via EDNS Client Subnet to authoritative servers listed in
 :ref:`setting-edns-subnet-allow-list` when :ref:`setting-use-incoming-edns-subnet` is set and the query has
 an ECS source prefix-length set to 0.
 The default is to look for the first usable (not an ``any`` one) address in
 :ref:`setting-query-local-address` (starting with IPv4). If no suitable address is
 found, the recursor fallbacks to sending 127.0.0.1.
''',
-    'versionadded': '4.1.0'
""",
+        "versionadded": "4.1.0",
     },
     {
-        'name' : 'edns_bufsize',
-        'section' : 'outgoing',
-        'oldname' : 'edns-outgoing-bufsize',
-        'type' : LType.Uint64,
-        'default' : '1232',
-        'help' : 'Outgoing EDNS buffer size',
-        'doc' : '''
+        "name": "edns_bufsize",
+        "section": "outgoing",
+        "oldname": "edns-outgoing-bufsize",
+        "type": LType.Uint64,
+        "default": "1232",
+        "help": "Outgoing EDNS buffer size",
+        "doc": """
 .. note:: Why 1232?
 
   1232 is the largest number of payload bytes that can fit in the smallest IPv6 packet.
@@ -884,65 +883,68 @@ found, the recursor fallbacks to sending 127.0.0.1.
 
 This is the value set for the EDNS0 buffer size in outgoing packets.
 Lower this if you experience timeouts.
''',
-     'versionchanged': ('4.2.0', 'Before 4.2.0, the default was 1680')
""",
+        "versionchanged": ("4.2.0", "Before 4.2.0, the default was 1680"),
     },
     {
-        'name' : 'edns_padding_from',
-        'section' : 'incoming',
-        'type' : LType.ListSubnets,
-        'default' : '',
-        'help' : 'List of netmasks (proxy IP in case of proxy-protocol presence, client IP otherwise) for which EDNS padding will be enabled in responses, provided that \'edns-padding-mode\' applies',
-        'doc' : '''
+        "name": "edns_padding_from",
+        "section": "incoming",
+        "type": LType.ListSubnets,
+        "default": "",
+        "help": "List of netmasks (proxy IP in case of proxy-protocol presence, client IP otherwise) for which EDNS padding will be enabled in responses, provided that 'edns-padding-mode' applies",
+        "doc": """
 List of netmasks (proxy IP in case of proxy-protocol presence, client IP otherwise) for which EDNS padding will be enabled in responses, provided that :ref:`setting-edns-padding-mode` applies.
- ''',
-        'versionadded' : '4.5.0',
-        'versionchanged' : ('5.0.5', 'YAML settings only: previously this was defined as a string instead of a sequence')
-    },
-    {
-        'name' : 'edns_padding_mode',
-        'section' : 'incoming',
-        'type' : LType.String,
-        'default' : 'padded-queries-only',
-        'help' : 'Whether to add EDNS padding to all responses (\'always\') or only to responses for queries containing the EDNS padding option (\'padded-queries-only\', the default). In both modes, padding will only be added to responses for queries coming from \'setting-edns-padding-from\' sources',
-        'doc' : '''
+ """,
+        "versionadded": "4.5.0",
+        "versionchanged": (
+            "5.0.5",
+            "YAML settings only: previously this was defined as a string instead of a sequence",
+        ),
+    },
+    {
+        "name": "edns_padding_mode",
+        "section": "incoming",
+        "type": LType.String,
+        "default": "padded-queries-only",
+        "help": "Whether to add EDNS padding to all responses ('always') or only to responses for queries containing the EDNS padding option ('padded-queries-only', the default). In both modes, padding will only be added to responses for queries coming from 'setting-edns-padding-from' sources",
+        "doc": """
 One of ``always``, ``padded-queries-only``.
 Whether to add EDNS padding to all responses (``always``) or only to responses for queries containing the EDNS padding option (``padded-queries-only``, the default).
 In both modes, padding will only be added to responses for queries coming from :ref:`setting-edns-padding-from` sources.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'edns_padding',
-        'section' : 'outgoing',
-        'oldname' : 'edns-padding-out',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Whether to add EDNS padding to outgoing DoT messages',
-        'doc' : '''
+        "name": "edns_padding",
+        "section": "outgoing",
+        "oldname": "edns-padding-out",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Whether to add EDNS padding to outgoing DoT messages",
+        "doc": """
 Whether to add EDNS padding to outgoing DoT queries.
''',
-    'versionadded': '4.8.0'
""",
+        "versionadded": "4.8.0",
     },
     {
-        'name' : 'edns_padding_tag',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '7830',
-        'help' : 'Packetcache tag associated to responses sent with EDNS padding, to prevent sending these to clients for which padding is not enabled.',
-        'doc' : '''
+        "name": "edns_padding_tag",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "7830",
+        "help": "Packetcache tag associated to responses sent with EDNS padding, to prevent sending these to clients for which padding is not enabled.",
+        "doc": """
 The packetcache tag to use for padded responses, to prevent a client not allowed by the :ref:`setting-edns-padding-from` list to be served a cached answer generated for an allowed one. This
 effectively divides the packet cache in two when :ref:`setting-edns-padding-from` is used. Note that this will not override a tag set from one of the ``Lua`` hooks.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'edns_subnet_allow_list',
-        'section' : 'outgoing',
-        'type' : LType.ListStrings,
-        'default' : '',
-        'help' : 'List of netmasks and domains that we should enable EDNS subnet for',
-        'doc' : '''
+        "name": "edns_subnet_allow_list",
+        "section": "outgoing",
+        "type": LType.ListStrings,
+        "default": "",
+        "help": "List of netmasks and domains that we should enable EDNS subnet for",
+        "doc": """
 List of netmasks and domains that :rfc:`EDNS Client Subnet <7871>` should be enabled for in outgoing queries.
 
 For example, an EDNS Client Subnet option containing the address of the initial requestor (but see :ref:`setting-ecs-add-for`) will be added to an outgoing query sent to server 192.0.2.1 for domain X if 192.0.2.1 matches one of the supplied netmasks, or if X matches one of the supplied domains.
@@ -952,112 +954,112 @@ The initial requestor address will be truncated to 24 bits for IPv4 (see :ref:`s
 Note that this setting describes the destination of outgoing queries, not the sources of incoming queries, nor the subnets described in the EDNS Client Subnet option.
 
 By default, this option is empty, meaning no EDNS Client Subnet information is sent.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'edns_subnet_harden',
-        'section' : 'outgoing',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Do more strict checking or EDNS Client Subnet information returned by authoritative servers',
-        'doc' : '''
+        "name": "edns_subnet_harden",
+        "section": "outgoing",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Do more strict checking or EDNS Client Subnet information returned by authoritative servers",
+        "doc": """
 Do more strict checking or EDNS Client Subnet information returned by authoritative servers.
 Answers missing ECS information will be ignored and followed up by an ECS-less query.
''',
-    'versionadded': ['5.2.4', '5.1.6', '5.0.12']
""",
+        "versionadded": ["5.2.4", "5.1.6", "5.0.12"],
     },
     {
-        'name' : 'enable_old_settings',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Enable (deprecated) parsing of old-style settings',
-        'doc' : '''
+        "name": "enable_old_settings",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Enable (deprecated) parsing of old-style settings",
+        "doc": """
 Enable the deprecated parsing of old-style settings.
 Only makes sense to set on the command line.
-        ''',
-        'skip-yaml': True,
-        'versionadded': '5.2.0',
-    },
-    {
-        'name' : 'entropy_source',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '/dev/urandom',
-        'help' : '',
-        'doc' : '''
''',
-        'skip-yaml': True,
-        'versionchanged': ('4.9.0', 'This setting is no longer used.'),
-    },
-    {
-        'name' : 'etc_hosts_file',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '/etc/hosts',
-        'help' : 'Path to \'hosts\' file',
-        'doc' : '''
+        """,
+        "skip-yaml": True,
+        "versionadded": "5.2.0",
+    },
+    {
+        "name": "entropy_source",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "/dev/urandom",
+        "help": "",
+        "doc": """
""",
+        "skip-yaml": True,
+        "versionchanged": ("4.9.0", "This setting is no longer used."),
+    },
+    {
+        "name": "etc_hosts_file",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "/etc/hosts",
+        "help": "Path to 'hosts' file",
+        "doc": """
 The path to the /etc/hosts file, or equivalent.
 This file can be used to serve data authoritatively using :ref:`setting-export-etc-hosts`.
''',
""",
     },
     {
-        'name' : 'event_trace_enabled',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'If set, event traces are collected and send out via protobuf logging (1), logfile (2), opentelemetry trace data (4) or a combination',
-        'doc' : '''
+        "name": "event_trace_enabled",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "If set, event traces are collected and send out via protobuf logging (1), logfile (2), opentelemetry trace data (4) or a combination",
+        "doc": """
 Enable the recording and logging of ref:`event traces`. This is an experimental feature and subject to change.
 Possible values are 0: (disabled), 1 (add information to protobuf logging messages), 2 (write to log), 4 (output OpenTelemetry Trace data in protobuf logging messages, since version 5.3.0). Values can be added to get multiple types of logging simultaneously.
 For example, 6 means: write to log and output OpenTelemetry Trace data in the protobuf stream.
''',
-        'versionadded': '4.6.0',
-        'versionchanged': ('5.3.0', 'A value to generate OpenTelemetry Trace data was added'),
-        'runtime': 'set-event-trace-enabled',
-    },
-    {
-        'name' : 'export_etc_hosts',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'If we should serve up contents from /etc/hosts',
-        'doc' : '''
""",
+        "versionadded": "4.6.0",
+        "versionchanged": ("5.3.0", "A value to generate OpenTelemetry Trace data was added"),
+        "runtime": "set-event-trace-enabled",
+    },
+    {
+        "name": "export_etc_hosts",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "If we should serve up contents from /etc/hosts",
+        "doc": """
 If set, this flag will export the host names and IP addresses mentioned in ``/etc/hosts``.
''',
""",
     },
     {
-        'name' : 'export_etc_hosts_search_suffix',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Also serve up the contents of /etc/hosts with this suffix',
-        'doc' : '''
+        "name": "export_etc_hosts_search_suffix",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Also serve up the contents of /etc/hosts with this suffix",
+        "doc": """
 If set, all hostnames in the :ref:`setting-export-etc-hosts` file are loaded in canonical form, based on this suffix, unless the name contains a '.', in which case the name is unchanged.
 So an entry called 'pc' with ``export-etc-hosts-search-suffix='home.com'`` will lead to the generation of 'pc.home.com' within the recursor.
 An entry called 'server1.home' will be stored as 'server1.home', regardless of this setting.
''',
""",
     },
     {
-        'name' : 'extended_resolution_errors',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'If set, send an EDNS Extended Error extension on resolution failures, like DNSSEC validation errors',
-        'doc' : '''
+        "name": "extended_resolution_errors",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "If set, send an EDNS Extended Error extension on resolution failures, like DNSSEC validation errors",
+        "doc": """
 If set, the recursor will add an EDNS Extended Error (:rfc:`8914`) to responses when resolution failed, like DNSSEC validation errors, explaining the reason it failed. This setting is not needed to allow setting custom error codes from Lua or from a RPZ hit.
''',
-        'versionadded': '4.5.0',
-        'versionchanged': ('5.0.0', 'Default changed to enabled, previously it was disabled.'),
""",
+        "versionadded": "4.5.0",
+        "versionchanged": ("5.0.0", "Default changed to enabled, previously it was disabled."),
     },
     {
-        'name' : 'forward_zones',
-        'section' : 'recursor',
-        'type' : LType.ListForwardZones,
-        'default' : '',
-        'help' : 'Zones for which we forward queries, comma separated domain=ip pairs',
-        'doc' : '''
+        "name": "forward_zones",
+        "section": "recursor",
+        "type": LType.ListForwardZones,
+        "default": "",
+        "help": "Zones for which we forward queries, comma separated domain=ip pairs",
+        "doc": """
 Queries for zones listed here will be forwarded to the IP address listed. i.e.
 
 .. code-block:: none
@@ -1081,8 +1083,8 @@ SERVFAIL is returned.
 To prevent this, add a Negative Trust Anchor (NTA) for this zone in the :ref:`setting-lua-config-file` with ``addNTA('your.zone', 'A comment')``.
 If this forwarded zone is signed, instead of adding NTA, add the DS record to the :ref:`setting-lua-config-file`.
 See the :doc:`dnssec` information.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Queries for zones listed here will be forwarded to the IP address listed. i.e.
 
 .. code-block:: yaml
@@ -1129,17 +1131,20 @@ To forward to a recursive resolver use :ref:`setting-yaml-recursor.forward_zones
 
 .. note::
   When an ``NS`` record for a subzone is learned and the IP address for that nameserver is included in the IP ranges in :ref:`setting-dont-query`, SERVFAIL is returned.
- ''',
-        'versionchanged' : ('5.2.0',  'Zones having ``notify_allowed`` set will be added to :ref:`setting-yaml-incoming.allow_notify_for`.'),
-        'runtime': ['reload-zones'],
-    },
-    {
-        'name' : 'forward_zones_file',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'File with (+)domain=ip pairs for forwarding',
-        'doc' : '''
+ """,
+        "versionchanged": (
+            "5.2.0",
+            "Zones having ``notify_allowed`` set will be added to :ref:`setting-yaml-incoming.allow_notify_for`.",
+        ),
+        "runtime": ["reload-zones"],
+    },
+    {
+        "name": "forward_zones_file",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "File with (+)domain=ip pairs for forwarding",
+        "doc": """
 Same as :ref:`setting-forward-zones`, parsed from a file. Only 1 zone is allowed per line, specified as follows:
 
 .. code-block:: none
@@ -1151,8 +1156,8 @@ Zones prefixed with a ``+`` are treated as with
 :ref:`setting-forward-zones`.
 
 The DNSSEC notes from :ref:`setting-forward-zones` apply here as well.
''',
-    'doc-new' : '''
""",
+        "doc-new": """
         Same as :ref:`setting-forward-zones`, parsed from a file as a sequence of `Forward Zone`_.
         The filename MUST end in ``.yml`` for the content to be parsed as YAML.
 
@@ -1170,25 +1175,30 @@ The DNSSEC notes from :ref:`setting-forward-zones` apply here as well.
     notify_allowed: true
 
 The DNSSEC notes from :ref:`setting-forward-zones` apply here as well.
- ''',
-     'versionchanged': [('4.0.0', '(Old style settings only) Comments are allowed, everything behind ``#`` is ignored.'),
-                        ('4.6.0', '(Old style settings only) Zones prefixed with a ``^`` are added to the :ref:`setting-allow-notify-for` list. Both prefix characters can be used if desired, in any order.')],
-        'runtime': ['reload-zones'],
-    },
-    {
-        'name' : 'forward_zones_recurse',
-        'section' : 'recursor',
-        'type' : LType.ListForwardZones,
-        'default' : '',
-        'help' : 'Zones for which we forward queries with recursion bit, comma separated domain=ip pairs',
-        'doc' : '''
+ """,
+        "versionchanged": [
+            ("4.0.0", "(Old style settings only) Comments are allowed, everything behind ``#`` is ignored."),
+            (
+                "4.6.0",
+                "(Old style settings only) Zones prefixed with a ``^`` are added to the :ref:`setting-allow-notify-for` list. Both prefix characters can be used if desired, in any order.",
+            ),
+        ],
+        "runtime": ["reload-zones"],
+    },
+    {
+        "name": "forward_zones_recurse",
+        "section": "recursor",
+        "type": LType.ListForwardZones,
+        "default": "",
+        "help": "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs",
+        "doc": """
 Like regular :ref:`setting-forward-zones`, but forwarded queries have the ``recursion desired (RD)`` bit set to ``1``, meaning that this setting is intended to forward queries to other recursive resolvers.
 In contrast to regular forwarding, the rule that delegations of the forwarded subzones are respected is not active.
 This is because we rely on the forwarder to resolve the query fully.
 
 See :ref:`setting-forward-zones` for additional options (such as supplying multiple recursive servers) and an important note about DNSSEC.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Like regular :ref:`setting-forward-zones`, but forwarded queries have the ``recursion desired (RD)`` bit set to ``1``, meaning that this setting is intended to forward queries to other recursive resolvers.
 In contrast to regular forwarding, the rule that delegations of the forwarded subzones are respected is not active.
 This is because we rely on the forwarder to resolve the query fully.
@@ -1197,90 +1207,95 @@ This is because we rely on the forwarder to resolve the query fully.
   The `recurse` field of a `Forward Zone`_ is fixed to ``true`` in the context of :ref:`setting-yaml-recursor.forward_zones_recurse`.
 
 See :ref:`setting-forward-zones` for additional options (such as supplying multiple recursive servers) and an important note about DNSSEC.
''',
-        'runtime': ['reload-zones'],
""",
+        "runtime": ["reload-zones"],
     },
     {
-        'name' : 'gettag_needs_edns_options',
-        'section' : 'incoming',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'If EDNS Options should be extracted before calling the gettag() hook',
-        'doc' : '''
+        "name": "gettag_needs_edns_options",
+        "section": "incoming",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "If EDNS Options should be extracted before calling the gettag() hook",
+        "doc": """
 If set, EDNS options in incoming queries are extracted and passed to the :func:`gettag` hook in the ``ednsoptions`` table.
''',
-    'versionadded': '4.1.0'
""",
+        "versionadded": "4.1.0",
     },
     {
-        'name' : 'help',
-        'section' : 'commands',
-        'type' : LType.Command,
-        'default' : 'no',
-        'help' : 'Provide a helpful message',
-        'doc' : '''
-EMPTY?  '''
+        "name": "help",
+        "section": "commands",
+        "type": LType.Command,
+        "default": "no",
+        "help": "Provide a helpful message",
+        "doc": """
+EMPTY?  """,
     },
     {
-        'name' : 'hint_file',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'If set, load root hints from this file',
-        'doc' : '''
+        "name": "hint_file",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "If set, load root hints from this file",
+        "doc": """
 If set, the root-hints are read from this file. If empty, the default built-in root hints are used.
 
 In some special cases, processing the root hints is not needed, for example when forwarding all queries to another recursor.
 For these special cases, it is possible to disable the processing of root hints by setting the value to ``no`` or ``no-refresh``.
 See :ref:`handling-of-root-hints` for more information on root hints handling.
- ''',
-        'versionchanged': [('4.6.2', 'Introduced the value ``no`` to disable root-hints processing.'),
-                           ('4.9.0', 'Introduced the value ``no-refresh`` to disable both root-hints processing and periodic refresh of the cached root `NS` records.')]
-    },
-    {
-        'name' : 'ignore_unknown_settings',
-        'section' : 'recursor',
-        'type' : LType.ListStrings,
-        'default' : '',
-        'help' : 'Configuration settings to ignore if they are unknown',
-        'doc' : '''
+ """,
+        "versionchanged": [
+            ("4.6.2", "Introduced the value ``no`` to disable root-hints processing."),
+            (
+                "4.9.0",
+                "Introduced the value ``no-refresh`` to disable both root-hints processing and periodic refresh of the cached root `NS` records.",
+            ),
+        ],
+    },
+    {
+        "name": "ignore_unknown_settings",
+        "section": "recursor",
+        "type": LType.ListStrings,
+        "default": "",
+        "help": "Configuration settings to ignore if they are unknown",
+        "doc": """
 Names of settings to be ignored while parsing configuration files, if the setting
 name is unknown to PowerDNS.
 
 Useful during upgrade testing.
''',
""",
     },
     {
-        'name' : 'include_dir',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Include settings files from this directory.',
-        'doc' : '''
+        "name": "include_dir",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Include settings files from this directory.",
+        "doc": """
 Directory to scan for additional config files. All files that end with ``.conf`` are loaded in order using ``POSIX`` as locale.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Directory to scan for additional config files. All files that end with ``.yml`` are loaded in order using ``POSIX`` as locale.
''',
""",
     },
     {
-        'name' : 'latency_statistic_size',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '10000',
-        'help' : 'Number of latency values to calculate the qa-latency average',
-        'doc' : '''
+        "name": "latency_statistic_size",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "10000",
+        "help": "Number of latency values to calculate the qa-latency average",
+        "doc": """
 Indication of how many queries will be averaged to get the average latency reported by the 'qa-latency' metric.
''',
""",
     },
     {
-        'name' : 'listen',
-        'section' : 'incoming',
-        'oldname' : 'local-address',
-        'type' : LType.ListSocketAddresses,
-        'default' : '127.0.0.1, ::1',
-        'help' : 'IP addresses to listen on, separated by spaces or commas. Also accepts ports.',
-        'versionchanged': ('5.3.0', '::1 was added to the list'),
-        'doc' : '''
+        "name": "listen",
+        "section": "incoming",
+        "oldname": "local-address",
+        "type": LType.ListSocketAddresses,
+        "default": "127.0.0.1, ::1",
+        "help": "IP addresses to listen on, separated by spaces or commas. Also accepts ports.",
+        "versionchanged": ("5.3.0", "::1 was added to the list"),
+        "doc": """
 Local IP addresses to which we bind. Each address specified can
 include a port number; if no port is included then the
 :ref:`setting-local-port` port will be used for that address. If a
@@ -1294,8 +1309,8 @@ Examples::
   local-address=0.0.0.0:5353
   local-address=[::]:8053
   local-address=127.0.0.1:53, [::1]:5353
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 Local IP addresses to which we bind. Each address specified can
 include a port number; if no port is included then the
 :ref:`setting-local-port` port will be used for that address. If a
@@ -1312,158 +1327,158 @@ Example:
       - 127.0.0.1
       - '[::1]:5353'
       - '::'
''',
""",
     },
     {
-        'name' : 'port',
-        'section' : 'incoming',
-        'oldname' : 'local-port',
-        'type' : LType.Uint64,
-        'default' : '53',
-        'help' : 'port to listen on',
-        'doc' : '''
+        "name": "port",
+        "section": "incoming",
+        "oldname": "local-port",
+        "type": LType.Uint64,
+        "default": "53",
+        "help": "port to listen on",
+        "doc": """
 Local port to bind to.
 If an address in :ref:`setting-local-address` does not have an explicit port, this port is used.
''',
""",
     },
     {
-        'name' : 'timestamp',
-        'section' : 'logging',
-        'oldname' : 'log-timestamp',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Print timestamps in log lines, useful to disable when running with a tool that timestamps stderr already',
-        'doc' : '''
+        "name": "timestamp",
+        "section": "logging",
+        "oldname": "log-timestamp",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Print timestamps in log lines, useful to disable when running with a tool that timestamps stderr already",
+        "doc": """
 
''',
""",
     },
     {
-        'name' : 'non_local_bind',
-        'section' : 'incoming',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Enable binding to non-local addresses by using FREEBIND / BINDANY socket options',
-        'doc' : '''
+        "name": "non_local_bind",
+        "section": "incoming",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options",
+        "doc": """
 Bind to addresses even if one or more of the :ref:`setting-local-address`'s do not exist on this server.
 Setting this option will enable the needed socket options to allow binding to non-local addresses.
 This feature is intended to facilitate ip-failover setups, but it may also mask configuration issues and for this reason it is disabled by default.
''',
""",
     },
     {
-        'name' : 'loglevel',
-        'section' : 'logging',
-        'type' : LType.Uint64,
-        'default' : '6',
-        'help' : 'Amount of logging. Higher is more. Do not set below 3',
-        'doc' : '''
+        "name": "loglevel",
+        "section": "logging",
+        "type": LType.Uint64,
+        "default": "6",
+        "help": "Amount of logging. Higher is more. Do not set below 3",
+        "doc": """
 Amount of logging. The higher the number, the more lines logged.
 Corresponds to ``syslog`` level values (e.g. 0 = ``emergency``, 1 = ``alert``, 2 = ``critical``, 3 = ``error``, 4 = ``warning``, 5 = ``notice``, 6 = ``info``, 7 = ``debug``).
 Each level includes itself plus the lower levels before it.
 Not recommended to set this below 3.
 If :ref:`setting-quiet` is ``no/false``, :ref:`setting-loglevel` will be minimally set to ``6 (info)``.
''',
-        'versionchanged': ('5.0.0', 'Previous version would not allow setting a level below ``3 (error)``.')
""",
+        "versionchanged": ("5.0.0", "Previous version would not allow setting a level below ``3 (error)``."),
     },
     {
-        'name' : 'common_errors',
-        'section' : 'logging',
-        'oldname' : 'log-common-errors',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'If we should log rather common errors',
-        'doc' : '''
+        "name": "common_errors",
+        "section": "logging",
+        "oldname": "log-common-errors",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "If we should log rather common errors",
+        "doc": """
 Some DNS errors occur rather frequently and are no cause for alarm.
''',
""",
     },
     {
-        'name' : 'rpz_changes',
-        'section' : 'logging',
-        'oldname' : 'log-rpz-changes',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Log additions and removals to RPZ zones at Info level',
-        'doc' : '''
+        "name": "rpz_changes",
+        "section": "logging",
+        "oldname": "log-rpz-changes",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Log additions and removals to RPZ zones at Info level",
+        "doc": """
 Log additions and removals to RPZ zones at Info (6) level instead of Debug (7).
''',
-    'versionadded': '4.1.0'
""",
+        "versionadded": "4.1.0",
     },
     {
-        'name' : 'facility',
-        'section' : 'logging',
-        'oldname' : 'logging-facility',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Facility to log messages as. 0 corresponds to local0',
-        'doc' : '''
+        "name": "facility",
+        "section": "logging",
+        "oldname": "logging-facility",
+        "type": LType.String,
+        "default": "",
+        "help": "Facility to log messages as. 0 corresponds to local0",
+        "doc": """
 If set to a digit, logging is performed under this LOCAL facility.
 See :ref:`logging`.
 Do not pass names like 'local0'!
''',
""",
     },
     {
-        'name' : 'lowercase',
-        'section' : 'outgoing',
-        'oldname' : 'lowercase-outgoing',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Force outgoing questions to lowercase',
-        'doc' : '''
+        "name": "lowercase",
+        "section": "outgoing",
+        "oldname": "lowercase-outgoing",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Force outgoing questions to lowercase",
+        "doc": """
 Set to true to lowercase the outgoing queries.
 When set to 'no' (the default) a query from a client using mixed case in the DNS labels (such as a user entering mixed-case names or `draft-vixie-dnsext-dns0x20-00 <http://tools.ietf.org/html/draft-vixie-dnsext-dns0x20-00>`_), PowerDNS preserves the case of the query.
 Broken authoritative servers might give a wrong or broken answer on this encoding.
 Setting ``lowercase-outgoing`` to 'yes' makes the PowerDNS Recursor lowercase all the labels in the query to the authoritative servers, but still return the proper case to the client requesting.
''',
""",
     },
     {
-        'name' : 'lua_config_file',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'More powerful configuration options',
-        'doc' : '''
+        "name": "lua_config_file",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "More powerful configuration options",
+        "doc": """
 If set, and Lua support is compiled in, this will load an additional configuration file for newer features and more complicated setups.
 See :doc:`lua-config/index` for the options that can be set in this file.
''',
""",
     },
     {
-        'name' : 'lua_global_include_dir',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'More powerful configuration options',
-        'doc' : '''
+        "name": "lua_global_include_dir",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "More powerful configuration options",
+        "doc": """
  When creating a Lua context, all ``*.lua`` files in the directory are loaded into the Lua context.
''',
""",
     },
     {
-        'name' : 'lua_dns_script',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Filename containing an optional Lua script that will be used to modify dns answers',
-        'doc' : '''
+        "name": "lua_dns_script",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Filename containing an optional Lua script that will be used to modify dns answers",
+        "doc": """
 Path to a lua file to manipulate the Recursor's answers. See :doc:`lua-scripting/index` for more information.
''',
""",
     },
     {
-        'name' : 'lua_maintenance_interval',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '1',
-        'help' : 'Number of seconds between calls to the lua user defined maintenance() function',
-        'doc' : '''
+        "name": "lua_maintenance_interval",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "1",
+        "help": "Number of seconds between calls to the lua user defined maintenance() function",
+        "doc": """
 The interval between calls to the Lua user defined `maintenance()` function in seconds.
 See :ref:`hooks-maintenance-callback`
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'max_busy_dot_probes',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Maximum number of concurrent DoT probes',
-        'doc' : '''
+        "name": "max_busy_dot_probes",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Maximum number of concurrent DoT probes",
+        "doc": """
 Limit the maximum number of simultaneous DoT probes the Recursor will schedule.
 The default value 0 means no DoT probes are scheduled.
 
@@ -1478,217 +1493,223 @@ In that case no probe will be scheduled.
 .. note::
   DoT probing is an experimental feature.
   Please test thoroughly to determine if it is suitable in your specific production environment before enabling.
''',
-    'versionadded': '4.7.0'
""",
+        "versionadded": "4.7.0",
     },
     {
-        'name' : 'max_cache_bogus_ttl',
-        'section' : 'recordcache',
-        'type' : LType.Uint64,
-        'default' : '3600',
-        'help' : 'maximum number of seconds to keep a Bogus (positive or negative) cached entry in memory',
-        'doc' : '''
+        "name": "max_cache_bogus_ttl",
+        "section": "recordcache",
+        "type": LType.Uint64,
+        "default": "3600",
+        "help": "maximum number of seconds to keep a Bogus (positive or negative) cached entry in memory",
+        "doc": """
 Maximum number of seconds to cache an item in the DNS cache (negative or positive) if its DNSSEC validation failed, no matter what the original TTL specified, to reduce the impact of a broken domain.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'max_entries',
-        'section' : 'recordcache',
-        'oldname' : 'max-cache-entries',
-        'type' : LType.Uint64,
-        'default' : '1000000',
-        'help' : 'If set, maximum number of entries in the main cache',
-        'doc' : '''
+        "name": "max_entries",
+        "section": "recordcache",
+        "oldname": "max-cache-entries",
+        "type": LType.Uint64,
+        "default": "1000000",
+        "help": "If set, maximum number of entries in the main cache",
+        "doc": """
 Maximum number of DNS record cache entries, shared by all threads since 4.4.0.
 Each entry associates a name and type with a record set.
 The size of the negative cache is 10% of this number.
''',
-        'runtime': 'set-max-cache-entries',
""",
+        "runtime": "set-max-cache-entries",
     },
     {
-        'name' : 'max_ttl',
-        'section' : 'recordcache',
-        'oldname' : 'max-cache-ttl',
-        'type' : LType.Uint64,
-        'default' : '86400',
-        'help' : 'maximum number of seconds to keep a cached entry in memory',
-        'doc' : '''
+        "name": "max_ttl",
+        "section": "recordcache",
+        "oldname": "max-cache-ttl",
+        "type": LType.Uint64,
+        "default": "86400",
+        "help": "maximum number of seconds to keep a cached entry in memory",
+        "doc": """
 Maximum number of seconds to cache an item in the DNS cache, no matter what the original TTL specified.
 This value also controls the refresh period of cached root data.
 See :ref:`handling-of-root-hints` for more information on this.
- ''',
-     'versionchanged': ('4.1.0', 'The minimum value of this setting is 15. i.e. setting this to lower than 15 will make this value 15.')
-    },
-    {
-        'name' : 'max_entry_size',
-        'section' : 'recordcache',
-        'oldname': 'max-recordcache-entry-size',
-        'type' : LType.Uint64,
-        'default' : '8192',
-        'help' : 'maximum storage size of a recordset stored in record cache',
-        'doc' : '''
+ """,
+        "versionchanged": (
+            "4.1.0",
+            "The minimum value of this setting is 15. i.e. setting this to lower than 15 will make this value 15.",
+        ),
+    },
+    {
+        "name": "max_entry_size",
+        "section": "recordcache",
+        "oldname": "max-recordcache-entry-size",
+        "type": LType.Uint64,
+        "default": "8192",
+        "help": "maximum storage size of a recordset stored in record cache",
+        "doc": """
 Maximum size of storage used by a single record cache entry. Entries larger than this number will not be stored.
 Zero means no limit.
-''',
-    'versionadded': ['5.1.10', '5.2.8', '5.3.5'],
+""",
+        "versionadded": ["5.1.10", "5.2.8", "5.3.5"],
     },
     {
-        'name' : 'max_concurrent_requests_per_tcp_connection',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '10',
-        'help' : 'Maximum number of requests handled concurrently per TCP connection',
-        'doc' : '''
+        "name": "max_concurrent_requests_per_tcp_connection",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "10",
+        "help": "Maximum number of requests handled concurrently per TCP connection",
+        "doc": """
 Maximum number of incoming requests handled concurrently per tcp
 connection. This number must be larger than 0 and smaller than 65536
 and also smaller than `max-mthreads`.
''',
-    'versionadded': '4.3.0'
""",
+        "versionadded": "4.3.0",
     },
     {
-        'name': 'max_chain_length',
-        'section': 'recursor',
-        'type': LType.Uint64,
-        'default': '0',
-        'help': 'maximum number of queries that can be chained to an outgoing request, 0 is no limit',
-        'doc': '''
+        "name": "max_chain_length",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "maximum number of queries that can be chained to an outgoing request, 0 is no limit",
+        "doc": """
 The maximum number of queries that can be attached to an outgoing request chain. Attaching requests to a chain
 saves on outgoing queries, but the processing of a chain when the reply to the outgoing query comes in
 might result in a large outgoing traffic spike. Reducing the maximum chain length mitigates this.
 If this value is zero, no maximum is enforced, though the maximum number of mthreads (:ref:`setting-max-mthreads`)
 also limits the chain length.
-''',
-        'versionadded': '5.1.0'
+""",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'max_include_depth',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '20',
-        'help' : 'Maximum nested $INCLUDE depth when loading a zone from a file',
-        'doc' : '''
+        "name": "max_include_depth",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "20",
+        "help": "Maximum nested $INCLUDE depth when loading a zone from a file",
+        "doc": """
 Maximum number of nested ``$INCLUDE`` directives while processing a zone file.
 Zero mean no ``$INCLUDE`` directives will be accepted.
''',
-    'versionadded': '4.6.0'
""",
+        "versionadded": "4.6.0",
     },
     {
-        'name' : 'max_generate_steps',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Maximum number of $GENERATE steps when loading a zone from a file',
-        'doc' : '''
+        "name": "max_generate_steps",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Maximum number of $GENERATE steps when loading a zone from a file",
+        "doc": """
 Maximum number of steps for a '$GENERATE' directive when parsing a
 zone file. This is a protection measure to prevent consuming a lot of
 CPU and memory when untrusted zones are loaded. Default to 0 which
 means unlimited.
''',
-    'versionadded': '4.3.0'
""",
+        "versionadded": "4.3.0",
     },
     {
-        'name' : 'max_mthreads',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '2048',
-        'help' : 'Maximum number of simultaneous Mtasker threads',
-        'doc' : '''
+        "name": "max_mthreads",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "2048",
+        "help": "Maximum number of simultaneous Mtasker threads",
+        "doc": """
 Maximum number of simultaneous MTasker threads, per worker thread.
''',
""",
     },
     {
-        'name' : 'max_entries',
-        'section' : 'packetcache',
-        'oldname' : 'max-packetcache-entries',
-        'type' : LType.Uint64,
-        'default' : '500000',
-        'help' : 'maximum number of entries to keep in the packetcache',
-        'doc' : '''
+        "name": "max_entries",
+        "section": "packetcache",
+        "oldname": "max-packetcache-entries",
+        "type": LType.Uint64,
+        "default": "500000",
+        "help": "maximum number of entries to keep in the packetcache",
+        "doc": """
 Maximum number of Packet Cache entries. Sharded and shared by all threads since 4.9.0.
-''',
-        'runtime': 'set-max-packetcache-entries',
+""",
+        "runtime": "set-max-packetcache-entries",
     },
     {
-        'name' : 'max_entry_size',
-        'section' : 'packetcache',
-        'oldname' : 'max-packetcache-entry-size',
-        'type' : LType.Uint64,
-        'default' : '8192',
-        'help' : 'maximum size of a packet stored in the the packet cache',
-        'doc' : '''
+        "name": "max_entry_size",
+        "section": "packetcache",
+        "oldname": "max-packetcache-entry-size",
+        "type": LType.Uint64,
+        "default": "8192",
+        "help": "maximum size of a packet stored in the the packet cache",
+        "doc": """
 Maximum size of packets stored in the packet cache. Packets larger than this number will not be stored.
 Zero means no limit.
-''',
-    'versionadded': ['5.1.10', '5.2.8', '5.3.5'],
+""",
+        "versionadded": ["5.1.10", "5.2.8", "5.3.5"],
     },
     {
-        'name' : 'max_qperq',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '50',
-        'help' : 'Maximum outgoing queries per client query',
-        'doc' : '''
+        "name": "max_qperq",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "50",
+        "help": "Maximum outgoing queries per client query",
+        "doc": """
 The maximum number of outgoing queries that will be sent out during the resolution of a single client query.
 This is used to avoid cycles resolving names.
- ''',
-        'versionchanged': ('5.1.0', 'The default used to be 60, with an extra allowance if qname minimization was enabled. Having better algorithms allows for a lower default limit.'),
-    },
-    {
-        'name' : 'max_bytesperq',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '100000',
-        'help' : 'Maximum number of received bytes per client query',
-        'doc' : '''
+ """,
+        "versionchanged": (
+            "5.1.0",
+            "The default used to be 60, with an extra allowance if qname minimization was enabled. Having better algorithms allows for a lower default limit.",
+        ),
+    },
+    {
+        "name": "max_bytesperq",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "100000",
+        "help": "Maximum number of received bytes per client query",
+        "doc": """
 The maximum number of cumulative bytes that will be accepted during the resolution of a single client query.
 This is useful to limit amplification attacks.
''',
-        'versionadded': ['5.1.10', '5.2.8', '5.3.5'],
""",
+        "versionadded": ["5.1.10", "5.2.8", "5.3.5"],
     },
     {
-        'name' : 'max_cnames_followed',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '10',
-        'help' : 'Maximum number CNAME records followed',
-        'doc' : '''
+        "name": "max_cnames_followed",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "10",
+        "help": "Maximum number CNAME records followed",
+        "doc": """
 Maximum length of a CNAME chain. If a CNAME chain exceeds this length, a ``ServFail`` answer will be returned.
 Previously, this limit was fixed at 10.
''',
-    'versionadded': '5.1.0'
""",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'limit_qtype_any',
-        'section' : 'recordcache',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Limit answers to ANY queries in size',
-        'doc' : '''
+        "name": "limit_qtype_any",
+        "section": "recordcache",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Limit answers to ANY queries in size",
+        "doc": """
 Limit answers to ANY queries constructed from the record cache in size.
 Trying to retrieve more than :ref:`setting-max-rrset-size` records will result in a ``ServFail``',
''',
-    'versionadded': ['4.9.9', '5.0.9', '5.1.2']
""",
+        "versionadded": ["4.9.9", "5.0.9", "5.1.2"],
     },
     {
-        'name' : 'max_rrset_size',
-        'section' : 'recordcache',
-        'type' : LType.Uint64,
-        'default' : '256',
-        'help' : 'Maximum size of RRSet in cache',
-        'doc' : '''
+        "name": "max_rrset_size",
+        "section": "recordcache",
+        "type": LType.Uint64,
+        "default": "256",
+        "help": "Maximum size of RRSet in cache",
+        "doc": """
 Maximum size of RRSets in cache.
 Trying to retrieve larger RRSets will result in a ``ServFail``.',
''',
-    'versionadded': ['4.9.9', '5.0.9', '5.1.2']
""",
+        "versionadded": ["4.9.9", "5.0.9", "5.1.2"],
     },
     {
-        'name' : 'max_ns_address_qperq',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '10',
-        'help' : 'Maximum outgoing NS address queries per query',
-        'doc' : '''
+        "name": "max_ns_address_qperq",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "10",
+        "help": "Maximum outgoing NS address queries per query",
+        "doc": """
 The maximum number of outgoing queries with empty replies for
 resolving nameserver names to addresses we allow during the resolution
 of a single client query. If IPv6 is enabled, an A and a AAAA query
@@ -1697,132 +1718,137 @@ NS records, the limit is further reduced for that zone by lowering
 it by the number of NS records found above the
 :ref:`setting-max-ns-address-qperq` value. The limit will not be reduced to a
 number lower than 5.
''',
-    'versionadded' : ['4.1.16', '4.2.2', '4.3.1']
""",
+        "versionadded": ["4.1.16", "4.2.2", "4.3.1"],
     },
     {
-        'name' : 'max_ns_per_resolve',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '13',
-        'help' : 'Maximum number of NS records to consider to resolve a name, 0 is no limit',
-        'doc' : '''
+        "name": "max_ns_per_resolve",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "13",
+        "help": "Maximum number of NS records to consider to resolve a name, 0 is no limit",
+        "doc": """
 The maximum number of NS records that will be considered to select a nameserver to contact to resolve a name.
 If a zone has more than :ref:`setting-max-ns-per-resolve` NS records, a random sample of this size will be used.
 If :ref:`setting-max-ns-per-resolve` is zero, no limit applies.
''',
-    'versionadded': ['4.8.0', '4.7.3', '4.6.4', '4.5.11']
""",
+        "versionadded": ["4.8.0", "4.7.3", "4.6.4", "4.5.11"],
     },
     {
-        'name' : 'max_negative_ttl',
-        'section' : 'recordcache',
-        'type' : LType.Uint64,
-        'default' : '3600',
-        'help' : 'maximum number of seconds to keep a negative cached entry in memory',
-        'doc' : '''
+        "name": "max_negative_ttl",
+        "section": "recordcache",
+        "type": LType.Uint64,
+        "default": "3600",
+        "help": "maximum number of seconds to keep a negative cached entry in memory",
+        "doc": """
 A query for which there is authoritatively no answer is cached to quickly deny a record's existence later on, without putting a heavy load on the remote server.
 In practice, caches can become saturated with hundreds of thousands of hosts which are tried only once.
 This setting, which defaults to 3600 seconds, puts a maximum on the amount of time negative entries are cached.
''',
""",
     },
     {
-        'name' : 'max_recursion_depth',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '16',
-        'help' : 'Maximum number of internal recursion calls per query, 0 for unlimited',
-        'doc' : '''
+        "name": "max_recursion_depth",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "16",
+        "help": "Maximum number of internal recursion calls per query, 0 for unlimited",
+        "doc": """
 Total maximum number of internal recursion calls the server may use to answer a single query.
 0 means unlimited.
 The value of :ref:`setting-stack-size` should be increased together with this one to prevent the stack from overflowing.
 If :ref:`setting-qname-minimization` is enabled, the fallback code in case of a failing resolve is allowed an additional `max-recursion-depth/2`.
- ''',
-     'versionchanged': [('4.1.0', 'Before 4.1.0, this settings was unlimited.'),
-                        ('4.9.0', "Before 4.9.0 this setting's default was 40 and the limit on ``CNAME`` chains (fixed at 16) acted as a bound on he recursion depth.")]
-    },
-    {
-        'name' : 'max_tcp_clients',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '1024',
-        'help' : 'Maximum number of simultaneous TCP clients',
-        'doc' : '''
+ """,
+        "versionchanged": [
+            ("4.1.0", "Before 4.1.0, this settings was unlimited."),
+            (
+                "4.9.0",
+                "Before 4.9.0 this setting's default was 40 and the limit on ``CNAME`` chains (fixed at 16) acted as a bound on he recursion depth.",
+            ),
+        ],
+    },
+    {
+        "name": "max_tcp_clients",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "1024",
+        "help": "Maximum number of simultaneous TCP clients",
+        "doc": """
 Maximum number of simultaneous incoming TCP connections allowed.
''',
-        'versionchanged': ('5.2.0', 'Before 5.2.0 the default was 128.'),
""",
+        "versionchanged": ("5.2.0", "Before 5.2.0 the default was 128."),
     },
     {
-        'name' : 'max_tcp_per_client',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'If set, maximum number of TCP sessions per client (IP address)',
-        'doc' : '''
+        "name": "max_tcp_per_client",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "If set, maximum number of TCP sessions per client (IP address)",
+        "doc": """
 Maximum number of simultaneous incoming TCP connections allowed per client (remote IP address).
 0 means unlimited.
''',
""",
     },
     {
-        'name' : 'max_tcp_queries_per_connection',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'If set, maximum number of TCP queries in a TCP connection',
-        'doc' : '''
+        "name": "max_tcp_queries_per_connection",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "If set, maximum number of TCP queries in a TCP connection",
+        "doc": """
 Maximum number of DNS queries in a TCP connection.
 0 means unlimited.
''',
-    'versionadded': '4.1.0'
""",
+        "versionadded": "4.1.0",
     },
     {
-        'name' : 'max_total_msec',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '7000',
-        'help' : 'Maximum total wall-clock time per query in milliseconds, 0 for unlimited',
-        'doc' : '''
+        "name": "max_total_msec",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "7000",
+        "help": "Maximum total wall-clock time per query in milliseconds, 0 for unlimited",
+        "doc": """
 Total maximum number of milliseconds of wallclock time the server may use to answer a single query.
 0 means unlimited.
''',
""",
     },
     {
-        'name' : 'max_udp_queries_per_round',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '10000',
-        'help' : 'Maximum number of UDP queries processed per recvmsg() round, before returning back to normal processing',
-        'doc' : '''
+        "name": "max_udp_queries_per_round",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "10000",
+        "help": "Maximum number of UDP queries processed per recvmsg() round, before returning back to normal processing",
+        "doc": """
 Under heavy load the recursor might be busy processing incoming UDP queries for a long while before there is no more of these, and might therefore
 neglect scheduling new ``mthreads``, handling responses from authoritative servers or responding to :doc:`rec_control <manpages/rec_control.1>`
 requests.
 This setting caps the maximum number of incoming UDP DNS queries processed in a single round of looping on ``recvmsg()`` after being woken up by the multiplexer, before
 returning back to normal processing and handling other events.
''',
-    'versionadded': '4.1.4'
""",
+        "versionadded": "4.1.4",
     },
     {
-        'name' : 'minimum_ttl_override',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '1',
-        'help' : 'The minimum TTL',
-        'doc' : '''
+        "name": "minimum_ttl_override",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "1",
+        "help": "The minimum TTL",
+        "doc": """
 This setting artificially raises all TTLs to be at least this long.
 Setting this to a value greater than 1 technically is an RFC violation, but might improve performance a lot.
 Using a value of 0 impacts performance of TTL 0 records greatly, since it forces the recursor to contact
 authoritative servers each time a client requests them.
''',
-        'versionchanged': ('4.5.0', 'Old versions used default 0.'),
-        'runtime': 'set-minimum-ttl',
-    },
-    {
-        'name' : 'tracking',
-        'section' : 'nod',
-        'oldname' : 'new-domain-tracking',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Track newly observed domains (i.e. never seen before).',
-        'doc' : '''
""",
+        "versionchanged": ("4.5.0", "Old versions used default 0."),
+        "runtime": "set-minimum-ttl",
+    },
+    {
+        "name": "tracking",
+        "section": "nod",
+        "oldname": "new-domain-tracking",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Track newly observed domains (i.e. never seen before).",
+        "doc": """
 Whether to track newly observed domains, i.e. never seen before. This
 is a probabilistic algorithm, using a stable bloom filter to store
 records of previously seen domains. When enabled for the first time,
@@ -1832,32 +1858,32 @@ that this feature is optional and must be enabled at compile-time,
 thus it may not be available in all pre-built packages.
 If protobuf is enabled and configured, then the newly observed domain
 status will appear as a flag in Response messages.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'log',
-        'section' : 'nod',
-        'oldname' : 'new-domain-log',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Log newly observed domains.',
-        'doc' : '''
+        "name": "log",
+        "section": "nod",
+        "oldname": "new-domain-log",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Log newly observed domains.",
+        "doc": """
 If a newly observed domain is detected, log that domain in the
 recursor log file. The log line looks something like::
 
  Jul 18 11:31:25 Newly observed domain nod=sdfoijdfio.com
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'lookup',
-        'section' : 'nod',
-        'oldname' : 'new-domain-lookup',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Perform a DNS lookup newly observed domains as a subdomain of the configured domain',
-        'doc' : '''
+        "name": "lookup",
+        "section": "nod",
+        "oldname": "new-domain-lookup",
+        "type": LType.String,
+        "default": "",
+        "help": "Perform a DNS lookup newly observed domains as a subdomain of the configured domain",
+        "doc": """
 If a domain is specified, then each time a newly observed domain is
 detected, the recursor will perform an A record lookup of '<newly
 observed domain>.<lookup domain>'. For example if 'new-domain-lookup'
@@ -1866,35 +1892,35 @@ detected, then an A record lookup will be made for
 'example.com.nod.powerdns.com'. This feature gives a way to share the
 newly observed domain with partners, vendors or security teams. The
 result of the DNS lookup will be ignored by the recursor.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'db_size',
-        'section' : 'nod',
-        'oldname' : 'new-domain-db-size',
-        'type' : LType.Uint64,
-        'default' : '67108864',
-        'help' : 'Size of the DB used to track new domains in terms of number of cells. Defaults to 67108864',
-        'doc' : '''
+        "name": "db_size",
+        "section": "nod",
+        "oldname": "new-domain-db-size",
+        "type": LType.Uint64,
+        "default": "67108864",
+        "help": "Size of the DB used to track new domains in terms of number of cells. Defaults to 67108864",
+        "doc": """
 The default size of the stable bloom filter used to store previously
 observed domains is 67108864. To change the number of cells, use this
 setting. For each cell, the SBF uses 1 bit of memory, and one byte of
 disk for the persistent file.
 If there are already persistent files saved to disk, this setting will
 have no effect unless you remove the existing files.
''',
-    'versionadded': '4.2.0'
-    },
-    {
-        'name' : 'history_dir',
-        'section' : 'nod',
-        'oldname' : 'new-domain-history-dir',
-        'type' : LType.String,
-        'default' : 'NODCACHEDIRNOD',
-        'docdefault': 'Determined by distribution',
-        'help' : 'Persist new domain tracking data here to persist between restarts',
-        'doc' : '''
""",
+        "versionadded": "4.2.0",
+    },
+    {
+        "name": "history_dir",
+        "section": "nod",
+        "oldname": "new-domain-history-dir",
+        "type": LType.String,
+        "default": "NODCACHEDIRNOD",
+        "docdefault": "Determined by distribution",
+        "help": "Persist new domain tracking data here to persist between restarts",
+        "doc": """
 This setting controls which directory is used to store the on-disk
 cache of previously observed domains.
 
@@ -1908,116 +1934,116 @@ disk on startup. This ensures that previously observed domains are
 preserved across recursor restarts.
 If you change the new-domain-db-size setting, you must remove any files
 from this directory.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'db_snapshot_interval',
-        'section' : 'nod',
-        'oldname' : 'new-domain-db-snapshot-interval',
-        'type' : LType.Uint64,
-        'default' : '600',
-        'help' : 'Interval (in seconds) to write the NOD and UDR DB snapshots',
-        'doc' : '''
+        "name": "db_snapshot_interval",
+        "section": "nod",
+        "oldname": "new-domain-db-snapshot-interval",
+        "type": LType.Uint64,
+        "default": "600",
+        "help": "Interval (in seconds) to write the NOD and UDR DB snapshots",
+        "doc": """
 Interval (in seconds) to write the NOD and UDR DB snapshots.
 Set to zero to disable snapshot writing.',
''',
-    'versionadded': '5.1.0'
""",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'ignore_list',
-        'section' : 'nod',
-        'oldname' : 'new-domain-ignore-list',
-        'type' : LType.ListStrings,
-        'default' : '',
-        'help' : 'List of domains (and implicitly all subdomains) which will never be considered a new domain',
-        'doc' : '''
+        "name": "ignore_list",
+        "section": "nod",
+        "oldname": "new-domain-ignore-list",
+        "type": LType.ListStrings,
+        "default": "",
+        "help": "List of domains (and implicitly all subdomains) which will never be considered a new domain",
+        "doc": """
 This setting is a list of all domains (and implicitly all subdomains)
 that will never be considered a new domain. For example, if the domain
 'example.com' is in the list, then 'foo.bar.example.com' will never be
 considered a new domain. One use-case for the ignore list is to never
 reveal details of internal subdomains via the new-domain-lookup
 feature.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'ignore_list_file',
-        'section' : 'nod',
-        'type' : LType.String,
-        'oldname' : 'new-domain-ignore-list-file',
-        'default' : '',
-        'help' : 'File with a list of domains (and implicitly all subdomains) which will never be considered a new domain',
-        'doc' : '''
+        "name": "ignore_list_file",
+        "section": "nod",
+        "type": LType.String,
+        "oldname": "new-domain-ignore-list-file",
+        "default": "",
+        "help": "File with a list of domains (and implicitly all subdomains) which will never be considered a new domain",
+        "doc": """
 Path to a file with a list of domains. File should have one domain per line,
 with no extra characters or comments.
 See :ref:`setting-new-domain-ignore-list`.
''',
-    'versionadded': '5.1.0'
""",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'pb_tag',
-        'section' : 'nod',
-        'oldname' : 'new-domain-pb-tag',
-        'type' : LType.String,
-        'default' : 'pdns-nod',
-        'help' : 'If protobuf is configured, the tag to use for messages containing newly observed domains. Defaults to \'pdns-nod\'',
-        'doc' : '''
+        "name": "pb_tag",
+        "section": "nod",
+        "oldname": "new-domain-pb-tag",
+        "type": LType.String,
+        "default": "pdns-nod",
+        "help": "If protobuf is configured, the tag to use for messages containing newly observed domains. Defaults to 'pdns-nod'",
+        "doc": """
 If protobuf is configured, then this tag will be added to all protobuf response messages when
 a new domain is observed.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'network_timeout',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '1500',
-        'help' : 'Wait this number of milliseconds for network i/o',
-        'doc' : '''
+        "name": "network_timeout",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "1500",
+        "help": "Wait this number of milliseconds for network i/o",
+        "doc": """
 Number of milliseconds to wait for a remote authoritative server to respond.
 If the number of concurrent requests is high, the :program:Recursor uses a lower value.
''',
""",
     },
     {
-        'name' : 'no_shuffle',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Don\'t change',
-        'doc' : 'SKIP',
-        'skip-yaml': True,
+        "name": "no_shuffle",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Don't change",
+        "doc": "SKIP",
+        "skip-yaml": True,
     },
     {
-        'name' : 'non_resolving_ns_max_fails',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '5',
-        'help' : 'Number of failed address resolves of a nameserver to start throttling it, 0 is disabled',
-        'doc' : '''
+        "name": "non_resolving_ns_max_fails",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "5",
+        "help": "Number of failed address resolves of a nameserver to start throttling it, 0 is disabled",
+        "doc": """
 Number of failed address resolves of a nameserver name to start throttling it, 0 is disabled.
 Nameservers matching :ref:`setting-dont-throttle-names` will not be throttled.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'non_resolving_ns_throttle_time',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '60',
-        'help' : 'Number of seconds to throttle a nameserver with a name failing to resolve',
-        'doc' : '''
+        "name": "non_resolving_ns_throttle_time",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "60",
+        "help": "Number of seconds to throttle a nameserver with a name failing to resolve",
+        "doc": """
 Number of seconds to throttle a nameserver with a name failing to resolve.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'nothing_below_nxdomain',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : 'dnssec',
-        'help' : 'When an NXDOMAIN exists in cache for a name with fewer labels than the qname, send NXDOMAIN without doing a lookup (see RFC 8020)',
-        'doc' : '''
+        "name": "nothing_below_nxdomain",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "dnssec",
+        "help": "When an NXDOMAIN exists in cache for a name with fewer labels than the qname, send NXDOMAIN without doing a lookup (see RFC 8020)",
+        "doc": """
 - One of ``no``, ``dnssec``, ``yes``.
 
 The type of :rfc:`8020` handling using cached NXDOMAIN responses.
@@ -2038,289 +2064,293 @@ without consulting authoritative servers.
 ``yes``
   :rfc:`8020` processing is done using any non-Bogus NXDOMAIN record
   available in the cache.
''',
-    'versionadded': '4.3.0'
""",
+        "versionadded": "4.3.0",
     },
     {
-        'name' : 'nsec3_max_iterations',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '50',
-        'help' : 'Maximum number of iterations allowed for an NSEC3 record',
-        'doc' : '''
+        "name": "nsec3_max_iterations",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "50",
+        "help": "Maximum number of iterations allowed for an NSEC3 record",
+        "doc": """
 Maximum number of iterations allowed for an NSEC3 record.
 If an answer containing an NSEC3 record with more iterations is received, its DNSSEC validation status is treated as ``Insecure``.
- ''',
-        'versionadded': '4.1.0',
-        'versionchanged': [('4.5.2', 'Default is now 150, was 2500 before.'),
-                           ('5.0.0', 'Default is now 50, was 150 before.')]
-    },
-    {
-        'name' : 'max_rrsigs_per_record',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '2',
-        'help' : 'Maximum number of RRSIGs to consider when validating a given record',
-        'doc' : '''
+ """,
+        "versionadded": "4.1.0",
+        "versionchanged": [
+            ("4.5.2", "Default is now 150, was 2500 before."),
+            ("5.0.0", "Default is now 50, was 150 before."),
+        ],
+    },
+    {
+        "name": "max_rrsigs_per_record",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "2",
+        "help": "Maximum number of RRSIGs to consider when validating a given record",
+        "doc": """
 Maximum number of RRSIGs we are willing to cryptographically check when validating a given record. Expired or not yet incepted RRSIGs do not count toward to this limit.
''',
-        'versionadded': ['5.0.2', '4.9.3', '4.8.6'],
""",
+        "versionadded": ["5.0.2", "4.9.3", "4.8.6"],
     },
     {
-        'name' : 'max_nsec3s_per_record',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '10',
-        'help' : 'Maximum number of NSEC3s to consider when validating a given denial of existence',
-        'doc' : '''
+        "name": "max_nsec3s_per_record",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "10",
+        "help": "Maximum number of NSEC3s to consider when validating a given denial of existence",
+        "doc": """
 Maximum number of NSEC3s to consider when validating a given denial of existence.
''',
-        'versionadded': ['5.0.2', '4.9.3', '4.8.6'],
""",
+        "versionadded": ["5.0.2", "4.9.3", "4.8.6"],
     },
     {
-        'name' : 'max_signature_validations_per_query',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '30',
-        'help' : 'Maximum number of RRSIG signatures we are willing to validate per incoming query',
-        'doc' : '''
+        "name": "max_signature_validations_per_query",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "30",
+        "help": "Maximum number of RRSIG signatures we are willing to validate per incoming query",
+        "doc": """
 Maximum number of RRSIG signatures we are willing to validate per incoming query.
''',
-        'versionadded': ['5.0.2', '4.9.3', '4.8.6'],
""",
+        "versionadded": ["5.0.2", "4.9.3", "4.8.6"],
     },
     {
-        'name' : 'max_nsec3_hash_computations_per_query',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '600',
-        'help' : 'Maximum number of NSEC3 hashes that we are willing to compute during DNSSEC validation, per incoming query',
-        'doc' : '''
+        "name": "max_nsec3_hash_computations_per_query",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "600",
+        "help": "Maximum number of NSEC3 hashes that we are willing to compute during DNSSEC validation, per incoming query",
+        "doc": """
 Maximum number of NSEC3 hashes that we are willing to compute during DNSSEC validation, per incoming query.
''',
-        'versionadded': ['5.0.2', '4.9.3', '4.8.6'],
""",
+        "versionadded": ["5.0.2", "4.9.3", "4.8.6"],
     },
     {
-        'name' : 'aggressive_cache_max_nsec3_hash_cost',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '150',
-        'help' : 'Maximum estimated NSEC3 cost for a given query to consider aggressive use of the NSEC3 cache',
-        'doc' : '''
+        "name": "aggressive_cache_max_nsec3_hash_cost",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "150",
+        "help": "Maximum estimated NSEC3 cost for a given query to consider aggressive use of the NSEC3 cache",
+        "doc": """
 Maximum estimated NSEC3 cost for a given query to consider aggressive use of the NSEC3 cache. The cost is estimated based on a heuristic taking the zone's NSEC3 salt and iterations parameters into account, as well at the number of labels of the requested name. For example a query for a name like a.b.c.d.e.f.example.com. in an example.com zone. secured with NSEC3 and 10 iterations (NSEC3 iterations count of 9) and an empty salt will have an estimated worst-case cost of 10 (iterations) * 6 (number of labels) = 60. The aggressive NSEC cache is an optimization to reduce the number of queries to authoritative servers, which is especially useful when a zone is under pseudo-random subdomain attack, and we want to skip it the zone parameters make it expensive.
-''',
-        'versionadded': ['5.0.2', '4.9.3', '4.8.6'],
+""",
+        "versionadded": ["5.0.2", "4.9.3", "4.8.6"],
     },
     {
-        'name' : 'max_ds_per_zone',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '8',
-        'help' : 'Maximum number of DS records to consider per zone',
-        'doc' : '''
+        "name": "max_ds_per_zone",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "8",
+        "help": "Maximum number of DS records to consider per zone",
+        "doc": """
 Maximum number of DS records to consider when validating records inside a zone.
''',
-        'versionadded': ['5.0.2', '4.9.3', '4.8.6'],
""",
+        "versionadded": ["5.0.2", "4.9.3", "4.8.6"],
     },
     {
-        'name' : 'max_dnskeys',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '2',
-        'help' : 'Maximum number of DNSKEYs with the same algorithm and tag to consider when validating a given record',
-        'doc' : '''
+        "name": "max_dnskeys",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "2",
+        "help": "Maximum number of DNSKEYs with the same algorithm and tag to consider when validating a given record",
+        "doc": """
 Maximum number of DNSKEYs with the same algorithm and tag to consider when validating a given record. Setting this value to 1 effectively denies DNSKEY tag collisions in a zone.
''',
-        'versionadded': ['5.0.2', '4.9.3', '4.8.6'],
""",
+        "versionadded": ["5.0.2", "4.9.3", "4.8.6"],
     },
     {
-        'name' : 'ttl',
-        'section' : 'packetcache',
-        'oldname' : 'packetcache-ttl',
-        'type' : LType.Uint64,
-        'default' : '86400',
-        'help' : 'maximum number of seconds to keep a cached entry in packetcache',
-        'doc' : '''
+        "name": "ttl",
+        "section": "packetcache",
+        "oldname": "packetcache-ttl",
+        "type": LType.Uint64,
+        "default": "86400",
+        "help": "maximum number of seconds to keep a cached entry in packetcache",
+        "doc": """
 Maximum number of seconds to cache an item in the packet cache, no matter what the original TTL specified.
''',
-        'versionchanged': ('4.9.0', 'The default was changed from 3600 (1 hour) to 86400 (24 hours).')
""",
+        "versionchanged": ("4.9.0", "The default was changed from 3600 (1 hour) to 86400 (24 hours)."),
     },
     {
-        'name' : 'negative_ttl',
-        'section' : 'packetcache',
-        'oldname' : 'packetcache-negative-ttl',
-        'type' : LType.Uint64,
-        'default' : '60',
-        'help' : 'maximum number of seconds to keep a cached NxDomain or NoData entry in packetcache',
-        'doc' : '''
+        "name": "negative_ttl",
+        "section": "packetcache",
+        "oldname": "packetcache-negative-ttl",
+        "type": LType.Uint64,
+        "default": "60",
+        "help": "maximum number of seconds to keep a cached NxDomain or NoData entry in packetcache",
+        "doc": """
 Maximum number of seconds to cache an ``NxDomain`` or ``NoData`` (a ``NoError`` response without answer records) answer in the packetcache.
 This setting's maximum is capped to :ref:`setting-packetcache-ttl`.
 i.e. setting :ref:`setting-packetcache-ttl` to 15 and keeping :ref:`setting-packetcache-negative-ttl` at the default will lower the used value of :ref:`setting-packetcache-negative-ttl` to 15.
''',
-    'versionadded': '4.9.0'
""",
+        "versionadded": "4.9.0",
     },
     {
-        'name' : 'servfail_ttl',
-        'section' : 'packetcache',
-        'oldname' : 'packetcache-servfail-ttl',
-        'type' : LType.Uint64,
-        'default' : '60',
-        'help' : 'maximum number of seconds to keep a cached servfail entry in packetcache',
-        'doc' : '''
+        "name": "servfail_ttl",
+        "section": "packetcache",
+        "oldname": "packetcache-servfail-ttl",
+        "type": LType.Uint64,
+        "default": "60",
+        "help": "maximum number of seconds to keep a cached servfail entry in packetcache",
+        "doc": """
 Maximum number of seconds to cache an answer indicating a failure to resolve in the packet cache.
 Before version 4.6.0 only ``ServFail`` answers were considered as such. All responses with a code other than ``NoError`` and ``NXDomain``, or without records in the answer and authority sections, are considered as a failure to resolve.
 This setting's maximum is capped to :ref:`setting-packetcache-ttl`. Setting :ref:`setting-packetcache-ttl` to 15 and keeping :ref:`setting-packetcache-servfail-ttl` at the default will lower the used value of :ref:`setting-packetcache-servfail-ttl` to 15.
 Since 4.9.0, negative answers are handled separately from resolving failures.
-''',
+""",
     },
     {
-        'name' : 'shards',
-        'section' : 'packetcache',
-        'oldname' : 'packetcache-shards',
-        'type' : LType.Uint64,
-        'default' : '1024',
-        'help' : 'Number of shards in the packet cache',
-        'doc' : '''
+        "name": "shards",
+        "section": "packetcache",
+        "oldname": "packetcache-shards",
+        "type": LType.Uint64,
+        "default": "1024",
+        "help": "Number of shards in the packet cache",
+        "doc": """
 Sets the number of shards in the packet cache. If you have high contention as reported by ``packetcache-contented/packetcache-acquired``,
 you can try to enlarge this value or run with fewer threads.
''',
-    'versionadded': '4.9.0'
""",
+        "versionadded": "4.9.0",
     },
     {
-        'name' : 'pdns_distributes_queries',
-        'section' : 'incoming',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'If PowerDNS itself should distribute queries over threads',
-        'doc' : '''
+        "name": "pdns_distributes_queries",
+        "section": "incoming",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "If PowerDNS itself should distribute queries over threads",
+        "doc": """
 If set, PowerDNS will use distinct threads to listen to client sockets and distribute that work to worker-threads using a hash of the query.
 This feature should maximize the cache hit ratio on versions before 4.9.0.
 To use more than one thread set :ref:`setting-distributor-threads` in version 4.2.0 or newer.
 Enabling should improve performance on systems where :ref:`setting-reuseport` does not have the effect of
 balancing the queries evenly over multiple worker threads.
''',
-     'versionchanged': ('4.9.0', 'Default changed to ``no``, previously it was ``yes``.')
""",
+        "versionchanged": ("4.9.0", "Default changed to ``no``, previously it was ``yes``."),
     },
     {
-        'name' : 'processes',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '1',
-        'help' : 'Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)',
-        'doc' : '''SKIP''',
-        'skip-yaml': True,
+        "name": "processes",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "1",
+        "help": "Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)",
+        "doc": """SKIP""",
+        "skip-yaml": True,
     },
     {
-        'name' : 'protobuf_use_kernel_timestamp',
-        'section' : 'logging',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Compute the latency of queries in protobuf messages by using the timestamp set by the kernel when the query was received (when available)',
-        'doc' : '''
+        "name": "protobuf_use_kernel_timestamp",
+        "section": "logging",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Compute the latency of queries in protobuf messages by using the timestamp set by the kernel when the query was received (when available)",
+        "doc": """
 Whether to compute the latency of responses in protobuf messages using the timestamp set by the kernel when the query packet was received (when available), instead of computing it based on the moment we start processing the query.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'proxy_protocol_from',
-        'section' : 'incoming',
-        'type' : LType.ListSubnets,
-        'default' : '',
-        'help' : 'A Proxy Protocol header is required from these subnets',
-        'doc' : '''
+        "name": "proxy_protocol_from",
+        "section": "incoming",
+        "type": LType.ListSubnets,
+        "default": "",
+        "help": "A Proxy Protocol header is required from these subnets",
+        "doc": """
 Ranges that are required to send a Proxy Protocol version 2 header in front of UDP and TCP queries, to pass the original source and destination addresses and ports to the recursor, as well as custom values.
 Queries that are not prefixed with such a header will not be accepted from clients in these ranges. Queries prefixed by headers from clients that are not listed in these ranges will be dropped.
 
 Note that once a Proxy Protocol header has been received, the source address from the proxy header instead of the address of the proxy will be checked against the :ref:`setting-allow-from` ACL.
 
 The dnsdist docs have `more information about the PROXY protocol <https://dnsdist.org/advanced/passing-source-address.html#proxy-protocol>`_.
- ''',
-        'versionadded' : '4.4.0',
-        'versionchanged' : [('5.0.5', 'YAML settings only: previously this was defined as a string instead of a sequence'),
-                            ('5.3.0', '``rec_control reload-acls`` reloads this setting')],
-        'runtime': ['reload-acls (since 5.3.0)'],
-    },
-    {
-        'name' : 'proxy_protocol_exceptions',
-        'section' : 'incoming',
-        'type' : LType.ListSocketAddresses,
-        'default' : '',
-        'help' : 'A Proxy Protocol header should not be used for these listen addresses.',
-        'doc' : '''
+ """,
+        "versionadded": "4.4.0",
+        "versionchanged": [
+            ("5.0.5", "YAML settings only: previously this was defined as a string instead of a sequence"),
+            ("5.3.0", "``rec_control reload-acls`` reloads this setting"),
+        ],
+        "runtime": ["reload-acls (since 5.3.0)"],
+    },
+    {
+        "name": "proxy_protocol_exceptions",
+        "section": "incoming",
+        "type": LType.ListSocketAddresses,
+        "default": "",
+        "help": "A Proxy Protocol header should not be used for these listen addresses.",
+        "doc": """
 If set, clients sending from an address in :ref:`setting-proxy-protocol-from` to an address:port listed here are excluded from using the Proxy Protocol.
 If no port is specified, port 53 is assumed.
 This is typically used to provide an easy to use address and port to send debug queries to.
''',
-        'versionadded' : '5.1.0',
-        'versionchanged' : ('5.3.0', '``rec_control reload-acls`` reloads this setting'),
-        'runtime': ['reload-acls (since 5.3.0)'],
-    },
-    {
-        'name' : 'proxy_protocol_maximum_size',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '512',
-        'help' : 'The maximum size of a proxy protocol payload, including the TLV values',
-        'doc' : '''
""",
+        "versionadded": "5.1.0",
+        "versionchanged": ("5.3.0", "``rec_control reload-acls`` reloads this setting"),
+        "runtime": ["reload-acls (since 5.3.0)"],
+    },
+    {
+        "name": "proxy_protocol_maximum_size",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "512",
+        "help": "The maximum size of a proxy protocol payload, including the TLV values",
+        "doc": """
 The maximum size, in bytes, of a Proxy Protocol payload (header, addresses and ports, and TLV values). Queries with a larger payload will be dropped.
''',
-    'versionadded': '4.4.0'
""",
+        "versionadded": "4.4.0",
     },
     {
-        'name' : 'public_suffix_list_file',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Path to the Public Suffix List file, if any',
-        'doc' : '''
+        "name": "public_suffix_list_file",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Path to the Public Suffix List file, if any",
+        "doc": """
 Path to the Public Suffix List file, if any. If set, PowerDNS will try to load the Public Suffix List from this file instead of using the built-in list. The PSL is used to group the queries by relevant domain names when displaying the top queries.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'qname_minimization',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Use Query Name Minimization',
-        'doc' : '''
+        "name": "qname_minimization",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Use Query Name Minimization",
+        "doc": """
 Enable Query Name Minimization. This implements a relaxed form of Query Name Mimimization as
 described in :rfc:`9156`.
''',
-    'versionadded': '4.3.0'
""",
+        "versionadded": "4.3.0",
     },
     {
-        'name' : 'qname_max_minimize_count',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '10',
-        'help' : 'RFC9156 max minimize count',
-        'doc' : '''
+        "name": "qname_max_minimize_count",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "10",
+        "help": "RFC9156 max minimize count",
+        "doc": """
 ``Max minimize count`` parameter, described in :rfc:`9156`. This is the maximum number of iterations
 of the Query Name Minimization Algorithm.
''',
-    'versionadded': '5.0.0'
""",
+        "versionadded": "5.0.0",
     },
     {
-        'name' : 'qname_minimize_one_label',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '4',
-        'help' : 'RFC9156 minimize one label parameter',
-        'doc' : '''
+        "name": "qname_minimize_one_label",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "4",
+        "help": "RFC9156 minimize one label parameter",
+        "doc": """
 ``Minimize one label`` parameter, described in :rfc:`9156`.
 The value for the number of iterations of the Query Name Minimization Algorithm that should only have one label appended.
 This value has precedence over :ref:`setting-qname-max-minimize-count`.
''',
-    'versionadded': '5.0.0'
""",
+        "versionadded": "5.0.0",
     },
     {
-        'name' : 'source_address',
-        'section' : 'outgoing',
-        'oldname' : 'query-local-address',
-        'type' : LType.ListSubnets,
-        'default' : '0.0.0.0',
-        'help' : 'Source IP address for sending queries',
-        'doc' : '''
+        "name": "source_address",
+        "section": "outgoing",
+        "oldname": "query-local-address",
+        "type": LType.ListSubnets,
+        "default": "0.0.0.0",
+        "help": "Source IP address for sending queries",
+        "doc": """
 .. note::
     While subnets and their negations are mentioned as accepted, the handling of subnets has not been implemented yet.
     Only individual IP addresses can be listed.
@@ -2329,27 +2359,27 @@ Send out local queries from this address, or addresses. By adding multiple
 addresses, increased spoofing resilience is achieved. When no address of a certain
 address family is configured, there are *no* queries sent with that address family.
 In the default configuration this means that IPv6 is not used for outgoing queries.
''',
-     'versionchanged': ('4.4.0', 'IPv6 addresses can be set with this option as well.')
""",
+        "versionchanged": ("4.4.0", "IPv6 addresses can be set with this option as well."),
     },
     {
-        'name' : 'quiet',
-        'section' : 'logging',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Suppress logging of questions and answers',
-        'doc' : '''
+        "name": "quiet",
+        "section": "logging",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Suppress logging of questions and answers",
+        "doc": """
 Don't log queries.
''',
""",
     },
     {
-        'name' : 'locked_ttl_perc',
-        'section' : 'recordcache',
-        'oldname' : 'record-cache-locked-ttl-perc',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Replace records in record cache only after this % of original TTL has passed',
-        'doc' : '''
+        "name": "locked_ttl_perc",
+        "section": "recordcache",
+        "oldname": "record-cache-locked-ttl-perc",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Replace records in record cache only after this % of original TTL has passed",
+        "doc": """
 Replace record sets in the record cache only after this percentage of the original TTL has passed.
 The PowerDNS Recursor already has several mechanisms to protect against spoofing attempts.
 This adds an extra layer of protection---as it limits the window of time cache updates are accepted---at the cost of a less efficient record cache.
@@ -2364,180 +2394,183 @@ There are a few cases where records will be replaced anyway:
 - Authoritative record sets will replace unauthoritative record sets unless DNSSEC validation of the new record set failed.
 - If the new record set belongs to a DNSSEC-secure zone and successfully passed validation it will replace an existing entry.
 - Record sets produced by :ref:`setting-refresh-on-ttl-perc` tasks will also replace existing record sets.
''',
-    'versionadded': '4.8.0'
""",
+        "versionadded": "4.8.0",
     },
     {
-        'name' : 'shards',
-        'section' : 'recordcache',
-        'oldname' : 'record-cache-shards',
-        'type' : LType.Uint64,
-        'default' : '1024',
-        'help' : 'Number of shards in the record cache',
-        'doc' : '''
+        "name": "shards",
+        "section": "recordcache",
+        "oldname": "record-cache-shards",
+        "type": LType.Uint64,
+        "default": "1024",
+        "help": "Number of shards in the record cache",
+        "doc": """
 Sets the number of shards in the record cache. If you have high
 contention as reported by
 ``record-cache-contented/record-cache-acquired``, you can try to
 enlarge this value or run with fewer threads.
''',
-    'versionadded': '4.4.0'
""",
+        "versionadded": "4.4.0",
     },
     {
-        'name' : 'refresh_on_ttl_perc',
-        'section' : 'recordcache',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'If a record is requested from the cache and only this % of original TTL remains, refetch',
-        'doc' : '''
+        "name": "refresh_on_ttl_perc",
+        "section": "recordcache",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "If a record is requested from the cache and only this % of original TTL remains, refetch",
+        "doc": """
 Sets the 'refresh almost expired' percentage of the record cache. Whenever a record is fetched from the packet or record cache
 and only ``refresh-on-ttl-perc`` percent or less of its original TTL is left, a task is queued to refetch the name/type combination to
 update the record cache. In most cases this causes future queries to always see a non-expired record cache entry.
 A typical value is 10. If the value is zero, this functionality is disabled.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'reuseport',
-        'section' : 'incoming',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address',
-        'doc' : '''
+        "name": "reuseport",
+        "section": "incoming",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address",
+        "doc": """
 If ``SO_REUSEPORT`` support is available, allows multiple threads and processes to open listening sockets for the same port.
 
 Since 4.1.0, when :ref:`setting-pdns-distributes-queries` is disabled and :ref:`setting-reuseport` is enabled, every worker-thread will open a separate listening socket to let the kernel distribute the incoming queries instead of running a distributor thread (which could otherwise be a bottleneck) and avoiding thundering herd issues, thus leading to much higher performance on multi-core boxes.
- ''',
-     'versionchanged': ('4.9.0', 'The default is changed to ``yes``, previously it was ``no``. If ``SO_REUSEPORT`` support is not available, the setting defaults to ``no``.')
-    },
-    {
-        'name' : 'rng',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : 'auto',
-        'help' : '',
-        'doc' : '''
- ''',
-        'skip-yaml': True,
-        'versionchanged': ('4.9.0', 'This setting is no longer used.')
-    },
-    {
-        'name' : 'root_nx_trust',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'If set, believe that an NXDOMAIN from the root means the TLD does not exist',
-        'doc' : '''
+ """,
+        "versionchanged": (
+            "4.9.0",
+            "The default is changed to ``yes``, previously it was ``no``. If ``SO_REUSEPORT`` support is not available, the setting defaults to ``no``.",
+        ),
+    },
+    {
+        "name": "rng",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "auto",
+        "help": "",
+        "doc": """
+ """,
+        "skip-yaml": True,
+        "versionchanged": ("4.9.0", "This setting is no longer used."),
+    },
+    {
+        "name": "root_nx_trust",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "If set, believe that an NXDOMAIN from the root means the TLD does not exist",
+        "doc": """
 If set, an NXDOMAIN from the root-servers will serve as a blanket NXDOMAIN for the entire TLD the query belonged to.
 The effect of this is far fewer queries to the root-servers.
''',
-     'versionchanged': ('4.0.0', "Default is ``yes`` now, was ``no`` before 4.0.0")
""",
+        "versionchanged": ("4.0.0", "Default is ``yes`` now, was ``no`` before 4.0.0"),
     },
     {
-        'name' : 'save_parent_ns_set',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Save parent NS set to be used if child NS set fails',
-        'doc' : '''
+        "name": "save_parent_ns_set",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Save parent NS set to be used if child NS set fails",
+        "doc": """
 If set, a parent (non-authoritative) ``NS`` set is saved if it contains more entries than a newly encountered child (authoritative) ``NS`` set for the same domain.
 The saved parent ``NS`` set is tried if resolution using the child ``NS`` set fails.
''',
-    'versionadded': '4.7.0'
""",
+        "versionadded": "4.7.0",
     },
     {
-        'name' : 'security_poll_suffix',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : 'secpoll.powerdns.com.',
-        'help' : 'Domain name from which to query security update notifications',
-        'doc' : '''
+        "name": "security_poll_suffix",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "secpoll.powerdns.com.",
+        "help": "Domain name from which to query security update notifications",
+        "doc": """
 Domain name from which to query security update notifications.
 Setting this to an empty string disables secpoll.
''',
""",
     },
     {
-        'name' : 'serve_rfc1918',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'If we should be authoritative for RFC 1918 private IP space',
-        'doc' : '''
+        "name": "serve_rfc1918",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "If we should be authoritative for RFC 1918 private IP space",
+        "doc": """
 This makes the server authoritatively aware of: ``10.in-addr.arpa``, ``168.192.in-addr.arpa``, ``16-31.172.in-addr.arpa``, which saves load on the AS112 servers.
 Individual parts of these zones can still be loaded or forwarded.
''',
-        'runtime': ['reload-zones'],
""",
+        "runtime": ["reload-zones"],
     },
     {
-        'name' : 'serve_rfc6303',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'If we should be authoritative for RFC 6303 private IP space',
-        'doc' : '''
+        "name": "serve_rfc6303",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "If we should be authoritative for RFC 6303 private IP space",
+        "doc": """
 This makes the server authoritatively aware of the zones in RFC 6303 not covered by RFC 1918.
 Individual parts of these zones can still be loaded or forwarded.
 :ref:`setting-serve-rfc1918` must be enabled for this option to take effect.
-''',
-        'versionadded': ['5.1.3', '5.2.0'],
-        'runtime': ['reload-zones'],
+""",
+        "versionadded": ["5.1.3", "5.2.0"],
+        "runtime": ["reload-zones"],
     },
     {
-        'name' : 'serve_stale_extensions',
-        'section' : 'recordcache',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Number of times a record\'s ttl is extended by 30s to be served stale',
-        'doc' : '''
+        "name": "serve_stale_extensions",
+        "section": "recordcache",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Number of times a record's ttl is extended by 30s to be served stale",
+        "doc": """
 Maximum number of times an expired record's TTL is extended by 30s when serving stale.
 Extension only occurs if a record cannot be refreshed.
 A value of 0 means the ``Serve Stale`` mechanism is not used.
 To allow records becoming stale to be served for an hour, use a value of 120.
 See :ref:`serve-stale` for a description of the Serve Stale mechanism.
''',
-    'versionadded': '4.8.0'
""",
+        "versionadded": "4.8.0",
     },
     {
-        'name' : 'server_down_max_fails',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '64',
-        'help' : 'Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )',
-        'doc' : '''
+        "name": "server_down_max_fails",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "64",
+        "help": "Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )",
+        "doc": """
 If a server has not responded in any way this many times in a row, no longer send it any queries for :ref:`setting-server-down-throttle-time` seconds.
 Afterwards, we will try a new packet, and if that also gets no response at all, we again throttle for :ref:`setting-server-down-throttle-time` seconds.
 Even a single response packet will drop the block.
''',
""",
     },
     {
-        'name' : 'server_down_throttle_time',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '60',
-        'help' : 'Number of seconds to throttle all queries to a server after being marked as down',
-        'doc' : '''
+        "name": "server_down_throttle_time",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "60",
+        "help": "Number of seconds to throttle all queries to a server after being marked as down",
+        "doc": """
 Throttle a server that has failed to respond :ref:`setting-server-down-max-fails` times for this many seconds.
''',
""",
     },
     {
-        'name' : 'bypass_server_throttling_probability',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '25',
-        'help' : 'Determines the probability of a server marked down to be used anyway',
-        'doc' : '''
+        "name": "bypass_server_throttling_probability",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "25",
+        "help": "Determines the probability of a server marked down to be used anyway",
+        "doc": """
 This setting determines the probability of a server marked down to be used anyway.
 A value of ``n`` means that the chance of a server marked down still being used after it wins speed selection is is ``1/n``.
 If this setting is zero throttled servers will never be selected to be used anyway.
-        ''',
-        'versionadded': '5.0.0'
+        """,
+        "versionadded": "5.0.0",
     },
     {
-        'name' : 'server_id',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : RUNTIME,
-        'help' : 'Returned when queried for \'id.server\' TXT or NSID, defaults to hostname, set custom or \'disabled\'',
-        'doc' : '''
+        "name": "server_id",
+        "section": "recursor",
+        "type": LType.String,
+        "default": RUNTIME,
+        "help": "Returned when queried for 'id.server' TXT or NSID, defaults to hostname, set custom or 'disabled'",
+        "doc": """
 The reply given by The PowerDNS recursor to a query for 'id.server' with its hostname, useful for in clusters.
 When a query contains the :rfc:`NSID EDNS0 Option <5001>`, this value is returned in the response as the NSID value.
 
@@ -2550,272 +2583,274 @@ Query example (where 192.0.2.14 is your server):
 
     dig @192.0.2.14 CHAOS TXT id.server.
     dig @192.0.2.14 example.com IN A +nsid
''',
""",
     },
     {
-        'name' : 'setgid',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'If set, change group id to this gid for more security',
-        'doc' : '''
+        "name": "setgid",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "If set, change group id to this gid for more security",
+        "doc": """
 PowerDNS can change its user and group id after binding to its socket.
 Can be used for better :doc:`security <security>`.
- '''
+ """,
     },
     {
-        'name' : 'setuid',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'If set, change user id to this uid for more security',
-        'doc' : '''
+        "name": "setuid",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "If set, change user id to this uid for more security",
+        "doc": """
 PowerDNS can change its user and group id after binding to its socket.
 Can be used for better :doc:`security <security>`.
- '''
+ """,
     },
     {
-        'name' : 'signature_inception_skew',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '60',
-        'help' : 'Allow the signature inception to be off by this number of seconds',
-        'doc' : '''
+        "name": "signature_inception_skew",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "60",
+        "help": "Allow the signature inception to be off by this number of seconds",
+        "doc": """
 Allow the signature inception to be off by this number of seconds. Negative values are not allowed.
''',
-        'versionadded': '4.1.5',
-        'versionchanged': ('4.2.0', 'Default is now 60, was 0 before.')
""",
+        "versionadded": "4.1.5",
+        "versionchanged": ("4.2.0", "Default is now 60, was 0 before."),
     },
     {
-        'name' : 'single_socket',
-        'section' : 'outgoing',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'If set, only use a single socket for outgoing queries',
-        'doc' : '''
+        "name": "single_socket",
+        "section": "outgoing",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "If set, only use a single socket for outgoing queries",
+        "doc": """
 Use only a single socket for outgoing queries.
''',
""",
     },
     {
-        'name' : 'agent',
-        'section' : 'snmp',
-        'oldname' : 'snmp-agent',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'If set, register as an SNMP agent',
-        'doc' : '''
+        "name": "agent",
+        "section": "snmp",
+        "oldname": "snmp-agent",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "If set, register as an SNMP agent",
+        "doc": """
 If set to true and PowerDNS has been compiled with SNMP support, it will register as an SNMP agent to provide statistics and be able to send traps.
''',
-    'versionadded': '4.1.0'
""",
+        "versionadded": "4.1.0",
     },
     {
-        'name' : 'daemon_socket',
-        'section' : 'snmp',
-        'oldname' : 'snmp-daemon-socket',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'If set and snmp-agent is set, the socket to use to register to the SNMP daemon',
-        'doc' : '''
+        "name": "daemon_socket",
+        "section": "snmp",
+        "oldname": "snmp-daemon-socket",
+        "type": LType.String,
+        "default": "",
+        "help": "If set and snmp-agent is set, the socket to use to register to the SNMP daemon",
+        "doc": """
 If not empty and ``snmp-agent`` is set to true, indicates how PowerDNS should contact the SNMP daemon to register as an SNMP agent.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'soa_minimum_ttl',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Don\'t change',
-        'doc' : '''SKIP''',
-        'skip-yaml': True,
+        "name": "soa_minimum_ttl",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Don't change",
+        "doc": """SKIP""",
+        "skip-yaml": True,
     },
     {
-        'name' : 'socket_dir',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Where the controlsocket will live, /var/run/pdns-recursor when unset and not chrooted',
-        'doc' : '''
+        "name": "socket_dir",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Where the controlsocket will live, /var/run/pdns-recursor when unset and not chrooted",
+        "doc": """
 Where to store the control socket and pidfile.
 The default depends on ``LOCALSTATEDIR`` or the ``--with-socketdir`` setting when building (usually ``/var/run`` or ``/run``).
 
 When using :ref:`setting-chroot` the default becomes ``/``.
 The default value is overruled by the ``RUNTIME_DIRECTORY`` environment variable when that variable has a value (e.g. under systemd).
''',
""",
     },
     {
-        'name' : 'socket_group',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Group of socket',
-        'doc' : '''
+        "name": "socket_group",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Group of socket",
+        "doc": """
 Group and mode of the controlsocket.
 Owner and group can be specified by name, mode is in octal.
-'''
+""",
     },
     {
-        'name' : 'socket_mode',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Permissions for socket',
-        'doc' : '''
+        "name": "socket_mode",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Permissions for socket",
+        "doc": """
 Mode of the controlsocket.
 Owner and group can be specified by name, mode is in octal.
- '''
+ """,
     },
     {
-        'name' : 'socket_owner',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Owner of socket',
-        'doc' : '''
+        "name": "socket_owner",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Owner of socket",
+        "doc": """
 Owner of the controlsocket.
 Owner and group can be specified by name, mode is in octal.
- '''
+ """,
     },
     {
-        'name' : 'spoof_nearmiss_max',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '1',
-        'help' : 'If non-zero, assume spoofing after this many near misses',
-        'doc' : '''
+        "name": "spoof_nearmiss_max",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "1",
+        "help": "If non-zero, assume spoofing after this many near misses",
+        "doc": """
 If set to non-zero, PowerDNS will assume it is being subjected to a spoofing attack after seeing this many answers with the wrong id.
''',
-     'versionchanged': ('4.5.0', 'Older versions used 20 as the default value.')
""",
+        "versionchanged": ("4.5.0", "Older versions used 20 as the default value."),
     },
     {
-        'name' : 'stack_cache_size',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '100',
-        'help' : 'Size of the stack cache, per mthread',
-        'doc' : '''
+        "name": "stack_cache_size",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "100",
+        "help": "Size of the stack cache, per mthread",
+        "doc": """
 Maximum number of mthread stacks that can be cached for later reuse, per thread. Caching these stacks reduces the CPU load at the cost of a slightly higher memory usage, each cached stack consuming `stack-size` bytes of memory.
 It makes no sense to cache more stacks than the value of `max-mthreads`, since there will never be more stacks than that in use at a given time.
''',
-    'versionadded': '4.9.0'
""",
+        "versionadded": "4.9.0",
     },
     {
-        'name' : 'stack_size',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '200000',
-        'help' : 'stack size per mthread',
-        'doc' : '''
+        "name": "stack_size",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "200000",
+        "help": "stack size per mthread",
+        "doc": """
 Size in bytes of the stack of each mthread.
''',
""",
     },
     {
-        'name' : 'statistics_interval',
-        'section' : 'logging',
-        'type' : LType.Uint64,
-        'default' : '1800',
-        'help' : 'Number of seconds between printing of recursor statistics, 0 to disable',
-        'doc' : '''
+        "name": "statistics_interval",
+        "section": "logging",
+        "type": LType.Uint64,
+        "default": "1800",
+        "help": "Number of seconds between printing of recursor statistics, 0 to disable",
+        "doc": """
 Interval between logging statistical summary on recursor performance.
 Use 0 to disable.
''',
-    'versionadded': '4.1.0'
""",
+        "versionadded": "4.1.0",
     },
     {
-        'name' : 'stats_api_disabled_list',
-        'section' : 'recursor',
-        'type' : LType.ListStrings,
-        'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128',
-        'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*',
-        'help' : 'List of statistics that are disabled when retrieving the complete list of statistics via the API',
-        'doc' : '''
+        "name": "stats_api_disabled_list",
+        "section": "recursor",
+        "type": LType.ListStrings,
+        "default": "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128",
+        "docdefault": "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*",
+        "help": "List of statistics that are disabled when retrieving the complete list of statistics via the API",
+        "doc": """
 A list of comma-separated statistic names, that are disabled when retrieving the complete list of statistics via the API for performance reasons.
 These statistics can still be retrieved individually by specifically asking for it.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 A sequence of statistic names, that are disabled when retrieving the complete list of statistics via the API for performance reasons.
 These statistics can still be retrieved individually by specifically asking for it.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'stats_carbon_disabled_list',
-        'section' : 'recursor',
-        'type' : LType.ListStrings,
-        'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count',
-        'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*, cumul-answers-\\*, cumul-auth4answers-\\*, cumul-auth6answers-\\*',
-        'help' : 'List of statistics that are prevented from being exported via Carbon',
-        'doc' : '''
+        "name": "stats_carbon_disabled_list",
+        "section": "recursor",
+        "type": LType.ListStrings,
+        "default": "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count",
+        "docdefault": "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*, cumul-answers-\\*, cumul-auth4answers-\\*, cumul-auth6answers-\\*",
+        "help": "List of statistics that are prevented from being exported via Carbon",
+        "doc": """
 A list of comma-separated statistic names, that are prevented from being exported via carbon for performance reasons.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 A sequence of statistic names, that are prevented from being exported via carbon for performance reasons.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'stats_rec_control_disabled_list',
-        'section' : 'recursor',
-        'type' : LType.ListStrings,
-        'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count',
-        'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*, cumul-answers-\\*, cumul-auth4answers-\\*, cumul-auth6answers-\\*',
-        'help' : 'List of statistics that are prevented from being exported via rec_control get-all',
-        'doc' : '''
+        "name": "stats_rec_control_disabled_list",
+        "section": "recursor",
+        "type": LType.ListStrings,
+        "default": "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count",
+        "docdefault": "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*, cumul-answers-\\*, cumul-auth4answers-\\*, cumul-auth6answers-\\*",
+        "help": "List of statistics that are prevented from being exported via rec_control get-all",
+        "doc": """
 A list of comma-separated statistic names, that are disabled when retrieving the complete list of statistics via `rec_control get-all`, for performance reasons.
 These statistics can still be retrieved individually.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 A sequence of statistic names, that are disabled when retrieving the complete list of statistics via `rec_control get-all`, for performance reasons.
 These statistics can still be retrieved individually.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'stats_ringbuffer_entries',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '10000',
-        'help' : 'maximum number of packets to store statistics for',
-        'doc' : '''
+        "name": "stats_ringbuffer_entries",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "10000",
+        "help": "maximum number of packets to store statistics for",
+        "doc": """
 Number of entries in the remotes ringbuffer, which keeps statistics on who is querying your server.
 Can be read out using ``rec_control top-remotes``.
''',
""",
     },
     {
-        'name' : 'stats_snmp_disabled_list',
-        'section' : 'recursor',
-        'type' : LType.ListStrings,
-        'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count',
-        'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*',
-        'help' : 'List of statistics that are prevented from being exported via SNMP',
-        'doc' : '''
+        "name": "stats_snmp_disabled_list",
+        "section": "recursor",
+        "type": LType.ListStrings,
+        "default": "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count",
+        "docdefault": "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*",
+        "help": "List of statistics that are prevented from being exported via SNMP",
+        "doc": """
 A list of comma-separated statistic names, that are prevented from being exported via SNMP, for performance reasons.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 A sequence of statistic names, that are prevented from being exported via SNMP, for performance reasons.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'structured_logging',
-        'section' : 'logging',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Prefer structured logging',
-        'doc' : '''
+        "name": "structured_logging",
+        "section": "logging",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Prefer structured logging",
+        "doc": """
 Prefer structured logging when both an old style and a structured log message are available.
- ''',
-        'versionadded': '4.6.0',
-        'versionchanged': [('5.0.0', 'Disabling structured logging is deprecated'),
-                           ('5.1.0', 'Disabling structured logging is not supported')]
-    },
-    {
-        'name' : 'structured_logging_backend',
-        'section' : 'logging',
-        'type' : LType.String,
-        'default' : 'default',
-        'help' : 'Structured logging backend',
-        'doc' : '''
+ """,
+        "versionadded": "4.6.0",
+        "versionchanged": [
+            ("5.0.0", "Disabling structured logging is deprecated"),
+            ("5.1.0", "Disabling structured logging is not supported"),
+        ],
+    },
+    {
+        "name": "structured_logging_backend",
+        "section": "logging",
+        "type": LType.String,
+        "default": "default",
+        "help": "Structured logging backend",
+        "doc": """
 The backend used for structured logging output.
 This setting must be set on the command line (``--structured-logging-backend=...``) to be effective.
 Available backends are:
@@ -2826,157 +2861,157 @@ Available backends are:
 - ``json``: JSON objects are written to the standard error stream.
 
 See :doc:`appendices/structuredlogging` for more details.
''',
-        'versionadded': '4.8.0',
-        'versionchanged': ('5.1.0', 'The JSON backend was added')
""",
+        "versionadded": "4.8.0",
+        "versionchanged": ("5.1.0", "The JSON backend was added"),
     },
     {
-        'name' : 'tcp_fast_open',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size',
-        'doc' : '''
+        "name": "tcp_fast_open",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size",
+        "doc": """
 Enable TCP Fast Open support, if available, on the listening sockets.
 The numerical value supplied is used as the queue size, 0 meaning disabled. See :ref:`tcp-fast-open-support`.
''',
-    'versionadded': '4.1.0'
""",
+        "versionadded": "4.1.0",
     },
     {
-        'name' : 'tcp_fast_open_connect',
-        'section' : 'outgoing',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Enable TCP Fast Open support on outgoing sockets',
-        'doc' : '''
+        "name": "tcp_fast_open_connect",
+        "section": "outgoing",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Enable TCP Fast Open support on outgoing sockets",
+        "doc": """
 Enable TCP Fast Open Connect support, if available, on the outgoing connections to authoritative servers. See :ref:`tcp-fast-open-support`.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'tcp_max_idle_ms',
-        'section' : 'outgoing',
-        'oldname' : 'tcp-out-max-idle-ms',
-        'type' : LType.Uint64,
-        'default' : '10000',
-        'help' : 'Time TCP/DoT connections are left idle in milliseconds or 0 if no limit',
-        'doc' : '''
+        "name": "tcp_max_idle_ms",
+        "section": "outgoing",
+        "oldname": "tcp-out-max-idle-ms",
+        "type": LType.Uint64,
+        "default": "10000",
+        "help": "Time TCP/DoT connections are left idle in milliseconds or 0 if no limit",
+        "doc": """
 Time outgoing TCP/DoT connections are left idle in milliseconds or 0 if no limit. After having been idle for this time, the connection is eligible for closing.
''',
-    'versionadded': '4.6.0'
""",
+        "versionadded": "4.6.0",
     },
     {
-        'name' : 'tcp_max_idle_per_auth',
-        'section' : 'outgoing',
-        'oldname' : 'tcp-out-max-idle-per-auth',
-        'type' : LType.Uint64,
-        'default' : '10',
-        'help' : 'Maximum number of idle TCP/DoT connections to a specific IP per thread, 0 means do not keep idle connections open',
-        'doc' : '''
+        "name": "tcp_max_idle_per_auth",
+        "section": "outgoing",
+        "oldname": "tcp-out-max-idle-per-auth",
+        "type": LType.Uint64,
+        "default": "10",
+        "help": "Maximum number of idle TCP/DoT connections to a specific IP per thread, 0 means do not keep idle connections open",
+        "doc": """
 Maximum number of idle outgoing TCP/DoT connections to a specific IP per thread, 0 means do not keep idle connections open.
''',
-    'versionadded': '4.6.0'
""",
+        "versionadded": "4.6.0",
     },
     {
-        'name' : 'tcp_max_queries',
-        'section' : 'outgoing',
-        'oldname' : 'tcp-out-max-queries',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Maximum total number of queries per TCP/DoT connection, 0 means no limit',
-        'doc' : '''
+        "name": "tcp_max_queries",
+        "section": "outgoing",
+        "oldname": "tcp-out-max-queries",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Maximum total number of queries per TCP/DoT connection, 0 means no limit",
+        "doc": """
 Maximum total number of queries per outgoing TCP/DoT connection, 0 means no limit. After this number of queries, the connection is
 closed and a new one will be created if needed.
''',
""",
     },
     {
-        'name' : 'tcp_max_idle_per_thread',
-        'section' : 'outgoing',
-        'oldname' : 'tcp-out-max-idle-per-thread',
-        'type' : LType.Uint64,
-        'default' : '100',
-        'help' : 'Maximum number of idle TCP/DoT connections per thread',
-        'doc' : '''
+        "name": "tcp_max_idle_per_thread",
+        "section": "outgoing",
+        "oldname": "tcp-out-max-idle-per-thread",
+        "type": LType.Uint64,
+        "default": "100",
+        "help": "Maximum number of idle TCP/DoT connections per thread",
+        "doc": """
 Maximum number of idle outgoing TCP/DoT connections per thread, 0 means do not keep idle connections open.
''',
-    'versionadded': '4.6.0'
""",
+        "versionadded": "4.6.0",
     },
     {
-        'name' : 'threads',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '2',
-        'help' : 'Launch this number of threads',
-        'doc' : '''
+        "name": "threads",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "2",
+        "help": "Launch this number of threads",
+        "doc": """
 Spawn this number of threads on startup.
''',
""",
     },
     {
-        'name' : 'tcp_threads',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '1',
-        'help' : 'Launch this number of threads listening for and processing TCP queries',
-        'doc' : '''
+        "name": "tcp_threads",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "1",
+        "help": "Launch this number of threads listening for and processing TCP queries",
+        "doc": """
 Spawn this number of TCP processing threads on startup.
''',
-        'versionadded': '5.0.0'
""",
+        "versionadded": "5.0.0",
     },
     {
-        'name' : 'trace',
-        'section' : 'logging',
-        'type' : LType.String,
-        'default' : 'no',
-        'help' : 'if we should output heaps of logging. set to \'fail\' to only log failing domains',
-        'doc' : '''
+        "name": "trace",
+        "section": "logging",
+        "type": LType.String,
+        "default": "no",
+        "help": "if we should output heaps of logging. set to 'fail' to only log failing domains",
+        "doc": """
 One of ``no``, ``yes`` or ``fail``.
 If turned on, output impressive heaps of logging.
 May destroy performance under load.
 To log only queries resulting in a ``ServFail`` answer from the resolving process, this value can be set to ``fail``, but note that the performance impact is still large.
 Also note that queries that do produce a result but with a failing DNSSEC validation are not written to the log
''',
""",
     },
     {
-        'name' : 'udp_source_port_min',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '1024',
-        'help' : 'Minimum UDP port to bind on',
-        'doc' : '''
+        "name": "udp_source_port_min",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "1024",
+        "help": "Minimum UDP port to bind on",
+        "doc": """
 This option sets the low limit of UDP port number to bind on.
 
 In combination with :ref:`setting-udp-source-port-max` it configures the UDP
 port range to use. Port numbers are randomized within this range on
 initialization, and exceptions can be configured with :ref:`setting-udp-source-port-avoid`
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'udp_source_port_max',
-        'section' : 'outgoing',
-        'type' : LType.Uint64,
-        'default' : '65535',
-        'help' : 'Maximum UDP port to bind on',
-        'doc' : '''
+        "name": "udp_source_port_max",
+        "section": "outgoing",
+        "type": LType.Uint64,
+        "default": "65535",
+        "help": "Maximum UDP port to bind on",
+        "doc": """
 This option sets the maximum limit of UDP port number to bind on.
 
 See :ref:`setting-udp-source-port-min`.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'udp_source_port_avoid',
-        'section' : 'outgoing',
-        'type' : LType.ListStrings,
-        'default' : '4791,11211',
-        'help' : 'List of comma separated UDP port numbers to avoid',
-        'doc' : '''
+        "name": "udp_source_port_avoid",
+        "section": "outgoing",
+        "type": LType.ListStrings,
+        "default": "4791,11211",
+        "help": "List of comma separated UDP port numbers to avoid",
+        "doc": """
 A list of comma-separated UDP port numbers to avoid when binding.
 Ex: `4791,5300,11211`
 
 See :ref:`setting-udp-source-port-min`.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 A sequence of UDP port numbers to avoid when binding. For example:
 
 .. code-block:: yaml
@@ -2988,33 +3023,33 @@ A sequence of UDP port numbers to avoid when binding. For example:
      - 11211
 
 See :ref:`setting-udp-source-port-min`.
''',
-        'versionadded': '4.2.0',
-        'versionchanged': ('5.2.0', 'port 4791 was added to the default list'),
""",
+        "versionadded": "4.2.0",
+        "versionchanged": ("5.2.0", "port 4791 was added to the default list"),
     },
     {
-        'name' : 'udp_truncation_threshold',
-        'section' : 'incoming',
-        'type' : LType.Uint64,
-        'default' : '1232',
-        'help' : 'Maximum UDP response size before we truncate',
-        'doc' : '''
+        "name": "udp_truncation_threshold",
+        "section": "incoming",
+        "type": LType.Uint64,
+        "default": "1232",
+        "help": "Maximum UDP response size before we truncate",
+        "doc": """
 EDNS0 allows for large UDP response datagrams, which can potentially raise performance.
 Large responses however also have downsides in terms of reflection attacks.
 This setting limits the accepted size.
 Maximum value is 65535, but values above 4096 should probably not be attempted.
 
 To know why 1232, see the note at :ref:`setting-edns-outgoing-bufsize`.
''',
-        'versionchanged': ('4.2.0', 'Before 4.2.0, the default was 1680.')
""",
+        "versionchanged": ("4.2.0", "Before 4.2.0, the default was 1680."),
     },
     {
-        'name' : 'unique_response_tracking',
-        'section' : 'nod',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Track unique responses (tuple of query name, type and RR).',
-        'doc' : '''
+        "name": "unique_response_tracking",
+        "section": "nod",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Track unique responses (tuple of query name, type and RR).",
+        "doc": """
 Whether to track unique DNS responses, i.e. never seen before combinations
 of the triplet (query name, query type, RR[rrname, rrtype, rrdata]).
 This can be useful for tracking potentially suspicious domains and
@@ -3026,47 +3061,47 @@ This feature uses a probabilistic data structure (stable bloom filter) to
 track unique responses, which can have false positives as well as false
 negatives, thus it is a best-effort feature. Increasing the number of cells
 in the SBF using the unique-response-db-size setting can reduce FPs and FNs.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'unique_response_log',
-        'section' : 'nod',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Log unique responses',
-        'doc' : '''
+        "name": "unique_response_log",
+        "section": "nod",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Log unique responses",
+        "doc": """
 Whether to log when a unique response is detected. The log line
 looks something like:
 
 Oct 24 12:11:27 Unique response observed: qname=foo.com qtype=A rrtype=AAAA rrname=foo.com rrcontent=1.2.3.4
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'unique_response_db_size',
-        'section' : 'nod',
-        'type' : LType.Uint64,
-        'default' : '67108864',
-        'help' : 'Size of the DB used to track unique responses in terms of number of cells. Defaults to 67108864',
-        'doc' : '''
+        "name": "unique_response_db_size",
+        "section": "nod",
+        "type": LType.Uint64,
+        "default": "67108864",
+        "help": "Size of the DB used to track unique responses in terms of number of cells. Defaults to 67108864",
+        "doc": """
 The default size of the stable bloom filter used to store previously
 observed responses is 67108864. To change the number of cells, use this
 setting. For each cell, the SBF uses 1 bit of memory, and one byte of
 disk for the persistent file.
 If there are already persistent files saved to disk, this setting will
 have no effect unless you remove the existing files.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'unique_response_history_dir',
-        'section' : 'nod',
-        'type' : LType.String,
-        'default' : 'NODCACHEDIRUDR',
-        'docdefault': 'Determined by distribution',
-        'help' : 'Persist unique response tracking data here to persist between restarts',
-        'doc' : '''
+        "name": "unique_response_history_dir",
+        "section": "nod",
+        "type": LType.String,
+        "default": "NODCACHEDIRUDR",
+        "docdefault": "Determined by distribution",
+        "help": "Persist unique response tracking data here to persist between restarts",
+        "doc": """
 This setting controls which directory is used to store the on-disk
 cache of previously observed responses.
 
@@ -3079,153 +3114,153 @@ synchronized to disk every 10 minutes, and is also initialized from
 disk on startup. This ensures that previously observed responses are
 preserved across recursor restarts. If you change the
 unique-response-db-size, you must remove any files from this directory.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'unique_response_pb_tag',
-        'section' : 'nod',
-        'type' : LType.String,
-        'default' : 'pdns-udr',
-        'help' : 'If protobuf is configured, the tag to use for messages containing unique DNS responses. Defaults to \'pdns-udr\'',
-        'doc' : '''
+        "name": "unique_response_pb_tag",
+        "section": "nod",
+        "type": LType.String,
+        "default": "pdns-udr",
+        "help": "If protobuf is configured, the tag to use for messages containing unique DNS responses. Defaults to 'pdns-udr'",
+        "doc": """
 If protobuf is configured, then this tag will be added to all protobuf response messages when
 a unique DNS response is observed.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'unique_response_ignore_list',
-        'section' : 'nod',
-        'type' : LType.ListStrings,
-        'default' : '',
-        'help' : 'List of domains (and implicitly all subdomains) which will never be considered for UDR',
-        'doc' : '''
+        "name": "unique_response_ignore_list",
+        "section": "nod",
+        "type": LType.ListStrings,
+        "default": "",
+        "help": "List of domains (and implicitly all subdomains) which will never be considered for UDR",
+        "doc": """
 This setting is a list of all domains (and implicitly all subdomains)
 that will never be considered for new unique domain responses.
 For example, if the domain 'example.com' is in the list, then 'foo.bar.example.com'
 will never be considered for a new unique domain response.
-''',
-        'versionadded': '5.1.0'
+""",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'unique_response_ignore_list_file',
-        'section' : 'nod',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'File with list of domains (and implicitly all subdomains) which will never be considered for UDR',
-        'doc' : '''
+        "name": "unique_response_ignore_list_file",
+        "section": "nod",
+        "type": LType.String,
+        "default": "",
+        "help": "File with list of domains (and implicitly all subdomains) which will never be considered for UDR",
+        "doc": """
 Path to a file with a list of domains. File should have one domain per line,
 with no extra characters or comments.
 See :ref:`setting-unique-response-ignore-list`.
-''',
-        'versionadded': '5.1.0'
+""",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'use_incoming_edns_subnet',
-        'section' : 'incoming',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Pass along received EDNS Client Subnet information',
-        'doc' : '''
+        "name": "use_incoming_edns_subnet",
+        "section": "incoming",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Pass along received EDNS Client Subnet information",
+        "doc": """
 Whether to process and pass along a received EDNS Client Subnet to authoritative servers.
 The ECS information will only be sent for netmasks and domains listed in :ref:`setting-edns-subnet-allow-list` and will be truncated if the received scope exceeds :ref:`setting-ecs-ipv4-bits` for IPv4 or :ref:`setting-ecs-ipv6-bits` for IPv6.
''',
""",
     },
     {
-        'name' : 'version',
-        'section' : 'commands',
-        'type' : LType.Command,
-        'default' : 'no',
-        'help' : 'Print version string',
-        'doc' : '''
+        "name": "version",
+        "section": "commands",
+        "type": LType.Command,
+        "default": "no",
+        "help": "Print version string",
+        "doc": """
 Print version of this binary. Useful for checking which version of the PowerDNS recursor is installed on a system.
''',
""",
     },
     {
-        'name' : 'version_string',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : RUNTIME,
-        'help' : 'string reported on version.pdns or version.bind',
-        'doc' : '''
+        "name": "version_string",
+        "section": "recursor",
+        "type": LType.String,
+        "default": RUNTIME,
+        "help": "string reported on version.pdns or version.bind",
+        "doc": """
 By default, PowerDNS replies to the 'version.bind' query with its version number.
 Security conscious users may wish to override the reply PowerDNS issues.
''',
""",
     },
     {
-        'name' : 'webserver',
-        'section' : 'webservice',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Start a webserver (for REST API)',
-        'doc' : '''
+        "name": "webserver",
+        "section": "webservice",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Start a webserver (for REST API)",
+        "doc": """
 Start the webserver (for REST API).
''',
""",
     },
     {
-        'name' : 'address',
-        'section' : 'webservice',
-        'oldname' : 'webserver-address',
-        'type' : LType.String,
-        'default' : '127.0.0.1',
-        'help' : 'IP Address of webserver to listen on',
-        'doc' : '''
+        "name": "address",
+        "section": "webservice",
+        "oldname": "webserver-address",
+        "type": LType.String,
+        "default": "127.0.0.1",
+        "help": "IP Address of webserver to listen on",
+        "doc": """
 IP address for the webserver to listen on.
-''',
-        'doc-new' : '''
+""",
+        "doc-new": """
 IP address for the webserver to listen on.
 This field is ignored if :ref:`setting-yaml-webservice.listen` is set.
-''',
+""",
     },
     {
-        'name' : 'listen',
-        'section' : 'webservice',
-        'type' : LType.ListIncomingWSConfigs,
-        'default' : '',
-        'help' : 'IP addresses and associated attributes for the webserver to listen on',
-        'doc' : '''
+        "name": "listen",
+        "section": "webservice",
+        "type": LType.ListIncomingWSConfigs,
+        "default": "",
+        "help": "IP addresses and associated attributes for the webserver to listen on",
+        "doc": """
 IP addresses and associated attributes for the webserver to listen on.
 If this setting has a non-default value, :ref:`setting-yaml-webservice.address` and :ref:`setting-yaml-webservice.port` will be ignored. Note multiple listen addresses can be configured and https is supported as well, in contrast to earlier (pre 5.3.0) versions.
''',
-        'skip-old': 'No equivalent old-style setting',
-        'versionadded': '5.3.0',
-    },
-    {
-        'name' : 'allow_from',
-        'section' : 'webservice',
-        'oldname' : 'webserver-allow-from',
-        'type' : LType.ListSubnets,
-        'default' : '127.0.0.1, ::1',
-        'help' : 'Webserver access is only allowed from these subnets',
-        'doc' : '''
""",
+        "skip-old": "No equivalent old-style setting",
+        "versionadded": "5.3.0",
+    },
+    {
+        "name": "allow_from",
+        "section": "webservice",
+        "oldname": "webserver-allow-from",
+        "type": LType.ListSubnets,
+        "default": "127.0.0.1, ::1",
+        "help": "Webserver access is only allowed from these subnets",
+        "doc": """
 These IPs and subnets are allowed to access the webserver. Note that
 specifying an IP address without a netmask uses an implicit netmask
 of /32 or /128.
''',
-        'versionchanged': ('4.1.0', 'Default is now 127.0.0.1,::1, was 0.0.0.0/0,::/0 before.')
""",
+        "versionchanged": ("4.1.0", "Default is now 127.0.0.1,::1, was 0.0.0.0/0,::/0 before."),
     },
     {
-        'name' : 'hash_plaintext_credentials',
-        'section' : 'webservice',
-        'oldname': 'webserver-hash-plaintext-credentials',
-        'type' : LType.Bool,
-        'default' : 'false',
-        'help' : 'Whether to hash passwords and api keys supplied in plaintext, to prevent keeping the plaintext version in memory at runtime',
-        'doc' : '''
+        "name": "hash_plaintext_credentials",
+        "section": "webservice",
+        "oldname": "webserver-hash-plaintext-credentials",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Whether to hash passwords and api keys supplied in plaintext, to prevent keeping the plaintext version in memory at runtime",
+        "doc": """
 Whether passwords and API keys supplied in the configuration as plaintext should be hashed during startup, to prevent the plaintext versions from staying in memory. Doing so increases significantly the cost of verifying credentials and is thus disabled by default.
 Note that this option only applies to credentials stored in the configuration as plaintext, but hashed credentials are supported without enabling this option.
''',
-    'versionadded': '4.6.0'
""",
+        "versionadded": "4.6.0",
     },
     {
-        'name' : 'loglevel',
-        'section' : 'webservice',
-        'oldname' : 'webserver-loglevel',
-        'type' : LType.String,
-        'default' : 'normal',
-        'help' : 'Amount of logging in the webserver (none, normal, detailed)',
-        'doc' : '''
+        "name": "loglevel",
+        "section": "webservice",
+        "oldname": "webserver-loglevel",
+        "type": LType.String,
+        "default": "normal",
+        "help": "Amount of logging in the webserver (none, normal, detailed)",
+        "doc": """
 One of ``none``, ``normal``, ``detailed``.
 The amount of logging the webserver must do. ``none`` means no useful webserver information will be logged.
 When set to ``normal``, the webserver will log a line per request::
@@ -3236,67 +3271,67 @@ When set to ``detailed``, all available information about the request and respon
 
 .. note::
   The webserver logs these line on the NOTICE level. The :ref:`setting-loglevel` setting must be 5 or higher for these lines to end up in the log.
''',
-    'versionadded': '4.2.0'
""",
+        "versionadded": "4.2.0",
     },
     {
-        'name' : 'password',
-        'section' : 'webservice',
-        'oldname' : 'webserver-password',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Password required for accessing the webserver',
-        'doc' : '''
+        "name": "password",
+        "section": "webservice",
+        "oldname": "webserver-password",
+        "type": LType.String,
+        "default": "",
+        "help": "Password required for accessing the webserver",
+        "doc": """
 Password required to access the webserver. Since 4.6.0 the password can be hashed and salted using ``rec_control hash-password`` instead of being present in the configuration in plaintext, but the plaintext version is still supported.
''',
-        'versionchanged': ('4.6.0', 'This setting now accepts a hashed and salted version.')
""",
+        "versionchanged": ("4.6.0", "This setting now accepts a hashed and salted version."),
     },
     {
-        'name' : 'port',
-        'section' : 'webservice',
-        'type' : LType.Uint64,
-        'oldname': 'webserver-port',
-        'default' : '8082',
-        'help' : 'Port of webserver to listen on',
-        'doc' : '''
+        "name": "port",
+        "section": "webservice",
+        "type": LType.Uint64,
+        "oldname": "webserver-port",
+        "default": "8082",
+        "help": "Port of webserver to listen on",
+        "doc": """
 TCP port where the webserver should listen on.
''',
-        'doc-new' : '''
""",
+        "doc-new": """
 TCP port where the webserver should listen on.
 This field is ignored if :ref:`setting-yaml-webservice.listen` is set.
''',
""",
     },
     {
-        'name' : 'write_pid',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Write a PID file',
-        'doc' : '''
+        "name": "write_pid",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Write a PID file",
+        "doc": """
 If a PID file should be written to :ref:`setting-socket-dir`
''',
""",
     },
     {
-        'name' : 'x_dnssec_names',
-        'section' : 'dnssec',
-        'type' : LType.ListStrings,
-        'default' : '',
-        'help' : 'Collect DNSSEC statistics for names or suffixes in this list in separate x-dnssec counters',
-        'doc' : '''
+        "name": "x_dnssec_names",
+        "section": "dnssec",
+        "type": LType.ListStrings,
+        "default": "",
+        "help": "Collect DNSSEC statistics for names or suffixes in this list in separate x-dnssec counters",
+        "doc": """
 List of names whose DNSSEC validation metrics will be counted in a separate set of metrics that start
 with ``x-dnssec-result-``.
 The names are suffix-matched.
 This can be used to not count known failing (test) name validations in the ordinary DNSSEC metrics.
''',
-    'versionadded': '4.5.0'
""",
+        "versionadded": "4.5.0",
     },
     {
-        'name' : 'system_resolver_ttl',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Set TTL of system resolver feature, 0 (default) is disabled',
-        'doc' : '''
+        "name": "system_resolver_ttl",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Set TTL of system resolver feature, 0 (default) is disabled",
+        "doc": """
 Sets TTL in seconds of the system resolver feature.
 If not equal to zero names can be used for forwarding targets.
 The names will be resolved by the system resolver configured in the OS.
@@ -3307,16 +3342,16 @@ if a change is detected, the recursor performs an equivalent of ``rec_control re
 
 Make sure the recursor itself is not used by the system resolver! Default is 0 (not enabled).
 A suggested value is 60.
-''',
-    'versionadded': '5.1.0'
+""",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'system_resolver_interval',
-        'section' : 'recursor',
-        'type' : LType.Uint64,
-        'default' : '0',
-        'help' : 'Set interval (in seconds) of the re-resolve checks of system resolver subsystem.',
-        'doc' : '''
+        "name": "system_resolver_interval",
+        "section": "recursor",
+        "type": LType.Uint64,
+        "default": "0",
+        "help": "Set interval (in seconds) of the re-resolve checks of system resolver subsystem.",
+        "doc": """
 Sets the check interval (in seconds) of the system resolver feature.
 All names known by the system resolver subsystem are periodically checked for changing values.
 
@@ -3325,27 +3360,27 @@ if a change is detected, the recursor performs an equivalent of ``rec_control re
 
 This settings sets the interval between the checks.
 If set to zero (the default), the value :ref:`setting-system-resolver-ttl` is used.
-''',
-    'versionadded': '5.1.0'
+""",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'system_resolver_self_resolve_check',
-        'section' : 'recursor',
-        'type' : LType.Bool,
-        'default' : 'true',
-        'help' : 'Check for potential self-resolve, default enabled.',
-        'doc' : '''
+        "name": "system_resolver_self_resolve_check",
+        "section": "recursor",
+        "type": LType.Bool,
+        "default": "true",
+        "help": "Check for potential self-resolve, default enabled.",
+        "doc": """
 Warn on potential self-resolve.
 If this check draws the wrong conclusion, you can disable it.
-''',
-        'versionadded': '5.1.0'
+""",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'trustanchors',
-        'section' : 'dnssec',
-        'type' : LType.ListTrustAnchors,
-        'default' : '[{name: ., dsrecords: [\'20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d\', \'38696 8 2 683d2d0acb8c9b712a1948b27f741219298d0a450d612c483af444a4c0fb2b16\']}]',
-        'docdefault' : '''
+        "name": "trustanchors",
+        "section": "dnssec",
+        "type": LType.ListTrustAnchors,
+        "default": "[{name: ., dsrecords: ['20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d', '38696 8 2 683d2d0acb8c9b712a1948b27f741219298d0a450d612c483af444a4c0fb2b16']}]",
+        "docdefault": """
 
 .. code-block:: yaml
 
@@ -3355,269 +3390,269 @@ If this check draws the wrong conclusion, you can disable it.
          - 20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d
          - 38696 8 2 683d2d0acb8c9b712a1948b27f741219298d0a450d612c483af444a4c0fb2b16
 
-''',
-        'help' : 'Sequence of trust anchors',
-        'doc' : '''
+""",
+        "help": "Sequence of trust anchors",
+        "doc": """
 Sequence of trust anchors. If the sequence contains an entry for the root zone, the default root zone trust anchor is not included.
 If a zone appears multiple times, the entries in ``dsrecords`` are merged.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`',
-        'versionadded': '5.1.0',
-        'runtime': ['add-ta', 'clear-ta', 'reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'negative_trustanchors',
-        'section' : 'dnssec',
-        'type' : LType.ListNegativeTrustAnchors,
-        'default' : '',
-        'help' : 'A sequence of negative trust anchors',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/dnssec`",
+        "versionadded": "5.1.0",
+        "runtime": ["add-ta", "clear-ta", "reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "negative_trustanchors",
+        "section": "dnssec",
+        "type": LType.ListNegativeTrustAnchors,
+        "default": "",
+        "help": "A sequence of negative trust anchors",
+        "doc": """
 Sequence of negative trust anchors.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`',
-        'versionadded': '5.1.0',
-        'runtime': ['add-nta', 'clear-nta', 'reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'trustanchorfile',
-        'section' : 'dnssec',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'A path to a zone file containing trust anchors',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/dnssec`",
+        "versionadded": "5.1.0",
+        "runtime": ["add-nta", "clear-nta", "reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "trustanchorfile",
+        "section": "dnssec",
+        "type": LType.String,
+        "default": "",
+        "help": "A path to a zone file containing trust anchors",
+        "doc": """
 A path to a zone file to read trust anchors from.
 This can be used to read distribution provided trust anchors, as for instance ``/usr/share/dns/root.key`` from Debian's ``dns-root-data`` package.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`',
-        'versionadded': '5.1.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'trustanchorfile_interval',
-        'section' : 'dnssec',
-        'type' : LType.Uint64,
-        'default' : '24',
-        'help' : 'Interval (in hours) to read the trust anchors file',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/dnssec`",
+        "versionadded": "5.1.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "trustanchorfile_interval",
+        "section": "dnssec",
+        "type": LType.Uint64,
+        "default": "24",
+        "help": "Interval (in hours) to read the trust anchors file",
+        "doc": """
 Interval (in hours) to re-read the ``trustanchorfile``.  Zero disables periodic re-reads.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`',
-        'versionadded': '5.1.0',
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/dnssec`",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'protobuf_servers',
-        'section' : 'logging',
-        'type' : LType.ListProtobufServers,
-        'default' : '',
-        'help' : 'Sequence of protobuf servers',
-        'doc' : '''
+        "name": "protobuf_servers",
+        "section": "logging",
+        "type": LType.ListProtobufServers,
+        "default": "",
+        "help": "Sequence of protobuf servers",
+        "doc": """
 Sequence of outgoing protobuf servers. Currently the maximum size of this list is one.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`',
-        'versionadded': '5.1.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'outgoing_protobuf_servers',
-        'section' : 'logging',
-        'type' : LType.ListProtobufServers,
-        'default' : '',
-        'help' : 'List of outgoing protobuf servers',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/protobuf`",
+        "versionadded": "5.1.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "outgoing_protobuf_servers",
+        "section": "logging",
+        "type": LType.ListProtobufServers,
+        "default": "",
+        "help": "List of outgoing protobuf servers",
+        "doc": """
 Sequence of outgoing protobuf servers. Currently the maximum size of this list is one.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`',
-        'versionadded': '5.1.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'protobuf_mask_v4',
-        'section' : 'logging',
-        'type' : LType.Uint64,
-        'default' : '32',
-        'help' : 'Network mask to apply for client IPv4 addresses in protobuf messages',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/protobuf`",
+        "versionadded": "5.1.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "protobuf_mask_v4",
+        "section": "logging",
+        "type": LType.Uint64,
+        "default": "32",
+        "help": "Network mask to apply for client IPv4 addresses in protobuf messages",
+        "doc": """
 Network mask to apply to the client IPv4 addresses, for anonymization purposes. The default of 32 means no anonymization.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`',
-        'versionadded': '5.1.0',
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/protobuf`",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'protobuf_mask_v6',
-        'section' : 'logging',
-        'type' : LType.Uint64,
-        'default' : '128',
-        'help' : 'Network mask to apply for client IPv6 addresses in protobuf messages',
-        'doc' : '''
+        "name": "protobuf_mask_v6",
+        "section": "logging",
+        "type": LType.Uint64,
+        "default": "128",
+        "help": "Network mask to apply for client IPv6 addresses in protobuf messages",
+        "doc": """
 Network mask to apply to the client IPv6 addresses, for anonymization purposes. The default of 128 means no anonymization.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`',
-        'versionadded': '5.1.0',
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/protobuf`",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'dnstap_framestream_servers',
-        'section' : 'logging',
-        'type' : LType.ListDNSTapFrameStreamServers,
-        'default' : '',
-        'help' : 'Sequence of dnstap servers',
-        'doc' : '''
+        "name": "dnstap_framestream_servers",
+        "section": "logging",
+        "type": LType.ListDNSTapFrameStreamServers,
+        "default": "",
+        "help": "Sequence of dnstap servers",
+        "doc": """
 Sequence of dnstap servers. Currently the maximum size of this list is one.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`',
-        'versionadded': '5.1.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'dnstap_nod_framestream_servers',
-        'section' : 'logging',
-        'type' : LType.ListDNSTapNODFrameStreamServers,
-        'default' : '',
-        'help' : 'Sequence of NOD dnstap servers',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/protobuf`",
+        "versionadded": "5.1.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "dnstap_nod_framestream_servers",
+        "section": "logging",
+        "type": LType.ListDNSTapNODFrameStreamServers,
+        "default": "",
+        "help": "Sequence of NOD dnstap servers",
+        "doc": """
 Sequence of NOD dnstap servers. Currently the maximum size of this list is one.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`',
-        'versionadded': '5.1.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'sortlists',
-        'section' : 'recursor',
-        'type' : LType.ListSortLists,
-        'default' : '',
-        'help' : 'Sequence of sort lists',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/protobuf`",
+        "versionadded": "5.1.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "sortlists",
+        "section": "recursor",
+        "type": LType.ListSortLists,
+        "default": "",
+        "help": "Sequence of sort lists",
+        "doc": """
 Sequence of sort lists.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/sortlist`',
-        'versionadded': '5.1.0',
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/sortlist`",
+        "versionadded": "5.1.0",
     },
     {
-        'name' : 'rpzs',
-        'section' : 'recursor',
-        'type' : LType.ListRPZs,
-        'default' : '',
-        'help' : 'Sequence of RPZ entries',
-        'doc' : '''
+        "name": "rpzs",
+        "section": "recursor",
+        "type": LType.ListRPZs,
+        "default": "",
+        "help": "Sequence of RPZ entries",
+        "doc": """
 Sequence of RPZ entries.
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/rpz`',
-        'versionadded': '5.1.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'zonetocaches',
-        'section' : 'recordcache',
-        'type' : LType.ListZoneToCaches,
-        'default' : '',
-        'help' : 'Sequence of ZoneToCache entries ',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/rpz`",
+        "versionadded": "5.1.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "zonetocaches",
+        "section": "recordcache",
+        "type": LType.ListZoneToCaches,
+        "default": "",
+        "help": "Sequence of ZoneToCache entries ",
+        "doc": """
 Sequence of ZoneToCache entries
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/ztc`',
-        'versionadded': '5.1.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'allowed_additional_qtypes',
-        'section' : 'recursor',
-        'type' : LType.ListAllowedAdditionalQTypes,
-        'default' : '',
-        'help' : 'Sequence of AllowedAdditionalQType',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/ztc`",
+        "versionadded": "5.1.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "allowed_additional_qtypes",
+        "section": "recursor",
+        "type": LType.ListAllowedAdditionalQTypes,
+        "default": "",
+        "help": "Sequence of AllowedAdditionalQType",
+        "doc": """
 Sequence of AllowedAdditionalQType
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/additionals`',
-        'versionadded': '5.1.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'proxymappings',
-        'section' : 'incoming',
-        'type' : LType.ListProxyMappings,
-        'default' : '',
-        'help' : 'Sequence of ProxyMapping',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/additionals`",
+        "versionadded": "5.1.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "proxymappings",
+        "section": "incoming",
+        "type": LType.ListProxyMappings,
+        "default": "",
+        "help": "Sequence of ProxyMapping",
+        "doc": """
 Sequence of ProxyMapping
-        ''',
-        'skip-old' : 'Equivalent Lua config in :doc:`lua-config/proxymapping`',
-        'versionadded': '5.1.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'lua_start_stop_script',
-        'section' : 'recursor',
-        'type' : LType.String,
-        'default' : '',
-        'help' : 'Lua script containing functions to run on startup and shutdown',
-        'doc' : '''
+        """,
+        "skip-old": "Equivalent Lua config in :doc:`lua-config/proxymapping`",
+        "versionadded": "5.1.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "lua_start_stop_script",
+        "section": "recursor",
+        "type": LType.String,
+        "default": "",
+        "help": "Lua script containing functions to run on startup and shutdown",
+        "doc": """
 Load this Lua script on startup and shutdown and run the Lua function ``on_recursor_start`` on startup and the Lua function ``on_recursor_stop`` on a ``nice`` shutdown (using ``rec_control quit-nicely`` of the :program:`Recursor` process.
-        ''',
-        'skip-old' : 'No equivalent old-style setting',
-        'versionadded': '5.2.0',
+        """,
+        "skip-old": "No equivalent old-style setting",
+        "versionadded": "5.2.0",
     },
     {
-        'name' : 'forwarding_catalog_zones',
-        'section' : 'recursor',
-        'type' : LType.ListForwardingCatalogZones,
-        'default' : '',
-        'help' : 'Sequence of ForwardingCatalogZone',
-        'doc' : '''
+        "name": "forwarding_catalog_zones",
+        "section": "recursor",
+        "type": LType.ListForwardingCatalogZones,
+        "default": "",
+        "help": "Sequence of ForwardingCatalogZone",
+        "doc": """
 Sequence of ForwardingCatalogZone. This setting cannot be combined with :ref:`setting-lua-config-file`.
-        ''',
-        'skip-old' : 'No equivalent old style setting',
-        'versionadded': '5.2.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'cookies',
-        'section' : 'outgoing',
-        'oldname': 'outgoing-cookies',
-        'type': LType.Bool,
-        'default': 'false',
-        'help': 'Enable DNS cookies when contacting authoritative servers or forwarders',
-        'doc': '''
+        """,
+        "skip-old": "No equivalent old style setting",
+        "versionadded": "5.2.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "cookies",
+        "section": "outgoing",
+        "oldname": "outgoing-cookies",
+        "type": LType.Bool,
+        "default": "false",
+        "help": "Enable DNS cookies when contacting authoritative servers or forwarders",
+        "doc": """
 Enable DNS cookies (:rfc:`7873`, :rfc:`9018`) when contacting authoritative servers or forwarders.
-''',
-        'versionadded': '5.4.0',
+""",
+        "versionadded": "5.4.0",
     },
     {
-        'name' : 'cookies_unsupported',
-        'section' : 'outgoing',
-        'oldname': 'outgoing-cookies-unsupported',
-        'type': LType.ListSocketAddresses,
-        'default': '',
-        'help': 'Addresses (with optional port) of authoritative servers that do not support cookies',
-        'doc': '''
+        "name": "cookies_unsupported",
+        "section": "outgoing",
+        "oldname": "outgoing-cookies-unsupported",
+        "type": LType.ListSocketAddresses,
+        "default": "",
+        "help": "Addresses (with optional port) of authoritative servers that do not support cookies",
+        "doc": """
 Addresses of servers that do not properly support DNS cookies (:rfc:`7873`, :rfc:`9018`). Recursor will not even try to probe these servers for cookie support. If no port is specified port 53 is used.
-''',
-        'versionadded': '5.4.0',
+""",
+        "versionadded": "5.4.0",
     },
     {
-        'name' : 'tls_configurations',
-        'section' : 'outgoing',
-        'type' : LType.ListOutgoingTLSConfigurations,
-        'default' : '',
-        'help' : 'Sequence of OutgoingTLSConfiguration',
-        'doc' : '''
+        "name": "tls_configurations",
+        "section": "outgoing",
+        "type": LType.ListOutgoingTLSConfigurations,
+        "default": "",
+        "help": "Sequence of OutgoingTLSConfiguration",
+        "doc": """
 Configurations used for outgoing DoT connections.
 A DoT connection is matched against the subnets lists (using the remote IP) and if that does not provide a match, the nameserver name is matched against the suffixes lists. When a match is found, the corresponding DoT configuration is used.
-        ''',
-        'skip-old' : 'No equivalent old style setting',
-        'versionadded': '5.4.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
-    },
-    {
-        'name' : 'opentelemetry_trace_conditions',
-        'section' : 'logging',
-        'type' : LType.ListOpenTelemetryTraceConditions,
-        'default' : '',
-        'help' : 'Sequence of OpenTelemetryTraceCondition',
-        'doc' : '''
+        """,
+        "skip-old": "No equivalent old style setting",
+        "versionadded": "5.4.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
+    },
+    {
+        "name": "opentelemetry_trace_conditions",
+        "section": "logging",
+        "type": LType.ListOpenTelemetryTraceConditions,
+        "default": "",
+        "help": "Sequence of OpenTelemetryTraceCondition",
+        "doc": """
         List of conditions specifying when to generate :ref:`opentelemetry_tracing`.
-        ''',
-        'skip-old' : 'No equivalent old style setting',
-        'versionadded': '5.4.0',
-        'runtime': ['reload-lua-config', 'reload-yaml'],
+        """,
+        "skip-old": "No equivalent old style setting",
+        "versionadded": "5.4.0",
+        "runtime": ["reload-lua-config", "reload-yaml"],
     },
 ]
index f8fcd48fe575f85487929560b423230da660c0b8..21fa6e5314cd5ce3414201610dab7021772a2949 100755 (executable)
@@ -13,60 +13,82 @@ import tempfile
 import time
 
 try:
-  raw_input
+    raw_input
 except NameError:
-  raw_input = input
+    raw_input = input
 
-MYSQL_DB='pdnsapi'
-MYSQL_USER='root'
-MYSQL_HOST=os.environ.get('MYSQL_HOST', 'localhost')
-MYSQL_PASSWD=''
+MYSQL_DB = "pdnsapi"
+MYSQL_USER = "root"
+MYSQL_HOST = os.environ.get("MYSQL_HOST", "localhost")
+MYSQL_PASSWD = ""
 
-PGSQL_DB='pdnsapi'
+PGSQL_DB = "pdnsapi"
 
-SQLITE_DB = 'pdns.sqlite3'
+SQLITE_DB = "pdns.sqlite3"
 
-LMDB_DB = 'pdns.lmdb'
+LMDB_DB = "pdns.lmdb"
 
 WEBPORT = 5556
 DNSPORT = 5300
-APIKEY = '1234567890abcdefghijklmnopq-key'
-WEBPASSWORD = 'something'
+APIKEY = "1234567890abcdefghijklmnopq-key"
+WEBPASSWORD = "something"
 PDNSUTIL_CMD = [os.environ.get("PDNSUTIL", "../pdns/pdnsutil"), "--config-dir=."]
 
 ZONES = ["example.com", "powerdnssec.org", "cryptokeys.org"]
 ZONE_DIR = "../regression-tests/zones/"
 
-AUTH_MYSQL_TPL = """
+AUTH_MYSQL_TPL = (
+    """
 # Generated by runtests.py
 launch=gmysql
 gmysql-dnssec=on
-gmysql-dbname="""+MYSQL_DB+"""
-gmysql-user="""+MYSQL_USER+"""
-gmysql-host="""+MYSQL_HOST+"""
-gmysql-password="""+MYSQL_PASSWD+"""
+gmysql-dbname="""
+    + MYSQL_DB
+    + """
+gmysql-user="""
+    + MYSQL_USER
+    + """
+gmysql-host="""
+    + MYSQL_HOST
+    + """
+gmysql-password="""
+    + MYSQL_PASSWD
+    + """
 """
+)
 
-AUTH_PGSQL_TPL = """
+AUTH_PGSQL_TPL = (
+    """
 # Generated by runtests.py
 launch=gpgsql
 gpgsql-dnssec=on
-gpgsql-dbname="""+PGSQL_DB+"""
+gpgsql-dbname="""
+    + PGSQL_DB
+    + """
 """
+)
 
-AUTH_SQLITE_TPL = """
+AUTH_SQLITE_TPL = (
+    """
 # Generated by runtests.py
 launch=gsqlite3
 gsqlite3-dnssec=on
-gsqlite3-database="""+SQLITE_DB+"""
+gsqlite3-database="""
+    + SQLITE_DB
+    + """
 """
+)
 
-AUTH_LMDB_TPL = """
+AUTH_LMDB_TPL = (
+    """
 # Generated by runtests.py
 launch=lmdb
-lmdb-filename="""+LMDB_DB+"""
+lmdb-filename="""
+    + LMDB_DB
+    + """
 views
 """
+)
 
 AUTH_COMMON_TPL = """
 module-dir=../regression-tests/modules
@@ -104,7 +126,8 @@ recursor:
     file: ../regression-tests/zones/example.com.rec
 """
 
-REC_CONF_TPL = """
+REC_CONF_TPL = (
+    """
 # Generated by runtests.py
 incoming:
   allow_from_file: acl.list.yml
@@ -113,16 +136,23 @@ webservice:
   webserver: true
   api_dir: %(api_dir)s
   listen:
-    - addresses: [ 127.0.0.1:"""+str(WEBPORT)+""" ]
+    - addresses: [ 127.0.0.1:"""
+    + str(WEBPORT)
+    + """ ]
       tls:
         certificate: server.chain
         key: server.key
-  api_key: """+APIKEY+"""
-  password: """+WEBPASSWORD+"""
+  api_key: """
+    + APIKEY
+    + """
+  password: """
+    + WEBPASSWORD
+    + """
 recursor:
   include_dir: %(conf_dir)s
   devonly_regression_test_mode: true
 """
+)
 
 
 def ensure_empty_dir(name):
@@ -140,20 +170,20 @@ def run_check_call(cmd, *args, **kwargs):
     subprocess.check_call(cmd, *args, **kwargs)
 
 
-wait = ('--wait' in sys.argv)
+wait = "--wait" in sys.argv
 if wait:
-    sys.argv.remove('--wait')
+    sys.argv.remove("--wait")
 
-tests = [opt for opt in sys.argv if opt.startswith('--tests=')]
+tests = [opt for opt in sys.argv if opt.startswith("--tests=")]
 if tests:
     for opt in tests:
         sys.argv.remove(opt)
-tests = [opt.split('=', 1)[1] for opt in tests]
+tests = [opt.split("=", 1)[1] for opt in tests]
 
 daemon = (len(sys.argv) >= 2) and sys.argv[1] or None
-backend = (len(sys.argv) == 3) and sys.argv[2] or 'gsqlite3'
+backend = (len(sys.argv) == 3) and sys.argv[2] or "gsqlite3"
 
-if daemon not in ('authoritative', 'recursor') or backend not in ('gmysql', 'gpgsql', 'gsqlite3', 'lmdb'):
+if daemon not in ("authoritative", "recursor") or backend not in ("gmysql", "gpgsql", "gsqlite3", "lmdb"):
     print("Usage: ./runtests (authoritative|recursor) [gmysql|gpgsql|gsqlite3|lmdb]")
     sys.exit(2)
 
@@ -162,15 +192,23 @@ daemon = sys.argv[1]
 pdns_server = os.environ.get("PDNSSERVER", "../pdns/pdns_server")
 pdns_recursor = os.environ.get("PDNSRECURSOR", "../pdns/recursordist/build/pdns_recursor")
 common_args = [
-    "--daemon=no", "--socket-dir=.", "--config-dir=.",
-    "--local-address=127.0.0.1", "--local-port="+str(DNSPORT),
-    "--webserver=yes", "--webserver-port="+str(WEBPORT), "--webserver-address=127.0.0.1",
-    "--webserver-password="+WEBPASSWORD,
-    "--api-key="+APIKEY
+    "--daemon=no",
+    "--socket-dir=.",
+    "--config-dir=.",
+    "--local-address=127.0.0.1",
+    "--local-port=" + str(DNSPORT),
+    "--webserver=yes",
+    "--webserver-port=" + str(WEBPORT),
+    "--webserver-address=127.0.0.1",
+    "--webserver-password=" + WEBPASSWORD,
+    "--api-key=" + APIKEY,
 ]
 rec_args = [
-    "--daemon=no", "--socket-dir=.", "--config-dir=.",
-    "--local-address=127.0.0.1", "--local-port="+str(DNSPORT),
+    "--daemon=no",
+    "--socket-dir=.",
+    "--config-dir=.",
+    "--local-address=127.0.0.1",
+    "--local-port=" + str(DNSPORT),
 ]
 
 # Take sdig if it exists (recursor in travis), otherwise build it from Authoritative source.
@@ -182,69 +220,91 @@ if not sdig or not os.path.exists(sdig):
     sdig = "../pdns/sdig"
 
 
-if daemon == 'authoritative':
+if daemon == "authoritative":
     # Prepare mysql DB with some zones.
-    if backend == 'gmysql':
-        subprocess.call(["mysqladmin", "--user=" + MYSQL_USER, "--password=" + MYSQL_PASSWD, "--host=" + MYSQL_HOST, "--force", "drop", MYSQL_DB])
-
-        run_check_call(["mysqladmin", "--user=" + MYSQL_USER, "--password=" + MYSQL_PASSWD, "--host=" + MYSQL_HOST, "create", MYSQL_DB])
-
-        with open('../modules/gmysqlbackend/schema.mysql.sql', 'r') as schema_file:
-            run_check_call(["mysql", "--user=" + MYSQL_USER, "--password=" + MYSQL_PASSWD, "--host=" + MYSQL_HOST, MYSQL_DB], stdin=schema_file)
-
-        with open('pdns.conf', 'w') as pdns_conf:
+    if backend == "gmysql":
+        subprocess.call(
+            [
+                "mysqladmin",
+                "--user=" + MYSQL_USER,
+                "--password=" + MYSQL_PASSWD,
+                "--host=" + MYSQL_HOST,
+                "--force",
+                "drop",
+                MYSQL_DB,
+            ]
+        )
+
+        run_check_call(
+            [
+                "mysqladmin",
+                "--user=" + MYSQL_USER,
+                "--password=" + MYSQL_PASSWD,
+                "--host=" + MYSQL_HOST,
+                "create",
+                MYSQL_DB,
+            ]
+        )
+
+        with open("../modules/gmysqlbackend/schema.mysql.sql", "r") as schema_file:
+            run_check_call(
+                ["mysql", "--user=" + MYSQL_USER, "--password=" + MYSQL_PASSWD, "--host=" + MYSQL_HOST, MYSQL_DB],
+                stdin=schema_file,
+            )
+
+        with open("pdns.conf", "w") as pdns_conf:
             pdns_conf.write(AUTH_MYSQL_TPL + AUTH_COMMON_TPL)
 
     # Prepare pgsql DB with some zones.
-    elif backend == 'gpgsql':
+    elif backend == "gpgsql":
         subprocess.call(["dropdb", PGSQL_DB])
 
         subprocess.check_call(["createdb", PGSQL_DB])
 
-        with open('../modules/gpgsqlbackend/schema.pgsql.sql', 'r') as schema_file:
+        with open("../modules/gpgsqlbackend/schema.pgsql.sql", "r") as schema_file:
             subprocess.check_call(["psql", PGSQL_DB], stdin=schema_file)
 
-        with open('pdns.conf', 'w') as pdns_conf:
+        with open("pdns.conf", "w") as pdns_conf:
             pdns_conf.write(AUTH_PGSQL_TPL + AUTH_COMMON_TPL)
 
     # Prepare sqlite DB with some zones.
-    elif backend == 'gsqlite3':
+    elif backend == "gsqlite3":
         subprocess.call("rm -f " + SQLITE_DB + "*", shell=True)
 
-        with open('../modules/gsqlite3backend/schema.sqlite3.sql', 'r') as schema_file:
+        with open("../modules/gsqlite3backend/schema.sqlite3.sql", "r") as schema_file:
             run_check_call(["sqlite3", SQLITE_DB], stdin=schema_file)
 
-        with open('pdns.conf', 'w') as pdns_conf:
+        with open("pdns.conf", "w") as pdns_conf:
             pdns_conf.write(AUTH_SQLITE_TPL + AUTH_COMMON_TPL)
 
     # Prepare lmdb DB with some zones.
-    elif backend == 'lmdb':
+    elif backend == "lmdb":
         subprocess.call("rm -f " + LMDB_DB + "*", shell=True)
 
-        with open('pdns.conf', 'w') as pdns_conf:
+        with open("pdns.conf", "w") as pdns_conf:
             pdns_conf.write(AUTH_LMDB_TPL + AUTH_COMMON_TPL)
 
-    with open('bindbackend.conf', 'w') as bindbackend_conf:
+    with open("bindbackend.conf", "w") as bindbackend_conf:
         bindbackend_conf.write(BINDBACKEND_CONF_TPL)
 
     for zone in ZONES:
-        run_check_call(PDNSUTIL_CMD + ["load-zone", zone, ZONE_DIR+zone])
+        run_check_call(PDNSUTIL_CMD + ["load-zone", zone, ZONE_DIR + zone])
 
     run_check_call(PDNSUTIL_CMD + ["secure-zone", "powerdnssec.org"])
     servercmd = [pdns_server] + common_args + ["--no-shuffle", "--dnsupdate=yes", "--cache-ttl=0", "--api=yes"]
 
 else:
-    conf_dir = 'rec-conf.d'
+    conf_dir = "rec-conf.d"
     ensure_empty_dir(conf_dir)
-    api_dir = 'rec-api.d'
+    api_dir = "rec-api.d"
     ensure_empty_dir(api_dir)
-    with open('acl.list.yml', 'w') as acl_list:
+    with open("acl.list.yml", "w") as acl_list:
         acl_list.write(ACL_LIST_TPL)
-    with open('acl-notify.list.yml', 'w') as acl_notify_list:
+    with open("acl-notify.list.yml", "w") as acl_notify_list:
         acl_notify_list.write(ACL_NOTIFY_LIST_TPL)
-    with open('recursor.yml', 'w') as recursor_conf:
+    with open("recursor.yml", "w") as recursor_conf:
         recursor_conf.write(REC_CONF_TPL % locals())
-    with open(conf_dir+'/example.com.yml', 'w') as conf_file:
+    with open(conf_dir + "/example.com.yml", "w") as conf_file:
         conf_file.write(REC_EXAMPLE_COM_CONF_TPL)
 
     servercmd = [pdns_recursor] + rec_args
@@ -257,6 +317,7 @@ server_stdout = tempfile.TemporaryFile()
 server_stderr = tempfile.TemporaryFile()
 serverproc = subprocess.Popen(servercmd, close_fds=True, text=True, stdout=server_stdout, stderr=server_stderr)
 
+
 def finalize_server():
     serverproc.terminate()
     serverproc.wait()
@@ -279,16 +340,16 @@ available = False
 time.sleep(1)
 for _ in range(0, 10):
     try:
-        if daemon == 'authoritative':
-            requests.get('http://127.0.0.1:%s/' % WEBPORT)
+        if daemon == "authoritative":
+            requests.get("http://127.0.0.1:%s/" % WEBPORT)
         else:
-            requests.get('https://127.0.0.1:%s/' % WEBPORT, verify='ca.pem')
+            requests.get("https://127.0.0.1:%s/" % WEBPORT, verify="ca.pem")
         available = True
         break
     except HTTPError as http_err:
-      print(f'HTTP error occurred: {http_err}')
+        print(f"HTTP error occurred: {http_err}")
     except Exception as err:
-      print(f'Other error occurred: {err}')
+        print(f"Other error occurred: {err}")
     time.sleep(1)
 
 if not available:
@@ -297,32 +358,34 @@ if not available:
     sys.exit(2)
 
 print("Query for example.com/A to create statistic data...")
-if daemon == 'authoritative':
-  run_check_call([sdig, "127.0.0.1", str(DNSPORT), "example.com", "A"])
+if daemon == "authoritative":
+    run_check_call([sdig, "127.0.0.1", str(DNSPORT), "example.com", "A"])
 else:
-  run_check_call([sdig, "127.0.0.1", str(DNSPORT), "example.com", "A", "recurse"])
+    run_check_call([sdig, "127.0.0.1", str(DNSPORT), "example.com", "A", "recurse"])
 
 print("Running tests...")
 returncode = 0
 test_env = {}
 test_env.update(os.environ)
-test_env.update({
-    'WEBPASSWORD': WEBPASSWORD,
-    'WEBPORT': str(WEBPORT),
-    'APIKEY': APIKEY,
-    'DAEMON': daemon,
-    'BACKEND': backend,
-    'MYSQL_DB': MYSQL_DB,
-    'MYSQL_USER': MYSQL_USER,
-    'MYSQL_HOST': MYSQL_HOST,
-    'MYSQL_PASSWD': MYSQL_PASSWD,
-    'PGSQL_DB': PGSQL_DB,
-    'SQLITE_DB': SQLITE_DB,
-    'LMDB_DB': LMDB_DB,
-    'PDNSUTIL_CMD': ' '.join(PDNSUTIL_CMD),
-    'SDIG': sdig,
-    'DNSPORT': str(DNSPORT)
-})
+test_env.update(
+    {
+        "WEBPASSWORD": WEBPASSWORD,
+        "WEBPORT": str(WEBPORT),
+        "APIKEY": APIKEY,
+        "DAEMON": daemon,
+        "BACKEND": backend,
+        "MYSQL_DB": MYSQL_DB,
+        "MYSQL_USER": MYSQL_USER,
+        "MYSQL_HOST": MYSQL_HOST,
+        "MYSQL_PASSWD": MYSQL_PASSWD,
+        "PGSQL_DB": PGSQL_DB,
+        "SQLITE_DB": SQLITE_DB,
+        "LMDB_DB": LMDB_DB,
+        "PDNSUTIL_CMD": " ".join(PDNSUTIL_CMD),
+        "SDIG": sdig,
+        "DNSPORT": str(DNSPORT),
+    }
+)
 
 try:
     print("")
index 329fbd959afd9b55647ca91bd5ed749566a1f4bb..d1daadcefe43ec05b919dd78a519c048f9bdaed4 100644 (file)
@@ -5,13 +5,12 @@ from test_helper import ApiTestCase, is_auth
 
 
 class TestBasics(ApiTestCase):
-
     def test_unauth(self):
         r = requests.get(self.url("/api/v1/servers/localhost"), verify=False)
         self.assertEqual(r.status_code, requests.codes.unauthorized)
 
     def test_index_html(self):
-        r = requests.get(self.url("/"), auth=('admin', self.server_web_password), verify=False)
+        r = requests.get(self.url("/"), auth=("admin", self.server_web_password), verify=False)
         self.assertEqual(r.status_code, requests.codes.ok)
 
     def test_split_request(self):
@@ -24,7 +23,7 @@ class TestBasics(ApiTestCase):
         print("Sending request")
         for part in parts:
             print("Sending %s" % part)
-            s.sendall(part.encode('ascii'))
+            s.sendall(part.encode("ascii"))
             time.sleep(0.5)
 
         resp = s.recv(4096, socket.MSG_WAITALL)
@@ -33,28 +32,28 @@ class TestBasics(ApiTestCase):
         print("response", repr(resp))
 
         status = resp.splitlines(0)[0]
-        if b'400' in status:
-            raise Exception('Got unwanted response: %s' % status)
+        if b"400" in status:
+            raise Exception("Got unwanted response: %s" % status)
 
     def test_cors(self):
         r = self.session.options(self.url("/api/v1/servers/localhost"))
         # look for CORS headers
 
         self.assertEqual(r.status_code, requests.codes.ok)
-        self.assertEqual(r.headers['access-control-allow-origin'], "*")
-        self.assertEqual(r.headers['access-control-allow-headers'], 'Content-Type, X-API-Key')
-        self.assertEqual(r.headers['access-control-allow-methods'], 'GET, OPTIONS')
+        self.assertEqual(r.headers["access-control-allow-origin"], "*")
+        self.assertEqual(r.headers["access-control-allow-headers"], "Content-Type, X-API-Key")
+        self.assertEqual(r.headers["access-control-allow-methods"], "GET, OPTIONS")
 
         print("response", repr(r.headers))
 
         r = self.session.options(self.url("/api/v1/servers/localhost/zones/test"))
         self.assertEqual(r.status_code, requests.codes.ok)
-        self.assertEqual(r.headers['access-control-allow-origin'], "*")
-        self.assertEqual(r.headers['access-control-allow-headers'], 'Content-Type, X-API-Key')
+        self.assertEqual(r.headers["access-control-allow-origin"], "*")
+        self.assertEqual(r.headers["access-control-allow-headers"], "Content-Type, X-API-Key")
         if is_auth():
-            self.assertEqual(r.headers['access-control-allow-methods'], 'GET, PATCH, PUT, DELETE, OPTIONS')
+            self.assertEqual(r.headers["access-control-allow-methods"], "GET, PATCH, PUT, DELETE, OPTIONS")
         else:
-            self.assertEqual(r.headers['access-control-allow-methods'], 'GET, PUT, DELETE, OPTIONS')
+            self.assertEqual(r.headers["access-control-allow-methods"], "GET, PUT, DELETE, OPTIONS")
 
         print("response", repr(r.headers))
 
index 928d12ecd67567758027b45b6432534c6ebc5659..3d997192d00a0d4b78780a354d4489072f531f2d 100644 (file)
@@ -3,50 +3,47 @@ import unittest
 
 
 class Servers(ApiTestCase):
-
     def test_flush(self):
         r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=example.org."))
         self.assert_success_json(r)
         data = r.json()
-        self.assertIn('count', data)
+        self.assertIn("count", data)
 
     @unittest.skipIf(not is_recursor(), "Not applicable")
     def test_flush_count(self):
-        sdig("ns1.example.com", 'A')
+        sdig("ns1.example.com", "A")
         r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=ns1.example.com."))
         self.assert_success_json(r)
         data = r.json()
-        self.assertIn('count', data)
-        self.assertEqual(2, data['count'])
+        self.assertIn("count", data)
+        self.assertEqual(2, data["count"])
 
     @unittest.skipIf(not is_recursor(), "Not applicable")
     def test_flush_subtree(self):
-        sdig("ns1.example.com", 'A')
-        sdig("ns2.example.com", 'A')
+        sdig("ns1.example.com", "A")
+        sdig("ns2.example.com", "A")
         r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=example.com.&subtree=false"))
         self.assert_success_json(r)
         data = r.json()
-        self.assertIn('count', data)
-        self.assertEqual(3, data['count'])
+        self.assertIn("count", data)
+        self.assertEqual(3, data["count"])
         r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=example.com.&subtree=true"))
         self.assert_success_json(r)
         data = r.json()
-        self.assertIn('count', data)
-        self.assertEqual(4, data['count'])
+        self.assertIn("count", data)
+        self.assertEqual(4, data["count"])
 
     def test_flush_root(self):
         r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=."))
         self.assert_success_json(r)
         data = r.json()
-        self.assertIn('count', data)
-        self.assertEqual(data['result'], 'Flushed cache.')
+        self.assertIn("count", data)
+        self.assertEqual(data["result"], "Flushed cache.")
 
     def test_flush_no_domain(self):
-        r = self.session.put(
-            self.url("/api/v1/servers/localhost/cache/flush"))
+        r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush"))
         self.assertEqual(r.status_code, 422)
 
     def test_flush_unqualified(self):
-        r = self.session.put(
-            self.url("/api/v1/servers/localhost/cache/flush?domain=bar"))
+        r = self.session.put(self.url("/api/v1/servers/localhost/cache/flush?domain=bar"))
         self.assertEqual(r.status_code, 422)
index 930c8d56b28dc0e0192826f7950aad1ef8b36682..9e7ead3ca32cf46cc05a6d08ddda21f22f016aa6 100644 (file)
@@ -2,14 +2,13 @@ from test_helper import ApiTestCase
 
 
 class DiscoveryTest(ApiTestCase):
-
     def test_discovery(self):
         r = self.session.get(self.url("/api"))
         self.assert_success_json(r)
         lst = r.json()
-        self.assertEqual(lst, [{'version': 1, 'url': '/api/v1'}])
+        self.assertEqual(lst, [{"version": 1, "url": "/api/v1"}])
 
         r = self.session.get(self.url("/api/v1"))
         self.assert_success_json(r)
         lst = r.json()
-        self.assertEqual(lst, [{'api_features': [], 'server_url': '/api/v1/servers{/server}'}])
+        self.assertEqual(lst, [{"api_features": [], "server_url": "/api/v1/servers{/server}"}])
index 242297112111323ed46508330fa0d811f1153b7e..5117f42f0a617e28ead076f6f9459065722b31a4 100644 (file)
@@ -5,17 +5,17 @@ from test_helper import ApiTestCase, is_recursor
 
 @unittest.skipIf(not is_recursor(), "Only applicable to recursors")
 class RecursorAllowFromConfig(ApiTestCase):
-
     def test_config_allow_from_get(self):
         r = self.session.get(self.url("/api/v1/servers/localhost/config/allow-from"))
         self.assert_success_json(r)
 
     def test_config_allow_from_replace(self):
-        payload = {'value': ["127.0.0.1"]}
+        payload = {"value": ["127.0.0.1"]}
         r = self.session.put(
             self.url("/api/v1/servers/localhost/config/allow-from"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success_json(r)
         data = r.json()
         self.assertIn("value", data)
@@ -23,11 +23,12 @@ class RecursorAllowFromConfig(ApiTestCase):
         self.assertEqual("127.0.0.1/32", data["value"][0])
 
     def test_config_allow_from_replace_empty(self):
-        payload = {'value': []}
+        payload = {"value": []}
         r = self.session.put(
             self.url("/api/v1/servers/localhost/config/allow-from"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success_json(r)
         data = r.json()
         self.assertIn("value", data)
@@ -35,29 +36,30 @@ class RecursorAllowFromConfig(ApiTestCase):
 
     def test_config_allow_from_replace_error(self):
         """Test the error case, should return 422."""
-        payload = {'value': ["abcdefgh"]}
+        payload = {"value": ["abcdefgh"]}
         r = self.session.put(
             self.url("/api/v1/servers/localhost/config/allow-from"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
         data = r.json()
-        self.assertIn('Unable to convert', data['error'])
+        self.assertIn("Unable to convert", data["error"])
 
 
 @unittest.skipIf(not is_recursor(), "Only applicable to recursors")
 class RecursorAllowNotifyFromConfig(ApiTestCase):
-
     def test_config_allow_notify_from_get(self):
         r = self.session.get(self.url("/api/v1/servers/localhost/config/allow-notify-from"))
         self.assert_success_json(r)
 
     def test_config_allow_notify_from_replace(self):
-        payload = {'value': ["127.0.0.1"]}
+        payload = {"value": ["127.0.0.1"]}
         r = self.session.put(
             self.url("/api/v1/servers/localhost/config/allow-notify-from"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success_json(r)
         data = r.json()
         self.assertIn("value", data)
@@ -65,11 +67,12 @@ class RecursorAllowNotifyFromConfig(ApiTestCase):
         self.assertEqual("127.0.0.1/32", data["value"][0])
 
     def test_config_allow_notify_from_replace_empty(self):
-        payload = {'value': []}
+        payload = {"value": []}
         r = self.session.put(
             self.url("/api/v1/servers/localhost/config/allow-notify-from"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success_json(r)
         data = r.json()
         self.assertIn("value", data)
@@ -77,11 +80,12 @@ class RecursorAllowNotifyFromConfig(ApiTestCase):
 
     def test_config_allow_notify_from_replace_error(self):
         """Test the error case, should return 422."""
-        payload = {'value': ["abcdefgh"]}
+        payload = {"value": ["abcdefgh"]}
         r = self.session.put(
             self.url("/api/v1/servers/localhost/config/allow-notify-from"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
         data = r.json()
-        self.assertIn('Unable to convert', data['error'])
+        self.assertIn("Unable to convert", data["error"])
index 091b3ef66845cfb90b3c4be6ae0348e3f3664303..3ab8f046e63331523f8e4385e1f8d06bc0954697 100644 (file)
@@ -5,13 +5,12 @@ from test_helper import ApiTestCase, is_recursor
 
 @unittest.skipIf(not is_recursor(), "Only applicable to recursors")
 class RecursorOT(ApiTestCase):
-
     def assert_in_json_error(self, expected, json):
-        error = json['error']
+        error = json["error"]
         if expected not in error:
             found = False
-            if 'errors' in json:
-                errors = json['errors']
+            if "errors" in json:
+                errors = json["errors"]
                 for item in errors:
                     if expected in item:
                         found = True
@@ -21,110 +20,112 @@ class RecursorOT(ApiTestCase):
     def test_basic_ot_conditions(self):
         # initial list is empty
         r = self.session.get(
-            self.url("/api/v1/servers/localhost/ottraceconditions"),
-            headers={'content-type': 'application/json'})
+            self.url("/api/v1/servers/localhost/ottraceconditions"), headers={"content-type": "application/json"}
+        )
         self.assertEqual(r.status_code, 200)
         self.assertEqual(r.json(), [])
 
         # nonexistent condition
         r = self.session.get(
             self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4/32"),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Could not find otcondition', r.json())
+        self.assert_in_json_error("Could not find otcondition", r.json())
 
         # malformed netmask
         r = self.session.get(
             self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3/32"),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Could not parse netmask', r.json())
+        self.assert_in_json_error("Could not parse netmask", r.json())
 
         # deleting non-existent netmask
         r = self.session.delete(
             self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4/32"),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Could not find otcondition', r.json())
+        self.assert_in_json_error("Could not find otcondition", r.json())
 
         # creating, most simple case
-        payload = {
-            "acl": "1.2.3.4"
-        }
+        payload = {"acl": "1.2.3.4"}
         r = self.session.post(
             self.url("/api/v1/servers/localhost/ottraceconditions"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 201)
         data = r.json()
-        self.assertIn('acl', data)
-        self.assertIn('edns_option_required', data)
-        self.assertIn('traceid_only', data)
-        self.assertIn('type', data)
-        self.assertEqual(data['acl'], '1.2.3.4/32')
-        self.assertEqual(data['type'], 'OpenTelemetryTraceCondition')
-        self.assertFalse(data['edns_option_required'])
-        self.assertFalse(data['traceid_only'])
+        self.assertIn("acl", data)
+        self.assertIn("edns_option_required", data)
+        self.assertIn("traceid_only", data)
+        self.assertIn("type", data)
+        self.assertEqual(data["acl"], "1.2.3.4/32")
+        self.assertEqual(data["type"], "OpenTelemetryTraceCondition")
+        self.assertFalse(data["edns_option_required"])
+        self.assertFalse(data["traceid_only"])
 
         # creating, error because duplicate
-        payload = {
-            "acl": "1.2.3.4"
-        }
+        payload = {"acl": "1.2.3.4"}
         r = self.session.post(
             self.url("/api/v1/servers/localhost/ottraceconditions"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('OTCondition already exists', r.json())
+        self.assert_in_json_error("OTCondition already exists", r.json())
 
         # list has one element
         r = self.session.get(
-            self.url("/api/v1/servers/localhost/ottraceconditions"),
-            headers={'content-type': 'application/json'})
+            self.url("/api/v1/servers/localhost/ottraceconditions"), headers={"content-type": "application/json"}
+        )
         self.assertEqual(r.status_code, 200)
         self.assertEqual(len(r.json()), 1)
 
         # creating, more general case
-        payload = {
-            "acl": "1.2.3.0/24"
-        }
+        payload = {"acl": "1.2.3.0/24"}
         r = self.session.post(
             self.url("/api/v1/servers/localhost/ottraceconditions"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 201)
         data = r.json()
-        self.assertIn('acl', data)
-        self.assertIn('edns_option_required', data)
-        self.assertIn('traceid_only', data)
-        self.assertEqual(data['acl'], '1.2.3.0/24')
-        self.assertFalse(data['edns_option_required'])
-        self.assertFalse(data['traceid_only'])
+        self.assertIn("acl", data)
+        self.assertIn("edns_option_required", data)
+        self.assertIn("traceid_only", data)
+        self.assertEqual(data["acl"], "1.2.3.0/24")
+        self.assertFalse(data["edns_option_required"])
+        self.assertFalse(data["traceid_only"])
 
         # list has two elements
         r = self.session.get(
-            self.url("/api/v1/servers/localhost/ottraceconditions"),
-            headers={'content-type': 'application/json'})
+            self.url("/api/v1/servers/localhost/ottraceconditions"), headers={"content-type": "application/json"}
+        )
         self.assertEqual(r.status_code, 200)
         self.assertEqual(len(r.json()), 2)
 
         # querying by more specific key than /24
         r = self.session.get(
             self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4/31"),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Could not find otcondition', r.json())
+        self.assert_in_json_error("Could not find otcondition", r.json())
 
         # deleting specific netmask
         r = self.session.delete(
             self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4/32"),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
 
         # list has one elements
         r = self.session.get(
-            self.url("/api/v1/servers/localhost/ottraceconditions"),
-            headers={'content-type': 'application/json'})
+            self.url("/api/v1/servers/localhost/ottraceconditions"), headers={"content-type": "application/json"}
+        )
         self.assertEqual(r.status_code, 200)
         self.assertEqual(len(r.json()), 1)
 
@@ -135,46 +136,47 @@ class RecursorOT(ApiTestCase):
             "qnames": ["foo.bar", "nl", "com"],
             "qtypes": ["AAAA", "TXT"],
             "traceid_only": True,
-            "edns_option_required": True
+            "edns_option_required": True,
         }
         r = self.session.post(
             self.url("/api/v1/servers/localhost/ottraceconditions"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 201)
         data = r.json()
-        self.assertIn('acl', data)
-        self.assertIn('qid', data)
-        self.assertIn('qnames', data)
-        self.assertIn('qtypes', data)
-        self.assertIn('traceid_only', data)
-        self.assertIn('edns_option_required', data)
-        self.assertIn('type', data)
-        self.assertEqual(data['acl'], '::/0')
-        self.assertEqual(data['qid'], 99)
-        self.assertEqual(len(data['qnames']), 3)
-        self.assertEqual(len(data['qtypes']), 2)
-        self.assertEqual(data['type'], 'OpenTelemetryTraceCondition')
-        self.assertTrue(data['edns_option_required'])
-        self.assertTrue(data['traceid_only'])
+        self.assertIn("acl", data)
+        self.assertIn("qid", data)
+        self.assertIn("qnames", data)
+        self.assertIn("qtypes", data)
+        self.assertIn("traceid_only", data)
+        self.assertIn("edns_option_required", data)
+        self.assertIn("type", data)
+        self.assertEqual(data["acl"], "::/0")
+        self.assertEqual(data["qid"], 99)
+        self.assertEqual(len(data["qnames"]), 3)
+        self.assertEqual(len(data["qtypes"]), 2)
+        self.assertEqual(data["type"], "OpenTelemetryTraceCondition")
+        self.assertTrue(data["edns_option_required"])
+        self.assertTrue(data["traceid_only"])
 
         # and GET the newly created one in a separate call
         r = self.session.get(
-            self.url("/api/v1/servers/localhost/ottraceconditions/::/0"),
-            headers={'content-type': 'application/json'})
+            self.url("/api/v1/servers/localhost/ottraceconditions/::/0"), headers={"content-type": "application/json"}
+        )
         self.assertEqual(r.status_code, 200)
         data = r.json()
-        self.assertIn('acl', data)
-        self.assertIn('qid', data)
-        self.assertIn('qnames', data)
-        self.assertIn('qtypes', data)
-        self.assertIn('traceid_only', data)
-        self.assertIn('edns_option_required', data)
-        self.assertIn('type', data)
-        self.assertEqual(data['acl'], '::/0')
-        self.assertEqual(data['qid'], 99)
-        self.assertEqual(len(data['qnames']), 3)
-        self.assertEqual(len(data['qtypes']), 2)
-        self.assertEqual(data['type'], 'OpenTelemetryTraceCondition')
-        self.assertTrue(data['edns_option_required'])
-        self.assertTrue(data['traceid_only'])
+        self.assertIn("acl", data)
+        self.assertIn("qid", data)
+        self.assertIn("qnames", data)
+        self.assertIn("qtypes", data)
+        self.assertIn("traceid_only", data)
+        self.assertIn("edns_option_required", data)
+        self.assertIn("type", data)
+        self.assertEqual(data["acl"], "::/0")
+        self.assertEqual(data["qid"], 99)
+        self.assertEqual(len(data["qnames"]), 3)
+        self.assertEqual(len(data["qtypes"]), 2)
+        self.assertEqual(data["type"], "OpenTelemetryTraceCondition")
+        self.assertTrue(data["edns_option_required"])
+        self.assertTrue(data["traceid_only"])
index c0e1206514743b078de5e434f34306c88acf82a4..ee61137102024e4da7297e4f4e9e00907e4e4e32 100644 (file)
@@ -6,89 +6,90 @@ from test_helper import ApiTestCase, is_auth, is_recursor, is_auth_lmdb
 
 
 class Servers(ApiTestCase):
-
     def test_list_servers(self):
         r = self.session.get(self.url("/api/v1/servers"))
         self.assert_success_json(r)
         lst = r.json()
         self.assertEqual(len(lst), 1)  # only localhost allowed in there
         data = lst[0]
-        for k in ('id', 'daemon_type', 'url'):
+        for k in ("id", "daemon_type", "url"):
             self.assertIn(k, data)
-        self.assertEqual(data['id'], 'localhost')
+        self.assertEqual(data["id"], "localhost")
 
     def test_servers_localhost(self):
         r = self.session.get(self.url("/api/v1/servers/localhost"))
         self.assert_success_json(r)
         data = r.json()
-        for k in ('id', 'type', 'version', 'daemon_type', 'url', 'zones_url', 'config_url'):
+        for k in ("id", "type", "version", "daemon_type", "url", "zones_url", "config_url"):
             self.assertIn(k, data)
-        self.assertEqual(data['id'], 'localhost')
-        self.assertEqual(data['type'], 'Server')
+        self.assertEqual(data["id"], "localhost")
+        self.assertEqual(data["type"], "Server")
         # or 'recursor' for recursors
         if is_auth():
-            daemon_type = 'authoritative'
+            daemon_type = "authoritative"
         elif is_recursor():
-            daemon_type = 'recursor'
+            daemon_type = "recursor"
         else:
-            raise RuntimeError('Unknown daemon type')
-        self.assertEqual(data['daemon_type'], daemon_type)
+            raise RuntimeError("Unknown daemon type")
+        self.assertEqual(data["daemon_type"], daemon_type)
 
     def test_read_config(self):
         r = self.session.get(self.url("/api/v1/servers/localhost/config"))
         self.assert_success_json(r)
-        data = dict([(r['name'], r['value']) for r in r.json()])
-        self.assertIn('daemon', data)
+        data = dict([(r["name"], r["value"]) for r in r.json()])
+        self.assertIn("daemon", data)
 
     def test_read_statistics(self):
         r = self.session.get(self.url("/api/v1/servers/localhost/statistics"))
         self.assert_success_json(r)
         data = r.json()
-        self.assertIn('uptime', [e['name'] for e in data])
+        self.assertIn("uptime", [e["name"] for e in data])
         print(data)
         if is_auth():
             qtype_stats, respsize_stats, queries_stats, rcode_stats = None, None, None, None
             for elem in data:
-                if elem['type'] == 'MapStatisticItem' and elem['name'] == 'response-by-qtype':
-                    qtype_stats = elem['value']
-                elif elem['type'] == 'MapStatisticItem' and elem['name'] == 'response-sizes':
-                    respsize_stats = elem['value']
-                elif elem['type'] == 'RingStatisticItem' and elem['name'] == 'queries':
-                    queries_stats = elem['value']
-                elif elem['type'] == 'MapStatisticItem' and elem['name'] == 'response-by-rcode':
-                    rcode_stats = elem['value']
-            self.assertIn('A', [e['name'] for e in qtype_stats])
-            self.assertIn('80', [e['name'] for e in respsize_stats])
-            self.assertIn('example.com/A', [e['name'] for e in queries_stats])
-            self.assertIn('No Error', [e['name'] for e in rcode_stats])
+                if elem["type"] == "MapStatisticItem" and elem["name"] == "response-by-qtype":
+                    qtype_stats = elem["value"]
+                elif elem["type"] == "MapStatisticItem" and elem["name"] == "response-sizes":
+                    respsize_stats = elem["value"]
+                elif elem["type"] == "RingStatisticItem" and elem["name"] == "queries":
+                    queries_stats = elem["value"]
+                elif elem["type"] == "MapStatisticItem" and elem["name"] == "response-by-rcode":
+                    rcode_stats = elem["value"]
+            self.assertIn("A", [e["name"] for e in qtype_stats])
+            self.assertIn("80", [e["name"] for e in respsize_stats])
+            self.assertIn("example.com/A", [e["name"] for e in queries_stats])
+            self.assertIn("No Error", [e["name"] for e in rcode_stats])
         else:
             qtype_stats, respsize_stats, rcode_stats = None, None, None
             for elem in data:
-                if elem['type'] == 'MapStatisticItem' and elem['name'] == 'response-by-qtype':
-                    qtype_stats = elem['value']
-                elif elem['type'] == 'MapStatisticItem' and elem['name'] == 'response-sizes':
-                    respsize_stats = elem['value']
-                elif elem['type'] == 'MapStatisticItem' and elem['name'] == 'response-by-rcode':
-                    rcode_stats = elem['value']
-            self.assertIn('A', [e['name'] for e in qtype_stats])
-            self.assertIn('60', [e['name'] for e in respsize_stats])
-            self.assertIn('80', [e['name'] for e in respsize_stats])
-            self.assertIn('No Error', [e['name'] for e in rcode_stats])
+                if elem["type"] == "MapStatisticItem" and elem["name"] == "response-by-qtype":
+                    qtype_stats = elem["value"]
+                elif elem["type"] == "MapStatisticItem" and elem["name"] == "response-sizes":
+                    respsize_stats = elem["value"]
+                elif elem["type"] == "MapStatisticItem" and elem["name"] == "response-by-rcode":
+                    rcode_stats = elem["value"]
+            self.assertIn("A", [e["name"] for e in qtype_stats])
+            self.assertIn("60", [e["name"] for e in respsize_stats])
+            self.assertIn("80", [e["name"] for e in respsize_stats])
+            self.assertIn("No Error", [e["name"] for e in rcode_stats])
 
     def test_read_one_statistic(self):
         r = self.session.get(self.url("/api/v1/servers/localhost/statistics?statistic=uptime"))
         self.assert_success_json(r)
         data = r.json()
-        self.assertIn('uptime', [e['name'] for e in data])
+        self.assertIn("uptime", [e["name"] for e in data])
 
     def test_read_one_non_existent_statistic(self):
         r = self.session.get(self.url("/api/v1/servers/localhost/statistics?statistic=uptimeAAAA"))
         self.assertEqual(r.status_code, 422)
-        self.assertIn("Unknown statistic name", r.json()['error'])
+        self.assertIn("Unknown statistic name", r.json()["error"])
 
     def test_read_metrics(self):
         if is_recursor():
-            res = self.session.get(self.url("/metrics"), auth=('whatever', self.webServerBasicAuthPassword), timeout=2.0)
+            res = self.session.get(
+                self.url("/metrics"), auth=("whatever", self.webServerBasicAuthPassword), timeout=2.0
+            )
             self.assertEqual(res.status_code, 200)
             # print(res.text)
             found = False
@@ -97,11 +98,13 @@ class Servers(ApiTestCase):
                     continue
                 if line.split(" ")[0] == "pdns_recursor_uptime":
                     found = True
-            self.assertTrue(found,"pdns_recursor_uptime is missing")
+            self.assertTrue(found, "pdns_recursor_uptime is missing")
 
     @unittest.skipIf(is_auth(), "Not applicable")
     def test_read_statistics_using_password(self):
-        r = requests.get(self.url("/api/v1/servers/localhost/statistics"), auth=('admin', self.server_web_password), verify=False)
+        r = requests.get(
+            self.url("/api/v1/servers/localhost/statistics"), auth=("admin", self.server_web_password), verify=False
+        )
         self.assertEqual(r.status_code, requests.codes.ok)
         self.assert_success_json(r)
 
@@ -109,59 +112,74 @@ class Servers(ApiTestCase):
     @unittest.skipIf(is_auth_lmdb(), "No autoprimary management in LMDB yet")
     def test_autoprimaries(self):
         # verify that we have zero autoprimaries
-        res = self.session.get(self.url("/api/v1/servers/localhost/autoprimaries"), auth=('whatever', self.webServerBasicAuthPassword), timeout=2.0)
+        res = self.session.get(
+            self.url("/api/v1/servers/localhost/autoprimaries"),
+            auth=("whatever", self.webServerBasicAuthPassword),
+            timeout=2.0,
+        )
         self.assertEqual(res.status_code, requests.codes.ok)
         self.assertEqual(res.json(), [])
 
         # add one
-        payload = {
-            'ip': '192.0.2.1',
-            'nameserver': 'ns.example.com'
-        }
+        payload = {"ip": "192.0.2.1", "nameserver": "ns.example.com"}
 
         res = self.session.post(
             self.url("/api/v1/servers/localhost/autoprimaries"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
 
         self.assertEqual(res.status_code, 201)
 
         # check that it's there
-        res = self.session.get(self.url("/api/v1/servers/localhost/autoprimaries"), auth=('whatever', self.webServerBasicAuthPassword), timeout=2.0)
+        res = self.session.get(
+            self.url("/api/v1/servers/localhost/autoprimaries"),
+            auth=("whatever", self.webServerBasicAuthPassword),
+            timeout=2.0,
+        )
         self.assertEqual(res.status_code, requests.codes.ok)
-        self.assertEqual(res.json(), [{'account': '', 'ip': '192.0.2.1', 'nameserver': 'ns.example.com'}])
+        self.assertEqual(res.json(), [{"account": "", "ip": "192.0.2.1", "nameserver": "ns.example.com"}])
 
         # add another one, this time with an account field
-        payload = {
-            'ip': '192.0.2.2',
-            'nameserver': 'ns.example.org',
-            'account': 'test'
-        }
+        payload = {"ip": "192.0.2.2", "nameserver": "ns.example.org", "account": "test"}
 
         res = self.session.post(
             self.url("/api/v1/servers/localhost/autoprimaries"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
 
         self.assertEqual(res.status_code, 201)
 
         # check that both are there
-        res = self.session.get(self.url("/api/v1/servers/localhost/autoprimaries"), auth=('whatever', self.webServerBasicAuthPassword), timeout=2.0)
+        res = self.session.get(
+            self.url("/api/v1/servers/localhost/autoprimaries"),
+            auth=("whatever", self.webServerBasicAuthPassword),
+            timeout=2.0,
+        )
         self.assertEqual(res.status_code, requests.codes.ok)
         self.assertEqual(len(res.json()), 2)
-        self.assertEqual(sorted(res.json(), key=operator.itemgetter('ip')), [
-            {'account': '', 'ip': '192.0.2.1', 'nameserver': 'ns.example.com'},
-            {'account': 'test', 'ip': '192.0.2.2', 'nameserver': 'ns.example.org'}
-            ])
+        self.assertEqual(
+            sorted(res.json(), key=operator.itemgetter("ip")),
+            [
+                {"account": "", "ip": "192.0.2.1", "nameserver": "ns.example.com"},
+                {"account": "test", "ip": "192.0.2.2", "nameserver": "ns.example.org"},
+            ],
+        )
 
         # remove one
         res = self.session.delete(
             self.url("/api/v1/servers/localhost/autoprimaries/192.0.2.2/ns.example.org"),
-            headers={'content-type': 'application/json"'})
+            headers={"content-type": 'application/json"'},
+        )
 
         self.assertEqual(res.status_code, 204)
 
         # check that we are back to just one
-        res = self.session.get(self.url("/api/v1/servers/localhost/autoprimaries"), auth=('whatever', self.webServerBasicAuthPassword), timeout=2.0)
+        res = self.session.get(
+            self.url("/api/v1/servers/localhost/autoprimaries"),
+            auth=("whatever", self.webServerBasicAuthPassword),
+            timeout=2.0,
+        )
         self.assertEqual(res.status_code, requests.codes.ok)
-        self.assertEqual(res.json(), [{'account': '', 'ip': '192.0.2.1', 'nameserver': 'ns.example.com'}])
+        self.assertEqual(res.json(), [{"account": "", "ip": "192.0.2.1", "nameserver": "ns.example.com"}])
index c0f7b59c820b8c76e121071d11f50960626d6fe8..f5a9efba75529e8d52875806e2214f13c127c2a5 100644 (file)
@@ -3,21 +3,23 @@ import json
 import unittest
 from test_helper import ApiTestCase, unique_tsigkey_name, is_auth
 
+
 class AuthTSIGHelperMixin(object):
-    def create_tsig_key(self, name=None, algorithm='hmac-md5', key=None):
+    def create_tsig_key(self, name=None, algorithm="hmac-md5", key=None):
         if name is None:
             name = unique_tsigkey_name()
         payload = {
-            'name': name,
-            'algorithm': algorithm,
+            "name": name,
+            "algorithm": algorithm,
         }
         if key is not None:
-            payload.update({'key': key})
+            payload.update({"key": key})
         print("sending", payload)
         r = self.session.post(
             self.url("/api/v1/servers/localhost/tsigkeys"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success_json(r)
         self.assertEqual(r.status_code, 201)
         reply = r.json()
@@ -32,7 +34,7 @@ class AuthTSIG(ApiTestCase, AuthTSIGHelperMixin):
         Create a TSIG key that is generated by the server
         """
         name, payload, data = self.create_tsig_key()
-        for k in ('id', 'name', 'algorithm', 'key', 'type'):
+        for k in ("id", "name", "algorithm", "key", "type"):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
@@ -41,61 +43,56 @@ class AuthTSIG(ApiTestCase, AuthTSIGHelperMixin):
         """
         Create a new key with the key data provided
         """
-        key = 'fn+BREHMDq0uWA1WbDwaoc2ne3rD973ySJ33ToJTfWY='
+        key = "fn+BREHMDq0uWA1WbDwaoc2ne3rD973ySJ33ToJTfWY="
         name, payload, data = self.create_tsig_key(key=key)
-        self.assertEqual(data['key'], key)
+        self.assertEqual(data["key"], key)
 
     def test_create_key_with_hmacsha512(self):
         """
         Have the server generate a key with the provided algorithm
         """
-        algorithm = 'hmac-sha512'
+        algorithm = "hmac-sha512"
         name, payload, data = self.create_tsig_key(algorithm=algorithm)
-        self.assertEqual(data['algorithm'], algorithm)
+        self.assertEqual(data["algorithm"], algorithm)
 
     def test_get_non_existing_key(self):
         """
         Try to get a key that does not exist
         """
         name = "idonotexist"
-        r = self.session.get(self.url(
-            "/api/v1/servers/localhost/tsigkeys/" + name + '.'),
-            headers={'accept': 'application/json'})
+        r = self.session.get(
+            self.url("/api/v1/servers/localhost/tsigkeys/" + name + "."), headers={"accept": "application/json"}
+        )
         self.assert_error_json(r)
         self.assertEqual(r.status_code, 404)
         newdata = r.json()
-        self.assertIn('TSIG key with name \'' + name + '\' not found', newdata['error'])
+        self.assertIn("TSIG key with name '" + name + "' not found", newdata["error"])
 
     def test_remove_key(self):
         """
         Create a key and attempt to delete it
         """
         name, payload, data = self.create_tsig_key()
-        r = self.session.delete(self.url("/api/v1/servers/localhost/tsigkeys/" + data['id']))
+        r = self.session.delete(self.url("/api/v1/servers/localhost/tsigkeys/" + data["id"]))
         self.assertEqual(r.status_code, 204)
-        r = self.session.get(self.url(
-            "/api/v1/servers/localhost/tsigkeys"),
-            headers={'accept': 'application/json'})
+        r = self.session.get(self.url("/api/v1/servers/localhost/tsigkeys"), headers={"accept": "application/json"})
         self.assertEqual(r.status_code, 200)
         keys = r.json()
-        self.assertEqual(len([key for key in keys if key['name'] == name]), 0)
+        self.assertEqual(len([key for key in keys if key["name"] == name]), 0)
 
     def test_put_key_change_name(self):
         """
         Rename a key by PUTing a json with "name" set
         """
         name, payload, data = self.create_tsig_key()
-        payload = {
-            'name': 'mynewkey'
-        }
-        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + data['id']),
-                             data=json.dumps(payload))
+        payload = {"name": "mynewkey"}
+        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + data["id"]), data=json.dumps(payload))
         self.assertEqual(r.status_code, 200)
         newdata = r.json()
-        self.assertEqual(newdata['name'], 'mynewkey')
+        self.assertEqual(newdata["name"], "mynewkey")
 
         # Check if the old key is removed
-        r = self.session.get(self.url("/api/v1/servers/localhost/tsigkeys/" + data['id']))
+        r = self.session.get(self.url("/api/v1/servers/localhost/tsigkeys/" + data["id"]))
         self.assertEqual(r.status_code, 404, "Old key was not removed!")
 
     def test_put_key_change_key(self):
@@ -103,92 +100,79 @@ class AuthTSIG(ApiTestCase, AuthTSIGHelperMixin):
         Change the key by PUTing it
         """
         name, payload, data = self.create_tsig_key()
-        newkey = 'l36TAJalAys0HeEfSM1rFzSmz9kSwfiBo3HNkL62COs='
-        payload = {
-            'key': newkey
-        }
-        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + data['id']),
-                             data=json.dumps(payload))
+        newkey = "l36TAJalAys0HeEfSM1rFzSmz9kSwfiBo3HNkL62COs="
+        payload = {"key": newkey}
+        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + data["id"]), data=json.dumps(payload))
         self.assertEqual(r.status_code, 200)
         data = r.json()
-        self.assertEqual(data['key'], newkey)
+        self.assertEqual(data["key"], newkey)
 
     def test_put_key_change_algo(self):
         name, payload, data = self.create_tsig_key()
-        newalgo = 'hmac-sha256'
-        payload = {
-            'algorithm': newalgo
-        }
-        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + data['id']),
-                             data=json.dumps(payload))
+        newalgo = "hmac-sha256"
+        payload = {"algorithm": newalgo}
+        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + data["id"]), data=json.dumps(payload))
         self.assertEqual(r.status_code, 200)
         data = r.json()
-        self.assertEqual(data['algorithm'], newalgo)
+        self.assertEqual(data["algorithm"], newalgo)
 
     def test_put_non_existing_algo(self):
         name, payload, data = self.create_tsig_key()
-        payload = {
-            'algorithm': 'foobar'
-        }
-        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + data['id']),
-                             data=json.dumps(payload))
+        payload = {"algorithm": "foobar"}
+        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + data["id"]), data=json.dumps(payload))
         self.assertEqual(r.status_code, 422)
         data = r.json()
-        self.assertIn('Unknown TSIG algorithm: ', data['error'])
+        self.assertIn("Unknown TSIG algorithm: ", data["error"])
 
     def test_put_broken_key(self):
         name, payload, data = self.create_tsig_key()
-        payload = {
-            'key': 'f\\u0333oobar1======'
-        }
-        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + data['id']),
-                             data=json.dumps(payload))
+        payload = {"key": "f\\u0333oobar1======"}
+        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + data["id"]), data=json.dumps(payload))
         data = r.json()
         self.assertEqual(r.status_code, 422)
-        self.assertIn('Can not base64 decode key content ', data['error'])
+        self.assertIn("Can not base64 decode key content ", data["error"])
 
     def test_put_to_non_existing_key(self):
         name = unique_tsigkey_name()
-        payload = {
-            'algorithm': 'hmac-sha512'
-        }
-        r = self.session.put(self.url("/api/v1/servers/localhost/tsigkeys/" + name + '.'),
-                             data=json.dumps(payload),
-                             headers={'accept': 'application/json'})
+        payload = {"algorithm": "hmac-sha512"}
+        r = self.session.put(
+            self.url("/api/v1/servers/localhost/tsigkeys/" + name + "."),
+            data=json.dumps(payload),
+            headers={"accept": "application/json"},
+        )
         self.assertEqual(r.status_code, 404)
         data = r.json()
-        self.assertIn('TSIG key with name \'' + name + '\' not found', data['error'])
+        self.assertIn("TSIG key with name '" + name + "' not found", data["error"])
 
     def test_post_existing_key_name(self):
         name, payload, data = self.create_tsig_key()
-        r = self.session.post(self.url("/api/v1/servers/localhost/tsigkeys"),
-                              headers={'accept': 'application/json'},
-                              data=json.dumps(payload))
+        r = self.session.post(
+            self.url("/api/v1/servers/localhost/tsigkeys"),
+            headers={"accept": "application/json"},
+            data=json.dumps(payload),
+        )
         self.assertEqual(r.status_code, 409)
         data = r.json()
-        self.assertIn('A TSIG key with the name ', data['error'])
+        self.assertIn("A TSIG key with the name ", data["error"])
 
     def test_post_broken_key_name(self):
-        payload = {
-            'name': unique_tsigkey_name(),
-            'key': 'f\\u0333oobar1======',
-            'algorithm': 'hmac-md5'
-        }
-        r = self.session.post(self.url("/api/v1/servers/localhost/tsigkeys"),
-                              headers={'accept': 'application/json'},
-                              data=json.dumps(payload))
+        payload = {"name": unique_tsigkey_name(), "key": "f\\u0333oobar1======", "algorithm": "hmac-md5"}
+        r = self.session.post(
+            self.url("/api/v1/servers/localhost/tsigkeys"),
+            headers={"accept": "application/json"},
+            data=json.dumps(payload),
+        )
         self.assertEqual(r.status_code, 422)
         data = r.json()
-        self.assertIn(' cannot be base64-decoded', data['error'])
+        self.assertIn(" cannot be base64-decoded", data["error"])
 
     def test_post_wrong_algo(self):
-        payload = {
-            'name': unique_tsigkey_name(),
-            'algorithm': 'foobar'
-        }
-        r = self.session.post(self.url("/api/v1/servers/localhost/tsigkeys"),
-                              headers={'accept': 'application/json'},
-                              data=json.dumps(payload))
+        payload = {"name": unique_tsigkey_name(), "algorithm": "foobar"}
+        r = self.session.post(
+            self.url("/api/v1/servers/localhost/tsigkeys"),
+            headers={"accept": "application/json"},
+            data=json.dumps(payload),
+        )
         self.assertEqual(r.status_code, 400)
         data = r.json()
-        self.assertIn('Invalid TSIG algorithm: ', data['error'])
+        self.assertIn("Invalid TSIG algorithm: ", data["error"])
index c8719bc414debbd9096ad946f296d8999d0e7cd5..c09eb9cac2d90e5acb0318e6bc4c50bf58e99fdb 100644 (file)
@@ -6,6 +6,7 @@ import unittest
 from test_helper import ApiTestCase, is_auth, is_auth_lmdb
 from test_Zones import AuthZonesHelperMixin
 
+
 @unittest.skipIf(not is_auth(), "Not applicable")
 @unittest.skipIf(not is_auth_lmdb(), "Views require the LMDB backend")
 class Networks(ApiTestCase):
@@ -16,94 +17,96 @@ class Networks(ApiTestCase):
         super(Networks, self).tearDown()
 
     def test_networks(self):
-        r = self.set_network('192.0.2.0/24', view='view1')
+        r = self.set_network("192.0.2.0/24", view="view1")
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
         # Check network presence
         nets = self.get_networks()
-        self.assertEqual(nets['192.0.2.0/24'], 'view1')
+        self.assertEqual(nets["192.0.2.0/24"], "view1")
 
         # Check individual fetch
-        r = self.get_network('192.0.2.0/24')
+        r = self.get_network("192.0.2.0/24")
         print(r.content)
         self.assertEqual(r.status_code, 200)
-        self.assertEqual(r.json(), dict(network='192.0.2.0/24', view='view1'))
+        self.assertEqual(r.json(), dict(network="192.0.2.0/24", view="view1"))
 
         # empty view name is equivalent to delete
-        r = self.set_network('192.0.2.0/24', view='')
+        r = self.set_network("192.0.2.0/24", view="")
         print(r.content)
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
         # Check network absence
         nets = self.get_networks()
-        self.assertNotIn('192.0.2.0/24', nets)
+        self.assertNotIn("192.0.2.0/24", nets)
 
         # Check individual fetch
-        r = self.get_network('192.0.2.0/24')
+        r = self.get_network("192.0.2.0/24")
         print(r.content)
         self.assertEqual(r.status_code, 404)
 
     def set_network(self, prefix, **content):
         r = self.session.put(
-            self.url("/api/v1/servers/localhost/networks/"+prefix),
+            self.url("/api/v1/servers/localhost/networks/" + prefix),
             data=json.dumps(content),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
 
         return r
 
     def get_network(self, prefix):
         r = self.session.get(
-            self.url("/api/v1/servers/localhost/networks/"+prefix),
-            headers={'content-type': 'application/json'})
+            self.url("/api/v1/servers/localhost/networks/" + prefix), headers={"content-type": "application/json"}
+        )
 
         return r
 
     def get_networks(self):
         r = self.session.get(
-            self.url("/api/v1/servers/localhost/networks"),
-            headers={'content-type': 'application/json'})
+            self.url("/api/v1/servers/localhost/networks"), headers={"content-type": "application/json"}
+        )
 
         ret = {}
 
-        for netview in r.json()['networks']:
-            net = netview['network']
-            view = netview['view']
+        for netview in r.json()["networks"]:
+            net = netview["network"]
+            view = netview["view"]
             self.assertNotIn(net, ret)
             ret[net] = view
 
         return ret
 
+
 @unittest.skipIf(not is_auth(), "Not applicable")
 @unittest.skipIf(not is_auth_lmdb(), "Views require the LMDB backend")
 class Views(ApiTestCase, AuthZonesHelperMixin):
     def setUp(self):
         super(Views, self).setUp()
-        self.create_zone('example.com..spiceoflife')
+        self.create_zone("example.com..spiceoflife")
 
     def tearDown(self):
         super(Views, self).tearDown()
         self.session.delete(self.url("/api/v1/servers/localhost/zones/example.com..spiceoflife"))
 
-    def _test_views(self, variant=''):
-        zone = 'example.com.' + variant
-        r = self.set_view_zone('view1', zone)
+    def _test_views(self, variant=""):
+        zone = "example.com." + variant
+        r = self.set_view_zone("view1", zone)
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
         # Check view presence
         r = self.get_views()
         self.assertEqual(r.status_code, 200)
-        self.assertIn('view1', r.json()["views"])
+        self.assertIn("view1", r.json()["views"])
 
         # Check individual fetch
-        r = self.get_view('view1')
+        r = self.get_view("view1")
         print(r)
         self.assertEqual(r.status_code, 200)
         self.assertEqual(r.json()["zones"], [zone])
 
-        r = self.del_view_zone('view1', zone)
+        r = self.del_view_zone("view1", zone)
         print(r.content)
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
@@ -111,17 +114,15 @@ class Views(ApiTestCase, AuthZonesHelperMixin):
         # Check view absence
         r = self.get_views()
         self.assertEqual(r.status_code, 200)
-        self.assertNotIn('view1', r.json()["views"])
+        self.assertNotIn("view1", r.json()["views"])
 
         # Check individual fetch
-        r = self.get_view('view1')
+        r = self.get_view("view1")
         print(r.content)
         self.assertEqual(r.status_code, 404)
 
     def test_zonelist_variant(self):
-        r = self.session.get(
-            self.url("/api/v1/servers/localhost/zones"),
-            headers={'content-type': 'application/json'})
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones"), headers={"content-type": "application/json"})
 
         self.assertEqual(r.status_code, 200)
         self.assertIn("example.com..spiceoflife", [obj["name"] for obj in r.json()])
@@ -130,13 +131,14 @@ class Views(ApiTestCase, AuthZonesHelperMixin):
         return self._test_views()
 
     def test_views_variant(self):
-        return self._test_views('.spiceoflife')
+        return self._test_views(".spiceoflife")
 
     def set_view_zone(self, view, zone):
         r = self.session.post(
-            self.url("/api/v1/servers/localhost/views/"+view),
+            self.url("/api/v1/servers/localhost/views/" + view),
             data=json.dumps(dict(name=zone)),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
 
         self.assertEqual(r.status_code, 204)
 
@@ -144,9 +146,10 @@ class Views(ApiTestCase, AuthZonesHelperMixin):
 
     def del_view_zone(self, view, zone):
         r = self.session.delete(
-            self.url("/api/v1/servers/localhost/views/"+view+"/"+zone),
+            self.url("/api/v1/servers/localhost/views/" + view + "/" + zone),
             data=json.dumps(dict(name=zone)),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
 
         self.assertEqual(r.status_code, 204)
 
@@ -154,15 +157,13 @@ class Views(ApiTestCase, AuthZonesHelperMixin):
 
     def get_view(self, view):
         r = self.session.get(
-            self.url("/api/v1/servers/localhost/views/"+view),
-            headers={'content-type': 'application/json'})
+            self.url("/api/v1/servers/localhost/views/" + view), headers={"content-type": "application/json"}
+        )
 
         return r
 
     def get_views(self):
-        r = self.session.get(
-            self.url("/api/v1/servers/localhost/views"),
-            headers={'content-type': 'application/json'})
+        r = self.session.get(self.url("/api/v1/servers/localhost/views"), headers={"content-type": "application/json"})
 
         self.assertEqual(r.status_code, 200)
 
index d5aed7a9e3b49cfe56af3205cb459982b21d5135..9a7a343a97d82e324bef18fc1b75eff6de4dc3b0 100644 (file)
@@ -6,25 +6,37 @@ import unittest
 from copy import deepcopy
 from parameterized import parameterized
 from pprint import pprint
-from test_helper import ApiTestCase, unique_zone_name, is_auth, is_auth_lmdb, is_recursor, get_auth_db, get_db_records, pdnsutil_rectify, sdig
+from test_helper import (
+    ApiTestCase,
+    unique_zone_name,
+    is_auth,
+    is_auth_lmdb,
+    is_recursor,
+    get_auth_db,
+    get_db_records,
+    pdnsutil_rectify,
+    sdig,
+)
 
 
 def remove_timestamp(json):
     for item in json:
-        if 'modified_at' in item:
-            del item['modified_at']
+        if "modified_at" in item:
+            del item["modified_at"]
 
-def get_rrset(data, qname, qtype = None):
-    for rrset in data['rrsets']:
-        if rrset['name'] == qname and (qtype is None or rrset['type'] == qtype):
-            remove_timestamp(rrset['records'])
+
+def get_rrset(data, qname, qtype=None):
+    for rrset in data["rrsets"]:
+        if rrset["name"] == qname and (qtype is None or rrset["type"] == qtype):
+            remove_timestamp(rrset["records"])
             return rrset
     return None
 
+
 def get_first_rec(data, qname, qtype):
     rrset = get_rrset(data, qname, qtype)
     if rrset:
-        return rrset['records'][0]
+        return rrset["records"][0]
     return None
 
 
@@ -35,15 +47,15 @@ def eq_zone_rrsets(rrsets, expected):
         type_ = str(type_)
         data_got[type_] = set()
         data_expected[type_] = set()
-        uses_name = any(['name' in expected_record for expected_record in expected_records])
+        uses_name = any(["name" in expected_record for expected_record in expected_records])
         # minify + convert received data
-        for rrset in [rrset for rrset in rrsets if rrset['type'] == type_]:
+        for rrset in [rrset for rrset in rrsets if rrset["type"] == type_]:
             print(rrset)
-            for r in rrset['records']:
-                data_got[type_].add((rrset['name'] if uses_name else '@', rrset['type'], r['content']))
+            for r in rrset["records"]:
+                data_got[type_].add((rrset["name"] if uses_name else "@", rrset["type"], r["content"]))
         # minify expected data
         for r in expected_records:
-            data_expected[type_].add((r['name'] if uses_name else '@', type_, r['content']))
+            data_expected[type_].add((r["name"] if uses_name else "@", type_, r["content"]))
 
     print("eq_zone_rrsets: got:")
     pprint(data_got)
@@ -52,11 +64,13 @@ def eq_zone_rrsets(rrsets, expected):
 
     assert data_got == data_expected, "%r != %r" % (data_got, data_expected)
 
+
 def assert_eq_rrsets(rrsets, expected):
     """Assert rrsets sets are equal, ignoring sort order."""
-    key = lambda rrset: (rrset['name'], rrset['type'])
+    key = lambda rrset: (rrset["name"], rrset["type"])
     assert sorted(rrsets, key=key) == sorted(expected, key=key)
 
+
 def templated_rrsets(rrsets: list, zonename: str):
     """
     Replace $NAME$ in `name` and `content` of given rrsets with `zonename`.
@@ -64,34 +78,34 @@ def templated_rrsets(rrsets: list, zonename: str):
     """
     new_rrsets = []
     for rrset in rrsets:
-        new_rrset = rrset | {"name": rrset["name"].replace('$NAME$', zonename)}
+        new_rrset = rrset | {"name": rrset["name"].replace("$NAME$", zonename)}
 
         if "records" in rrset:
             records = []
             for record in rrset["records"]:
-                records.append(record | {"content": record["content"].replace('$NAME$', zonename)})
+                records.append(record | {"content": record["content"].replace("$NAME$", zonename)})
             new_rrset["records"] = records
 
         new_rrsets.append(new_rrset)
 
     return new_rrsets
 
-class ZonesApiTestCase(ApiTestCase):
 
+class ZonesApiTestCase(ApiTestCase):
     def assert_in_json_error(self, expected, json):
-        error = json['error']
+        error = json["error"]
         if expected not in error:
             found = False
-            if 'errors' in json:
-                errors = json['errors']
+            if "errors" in json:
+                errors = json["errors"]
                 for item in errors:
                     if expected in item:
                         found = True
                 assert found, "%r not found in %r" % (expected, errors)
             assert found, "%r not found in %r" % (expected, error)
 
-class Zones(ZonesApiTestCase):
 
+class Zones(ZonesApiTestCase):
     def _test_list_zones(self, dnssec=True):
         path = "/api/v1/servers/localhost/zones"
         if not dnssec:
@@ -99,20 +113,27 @@ class Zones(ZonesApiTestCase):
         r = self.session.get(self.url(path))
         self.assert_success_json(r)
         domains = r.json()
-        example_com = [domain for domain in domains if domain['name'] in ('example.com', 'example.com.')]
+        example_com = [domain for domain in domains if domain["name"] in ("example.com", "example.com.")]
         self.assertEqual(len(example_com), 1)
         example_com = example_com[0]
         print(example_com)
-        required_fields = ['id', 'url', 'name', 'kind']
+        required_fields = ["id", "url", "name", "kind"]
         if is_auth():
-            required_fields = required_fields + ['masters', 'last_check', 'notified_serial', 'serial', 'account', 'catalog']
+            required_fields = required_fields + [
+                "masters",
+                "last_check",
+                "notified_serial",
+                "serial",
+                "account",
+                "catalog",
+            ]
             if dnssec:
-                required_fields = required_fields + ['dnssec', 'edited_serial']
-            self.assertNotEqual(example_com['serial'], 0)
+                required_fields = required_fields + ["dnssec", "edited_serial"]
+            self.assertNotEqual(example_com["serial"], 0)
             if not dnssec:
-                self.assertNotIn('dnssec', example_com)
+                self.assertNotIn("dnssec", example_com)
         elif is_recursor():
-            required_fields = required_fields + ['recursion_desired', 'servers']
+            required_fields = required_fields + ["recursion_desired", "servers"]
         for field in required_fields:
             self.assertIn(field, example_com)
 
@@ -128,11 +149,7 @@ class AuthZonesHelperMixin(object):
     def create_zone(self, name=None, expect_error=None, **kwargs):
         if name is None:
             name = unique_zone_name()
-        payload = {
-            "name": name,
-            "kind": "Native",
-            "nameservers": ["ns1.example.com.", "ns2.example.com."]
-        }
+        payload = {"name": name, "kind": "Native", "nameservers": ["ns1.example.com.", "ns2.example.com."]}
         for k, v in kwargs.items():
             if v is None:
                 del payload[k]
@@ -147,7 +164,8 @@ class AuthZonesHelperMixin(object):
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={"content-type": "application/json"})
+            headers={"content-type": "application/json"},
+        )
 
         if expect_error:
             self.assertEqual(r.status_code, 422, r.content)
@@ -165,10 +183,7 @@ class AuthZonesHelperMixin(object):
 
     def get_zone(self, api_zone_id, expect_error=None, **kwargs):
         print("GET zone", api_zone_id, "args:", kwargs)
-        r = self.session.get(
-            self.url("/api/v1/servers/localhost/zones/" + api_zone_id),
-            params=kwargs
-        )
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + api_zone_id), params=kwargs)
 
         reply = r.json()
         print("reply", reply)
@@ -191,7 +206,8 @@ class AuthZonesHelperMixin(object):
         r = self.session.put(
             self.url("/api/v1/servers/localhost/zones/" + api_zone_id),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
 
         print("reply status code:", r.status_code)
         if expect_error:
@@ -205,49 +221,64 @@ class AuthZonesHelperMixin(object):
             # expect success (no content)
             self.assertEqual(r.status_code, 204, r.content)
 
+
 @unittest.skipIf(not is_auth(), "Not applicable")
 class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
-
     def test_create_zone(self):
         # soa_edit_api has a default, override with empty for this test
-        name, payload, data = self.create_zone(serial=22, soa_edit_api='')
-        for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'edited_serial', 'soa_edit_api', 'soa_edit', 'account'):
+        name, payload, data = self.create_zone(serial=22, soa_edit_api="")
+        for k in (
+            "id",
+            "url",
+            "name",
+            "masters",
+            "kind",
+            "last_check",
+            "notified_serial",
+            "serial",
+            "edited_serial",
+            "soa_edit_api",
+            "soa_edit",
+            "account",
+        ):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
         # validate generated SOA
-        expected_soa = "a.misconfigured.dns.server.invalid. hostmaster." + name + " " + \
-                       str(payload['serial']) + " 10800 3600 604800 3600"
-        self.assertEqual(
-            get_first_rec(data, name, 'SOA')['content'],
-            expected_soa
+        expected_soa = (
+            "a.misconfigured.dns.server.invalid. hostmaster."
+            + name
+            + " "
+            + str(payload["serial"])
+            + " 10800 3600 604800 3600"
         )
+        self.assertEqual(get_first_rec(data, name, "SOA")["content"], expected_soa)
 
         if not is_auth_lmdb():
             # Because we had confusion about dots, check that the DB is without dots.
-            dbrecs = get_db_records(name, 'SOA')
-            self.assertEqual(dbrecs[0]['content'], expected_soa.replace('. ', ' '))
-            self.assertNotEqual(data['serial'], data['edited_serial'])
+            dbrecs = get_db_records(name, "SOA")
+            self.assertEqual(dbrecs[0]["content"], expected_soa.replace(". ", " "))
+            self.assertNotEqual(data["serial"], data["edited_serial"])
 
     def test_create_zone_with_soa_edit_api(self):
         # soa_edit_api wins over serial
-        name, payload, data = self.create_zone(soa_edit_api='EPOCH', serial=10)
-        for k in ('soa_edit_api', ):
+        name, payload, data = self.create_zone(soa_edit_api="EPOCH", serial=10)
+        for k in ("soa_edit_api",):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
         # generated EPOCH serial surely is > fixed serial we passed in
         print(data)
-        self.assertGreater(data['serial'], payload['serial'])
-        soa_serial = int(get_first_rec(data, name, 'SOA')['content'].split(' ')[2])
-        self.assertGreater(soa_serial, payload['serial'])
-        self.assertEqual(soa_serial, data['serial'])
+        self.assertGreater(data["serial"], payload["serial"])
+        soa_serial = int(get_first_rec(data, name, "SOA")["content"].split(" ")[2])
+        self.assertGreater(soa_serial, payload["serial"])
+        self.assertEqual(soa_serial, data["serial"])
 
     def test_create_zone_with_catalog(self):
         # soa_edit_api wins over serial
-        name, payload, data = self.create_zone(catalog='catalog.invalid.', serial=10)
+        name, payload, data = self.create_zone(catalog="catalog.invalid.", serial=10)
         print(data)
-        for k in ('catalog', ):
+        for k in ("catalog",):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
@@ -256,102 +287,93 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
         r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         self.assert_success_json(r)
         domains = r.json()
-        domain = [domain for domain in domains if domain['name'] == name]
+        domain = [domain for domain in domains if domain["name"] == name]
         self.assertEqual(len(domain), 1)
         domain = domain[0]
         self.assertEqual(domain["catalog"], "catalog.invalid.")
 
     def test_create_zone_with_account(self):
         # soa_edit_api wins over serial
-        name, payload, data = self.create_zone(account='anaccount', serial=10, kind='Master')
+        name, payload, data = self.create_zone(account="anaccount", serial=10, kind="Master")
         print(data)
-        for k in ('account', ):
+        for k in ("account",):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
 
         # as we did not set a catalog in our request, check that the default catalog was applied
-        self.assertEqual(data['catalog'], "default-catalog.example.com.")
+        self.assertEqual(data["catalog"], "default-catalog.example.com.")
 
     def test_create_zone_default_soa_edit_api(self):
         """Test that zones created without soa_edit_api get the configured default-soa-edit-api value."""
         name, payload, data = self.create_zone()
         print(data)
         # default-soa-edit-api is set to EPOCH in the test config
-        self.assertEqual(data['soa_edit_api'], 'EPOCH')
+        self.assertEqual(data["soa_edit_api"], "EPOCH")
 
     def test_create_zone_override_soa_edit_api(self):
         """Test that explicitly setting soa_edit_api overrides the default."""
-        name, payload, data = self.create_zone(soa_edit_api='SOA-EDIT-INCREASE')
+        name, payload, data = self.create_zone(soa_edit_api="SOA-EDIT-INCREASE")
         print(data)
-        self.assertEqual(data['soa_edit_api'], 'SOA-EDIT-INCREASE')
+        self.assertEqual(data["soa_edit_api"], "SOA-EDIT-INCREASE")
 
     def test_create_zone_empty_soa_edit_api(self):
         """Test that explicitly setting soa_edit_api to empty does not use default."""
-        name, payload, data = self.create_zone(soa_edit_api='')
+        name, payload, data = self.create_zone(soa_edit_api="")
         print(data)
-        self.assertEqual(data['soa_edit_api'], '')
+        self.assertEqual(data["soa_edit_api"], "")
 
     def test_update_zone_does_not_override_soa_edit_api(self):
         """Test that updating a zone does not change existing soa_edit_api to default."""
         # Create zone with empty soa_edit_api
-        name, payload, data = self.create_zone(soa_edit_api='')
-        self.assertEqual(data['soa_edit_api'], '')
+        name, payload, data = self.create_zone(soa_edit_api="")
+        self.assertEqual(data["soa_edit_api"], "")
         # Update zone without specifying soa_edit_api - it should remain empty
-        update_payload = {
-            'kind': 'Master',
-            'masters': ['192.0.2.1']
-        }
+        update_payload = {"kind": "Master", "masters": ["192.0.2.1"]}
         self.put_zone(name, update_payload)
         data = self.get_zone(name)
         # Verify soa_edit_api was NOT changed to the default value
-        self.assertEqual(data['soa_edit_api'], '')
+        self.assertEqual(data["soa_edit_api"], "")
 
     def test_create_zone_exists(self):
         name, payload, data = self.create_zone()
         print(data)
-        payload = {
-            'name': name,
-            'kind': 'Native'
-        }
+        payload = {"name": name, "kind": "Native"}
         print(payload)
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 409)  # Conflict - already exists
-        self.assertIn("Conflict", r.json()['error'])
+        self.assertIn("Conflict", r.json()["error"])
 
     def test_create_zone_with_soa_edit(self):
-        name, payload, data = self.create_zone(soa_edit='INCEPTION-INCREMENT', soa_edit_api='SOA-EDIT-INCREASE')
+        name, payload, data = self.create_zone(soa_edit="INCEPTION-INCREMENT", soa_edit_api="SOA-EDIT-INCREASE")
         print(data)
-        self.assertEqual(data['soa_edit'], 'INCEPTION-INCREMENT')
-        self.assertEqual(data['soa_edit_api'], 'SOA-EDIT-INCREASE')
-        soa_serial = get_first_rec(data, name, 'SOA')['content'].split(' ')[2]
+        self.assertEqual(data["soa_edit"], "INCEPTION-INCREMENT")
+        self.assertEqual(data["soa_edit_api"], "SOA-EDIT-INCREASE")
+        soa_serial = get_first_rec(data, name, "SOA")["content"].split(" ")[2]
         # These particular settings lead to the first serial set to YYYYMMDD01.
-        self.assertEqual(soa_serial[-2:], '01')
+        self.assertEqual(soa_serial[-2:], "01")
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "127.0.0.1",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "A",
+            "ttl": 3600,
+            "records": [{"content": "127.0.0.1", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
-            self.url("/api/v1/servers/localhost/zones/" + data['id']),
+            self.url("/api/v1/servers/localhost/zones/" + data["id"]),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
-        data = self.get_zone(data['id'])
-        soa_serial = get_first_rec(data, name, 'SOA')['content'].split(' ')[2]
-        self.assertEqual(soa_serial[-2:], '02')
-        self.assertEqual(r.headers['X-PDNS-Old-Serial'][-2:], '01')
-        self.assertEqual(r.headers['X-PDNS-New-Serial'][-2:], '02')
+            headers={"content-type": "application/json"},
+        )
+        data = self.get_zone(data["id"])
+        soa_serial = get_first_rec(data, name, "SOA")["content"].split(" ")[2]
+        self.assertEqual(soa_serial[-2:], "02")
+        self.assertEqual(r.headers["X-PDNS-Old-Serial"][-2:], "01")
+        self.assertEqual(r.headers["X-PDNS-New-Serial"][-2:], "02")
 
     def test_create_zone_with_records(self):
         name = unique_zone_name()
@@ -359,14 +381,16 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
             "name": name,
             "type": "A",
             "ttl": 3600,
-            "records": [{
-                "content": "4.3.2.1",
-                "disabled": False,
-            }],
+            "records": [
+                {
+                    "content": "4.3.2.1",
+                    "disabled": False,
+                }
+            ],
         }
         name, payload, data = self.create_zone(name=name, rrsets=[rrset])
         # check our record has appeared
-        self.assertEqual(get_rrset(data, name, 'A')['records'], rrset['records'])
+        self.assertEqual(get_rrset(data, name, "A")["records"], rrset["records"])
 
     def test_create_zone_with_records_ordered(self):
         name = unique_zone_name()
@@ -400,185 +424,199 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
                 {
                     "content": "ns1.example.net.",
                     "disabled": False,
-                }
+                },
             ],
         }
 
         name, payload, data = self.create_zone(name=name, rrsets=[rrset_a, rrset_ns])
         # check our record has appeared
-        self.assertEqual(get_rrset(data, name, 'A')['records'], [
-            # The content should be lexographically ordered when retrieving
-            {
-                "content": "127.0.0.1",
-                "disabled": False,
-            },
-            {
-                "content": "4.3.2.1",
-                "disabled": False,
-            },
-        ])
+        self.assertEqual(
+            get_rrset(data, name, "A")["records"],
+            [
+                # The content should be lexographically ordered when retrieving
+                {
+                    "content": "127.0.0.1",
+                    "disabled": False,
+                },
+                {
+                    "content": "4.3.2.1",
+                    "disabled": False,
+                },
+            ],
+        )
 
-        self.assertEqual(get_rrset(data, rrset_ns['name'], 'NS')['records'], [
-            {
-                "content": "ns1.example.net.",
-                "disabled": False,
-            },
-            {
-                "content": "ns2.example.com.",
-                "disabled": False,
-            }
-        ])
+        self.assertEqual(
+            get_rrset(data, rrset_ns["name"], "NS")["records"],
+            [
+                {
+                    "content": "ns1.example.net.",
+                    "disabled": False,
+                },
+                {
+                    "content": "ns2.example.com.",
+                    "disabled": False,
+                },
+            ],
+        )
 
     def test_create_zone_with_wildcard_records(self):
         name = unique_zone_name()
         rrset = {
-            "name": "*."+name,
+            "name": "*." + name,
             "type": "A",
             "ttl": 3600,
-            "records": [{
-                "content": "4.3.2.1",
-                "disabled": False,
-            }],
+            "records": [
+                {
+                    "content": "4.3.2.1",
+                    "disabled": False,
+                }
+            ],
         }
         name, payload, data = self.create_zone(name=name, rrsets=[rrset])
         # check our record has appeared
-        self.assertEqual(get_rrset(data, rrset['name'], 'A')['records'], rrset['records'])
+        self.assertEqual(get_rrset(data, rrset["name"], "A")["records"], rrset["records"])
 
     def test_create_zone_with_comments(self):
         name = unique_zone_name()
         rrsets = [
-              {
-                  "name": name,
-                  "type": "soa",  # test uppercasing of type, too.
-                  "comments": [{
-                      "account": "test1",
-                      "content": "blah blah and test a few non-ASCII chars: Ã¶, â‚¬",
-                      "modified_at": 11112,
-                  }],
-              },
-              {
-                  "name": name,
-                  "type": "AAAA",
-                  "ttl": 3600,
-                  "records": [{
-                      "content": "2001:DB8::1",
-                      "disabled": False,
-                  }],
-                  "comments": [{
-                      "account": "test AAAA",
-                      "content": "blah blah AAAA",
-                      "modified_at": 11112,
-                  }],
-              },
-              {
-                  "name": name,
-                  "type": "TXT",
-                  "ttl": 3600,
-                  "records": [{
-                      "content": "\"test TXT\"",
-                      "disabled": False,
-                  }],
-              },
-              {
-                  "name": name,
-                  "type": "A",
-                  "ttl": 3600,
-                  "records": [{
-                      "content": "192.0.2.1",
-                      "disabled": False,
-                  }],
-              },
-          ]
+            {
+                "name": name,
+                "type": "soa",  # test uppercasing of type, too.
+                "comments": [
+                    {
+                        "account": "test1",
+                        "content": "blah blah and test a few non-ASCII chars: Ã¶, â‚¬",
+                        "modified_at": 11112,
+                    }
+                ],
+            },
+            {
+                "name": name,
+                "type": "AAAA",
+                "ttl": 3600,
+                "records": [
+                    {
+                        "content": "2001:DB8::1",
+                        "disabled": False,
+                    }
+                ],
+                "comments": [
+                    {
+                        "account": "test AAAA",
+                        "content": "blah blah AAAA",
+                        "modified_at": 11112,
+                    }
+                ],
+            },
+            {
+                "name": name,
+                "type": "TXT",
+                "ttl": 3600,
+                "records": [
+                    {
+                        "content": '"test TXT"',
+                        "disabled": False,
+                    }
+                ],
+            },
+            {
+                "name": name,
+                "type": "A",
+                "ttl": 3600,
+                "records": [
+                    {
+                        "content": "192.0.2.1",
+                        "disabled": False,
+                    }
+                ],
+            },
+        ]
 
         if is_auth_lmdb():
             # No comments in LMDB
-            self.create_zone(name=name, rrsets=rrsets, expect_error="Hosting backend does not support editing comments.")
+            self.create_zone(
+                name=name, rrsets=rrsets, expect_error="Hosting backend does not support editing comments."
+            )
             return
 
         name, _, data = self.create_zone(name=name, rrsets=rrsets)
         # NS records have been created
-        self.assertEqual(len(data['rrsets']), len(rrsets) + 1)
+        self.assertEqual(len(data["rrsets"]), len(rrsets) + 1)
         # check our comment has appeared
-        self.assertEqual(get_rrset(data, name, 'SOA')['comments'], rrsets[0]['comments'])
-        self.assertEqual(get_rrset(data, name, 'A')['comments'], [])
-        self.assertEqual(get_rrset(data, name, 'TXT')['comments'], [])
-        self.assertEqual(get_rrset(data, name, 'AAAA')['comments'], rrsets[1]['comments'])
+        self.assertEqual(get_rrset(data, name, "SOA")["comments"], rrsets[0]["comments"])
+        self.assertEqual(get_rrset(data, name, "A")["comments"], [])
+        self.assertEqual(get_rrset(data, name, "TXT")["comments"], [])
+        self.assertEqual(get_rrset(data, name, "AAAA")["comments"], rrsets[1]["comments"])
 
     def test_create_zone_uncanonical_nameservers(self):
         name = unique_zone_name()
-        payload = {
-            'name': name,
-            'kind': 'Native',
-            'nameservers': ['uncanon.example.com']
-        }
+        payload = {"name": name, "kind": "Native", "nameservers": ["uncanon.example.com"]}
         print(payload)
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Nameserver is not canonical', r.json())
+        self.assert_in_json_error("Nameserver is not canonical", r.json())
 
     def test_create_auth_zone_no_name(self):
         payload = {
-            'name': '',
-            'kind': 'Native',
+            "name": "",
+            "kind": "Native",
         }
         print(payload)
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('is not canonical', r.json())
+        self.assert_in_json_error("is not canonical", r.json())
 
     def test_create_zone_with_custom_soa(self):
         name = unique_zone_name()
-        content = u"ns1.example.net. testmaster@example.net. 10 10800 3600 604800 3600"
+        content = "ns1.example.net. testmaster@example.net. 10 10800 3600 604800 3600"
         rrset = {
             "name": name,
             "type": "soa",  # test uppercasing of type, too.
             "ttl": 3600,
-            "records": [{
-                "content": content,
-                "disabled": False,
-            }],
+            "records": [
+                {
+                    "content": content,
+                    "disabled": False,
+                }
+            ],
         }
-        name, payload, data = self.create_zone(name=name, rrsets=[rrset], soa_edit_api='')
-        self.assertEqual(get_rrset(data, name, 'SOA')['records'], rrset['records'])
+        name, payload, data = self.create_zone(name=name, rrsets=[rrset], soa_edit_api="")
+        self.assertEqual(get_rrset(data, name, "SOA")["records"], rrset["records"])
         if not is_auth_lmdb():
-            dbrecs = get_db_records(name, 'SOA')
-            self.assertEqual(dbrecs[0]['content'], content.replace('. ', ' '))
+            dbrecs = get_db_records(name, "SOA")
+            self.assertEqual(dbrecs[0]["content"], content.replace(". ", " "))
 
     def test_create_zone_double_dot(self):
-        name = 'test..' + unique_zone_name()
-        payload = {
-            'name': name,
-            'kind': 'Native',
-            'nameservers': ['ns1.example.com.']
-        }
+        name = "test.." + unique_zone_name()
+        payload = {"name": name, "kind": "Native", "nameservers": ["ns1.example.com."]}
         print(payload)
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Unable to parse Zone Name', r.json())
+        self.assert_in_json_error("Unable to parse Zone Name", r.json())
 
     def test_create_zone_restricted_chars(self):
-        name = 'test:' + unique_zone_name()  # : isn't good as a name.
-        payload = {
-            'name': name,
-            'kind': 'Native',
-            'nameservers': ['ns1.example.com']
-        }
+        name = "test:" + unique_zone_name()  # : isn't good as a name.
+        payload = {"name": name, "kind": "Native", "nameservers": ["ns1.example.com"]}
         print(payload)
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('contains unsupported characters', r.json())
+        self.assert_in_json_error("contains unsupported characters", r.json())
 
     def test_create_zone_mixed_nameservers_ns_rrset_zonelevel(self):
         name = unique_zone_name()
@@ -586,75 +624,82 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
             "name": name,
             "type": "NS",
             "ttl": 3600,
-            "records": [{
-                "content": "ns2.example.com.",
-                "disabled": False,
-            }],
+            "records": [
+                {
+                    "content": "ns2.example.com.",
+                    "disabled": False,
+                }
+            ],
         }
         payload = {
-            'name': name,
-            'kind': 'Native',
-            'nameservers': ['ns1.example.com.'],
-            'rrsets': [rrset],
+            "name": name,
+            "kind": "Native",
+            "nameservers": ["ns1.example.com."],
+            "rrsets": [rrset],
         }
         print(payload)
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Nameservers list MUST NOT be mixed with zone-level NS in rrsets', r.json())
+        self.assert_in_json_error("Nameservers list MUST NOT be mixed with zone-level NS in rrsets", r.json())
 
     def test_create_zone_mixed_nameservers_ns_rrset_below_zonelevel(self):
         name = unique_zone_name()
         rrset = {
-            "name": 'subzone.'+name,
+            "name": "subzone." + name,
             "type": "NS",
             "ttl": 3600,
-            "records": [{
-                "content": "ns2.example.com.",
-                "disabled": False,
-            }],
+            "records": [
+                {
+                    "content": "ns2.example.com.",
+                    "disabled": False,
+                }
+            ],
         }
         payload = {
-            'name': name,
-            'kind': 'Native',
-            'nameservers': ['ns1.example.com.'],
-            'rrsets': [rrset],
+            "name": name,
+            "kind": "Native",
+            "nameservers": ["ns1.example.com."],
+            "rrsets": [rrset],
         }
         print(payload)
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success_json(r)
 
     def test_create_zone_with_symbols(self):
-        name, payload, data = self.create_zone(name='foo/bar.'+unique_zone_name())
-        name = payload['name']
-        expected_id = name.replace('/', '=2F')
-        for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial'):
+        name, payload, data = self.create_zone(name="foo/bar." + unique_zone_name())
+        name = payload["name"]
+        expected_id = name.replace("/", "=2F")
+        for k in ("id", "url", "name", "masters", "kind", "last_check", "notified_serial", "serial"):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
-        self.assertEqual(data['id'], expected_id)
+        self.assertEqual(data["id"], expected_id)
         if not is_auth_lmdb():
-            dbrecs = get_db_records(name, 'SOA')
-            self.assertEqual(dbrecs[0]['name'], name.rstrip('.'))
+            dbrecs = get_db_records(name, "SOA")
+            self.assertEqual(dbrecs[0]["name"], name.rstrip("."))
 
     def test_create_zone_with_nameservers_non_string(self):
         # ensure we don't crash
         name = unique_zone_name()
         payload = {
-            'name': name,
-            'kind': 'Native',
-            'nameservers': [{'a': 'ns1.example.com'}]  # invalid
+            "name": name,
+            "kind": "Native",
+            "nameservers": [{"a": "ns1.example.com"}],  # invalid
         }
         print(payload)
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
 
     def test_create_zone_with_dnssec(self):
@@ -665,12 +710,12 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
 
         self.get_zone(name)
 
-        for k in ('dnssec', ):
+        for k in ("dnssec",):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
 
-        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name + '/cryptokeys'))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name + "/cryptokeys"))
 
         keys = r.json()
 
@@ -678,9 +723,9 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
 
         self.assertEqual(r.status_code, 200)
         self.assertEqual(len(keys), 1)
-        self.assertEqual(keys[0]['type'], 'Cryptokey')
-        self.assertEqual(keys[0]['active'], True)
-        self.assertEqual(keys[0]['keytype'], 'csk')
+        self.assertEqual(keys[0]["type"], "Cryptokey")
+        self.assertEqual(keys[0]["active"], True)
+        self.assertEqual(keys[0]["keytype"], "csk")
 
     def test_create_zone_with_dnssec_disable_dnssec(self):
         """
@@ -689,12 +734,12 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
         """
         name, payload, data = self.create_zone(dnssec=True)
 
-        self.put_zone(name, {'dnssec': False})
+        self.put_zone(name, {"dnssec": False})
 
         zoneinfo = self.get_zone(name)
-        self.assertEqual(zoneinfo['dnssec'], False)
+        self.assertEqual(zoneinfo["dnssec"], False)
 
-        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name + '/cryptokeys'))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name + "/cryptokeys"))
 
         keys = r.json()
 
@@ -705,77 +750,75 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
         """
         Create a zone with "nsec3param" set and see if the metadata was added.
         """
-        nsec3param = '1 0 100 aabbccddeeff'
+        nsec3param = "1 0 100 aabbccddeeff"
         name, payload, data = self.create_zone(dnssec=True, nsec3param=nsec3param)
 
         self.get_zone(name)
 
-        for k in ('dnssec', 'nsec3param'):
+        for k in ("dnssec", "nsec3param"):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
 
-        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name + '/metadata/NSEC3PARAM'))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name + "/metadata/NSEC3PARAM"))
 
         data = r.json()
 
         print(data)
 
         self.assertEqual(r.status_code, 200)
-        self.assertEqual(len(data['metadata']), 1)
-        self.assertEqual(data['kind'], 'NSEC3PARAM')
-        self.assertEqual(data['metadata'][0], nsec3param)
+        self.assertEqual(len(data["metadata"]), 1)
+        self.assertEqual(data["kind"], "NSEC3PARAM")
+        self.assertEqual(data["metadata"][0], nsec3param)
 
     def test_create_zone_with_nsec3narrow(self):
         """
         Create a zone with "nsec3narrow" set and see if the metadata was added.
         """
-        nsec3param = '1 0 100 aabbccddeeff'
-        name, payload, data = self.create_zone(dnssec=True, nsec3param=nsec3param,
-                                               nsec3narrow=True)
+        nsec3param = "1 0 100 aabbccddeeff"
+        name, payload, data = self.create_zone(dnssec=True, nsec3param=nsec3param, nsec3narrow=True)
 
         self.get_zone(name)
 
-        for k in ('dnssec', 'nsec3param', 'nsec3narrow'):
+        for k in ("dnssec", "nsec3param", "nsec3narrow"):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
 
-        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name + '/metadata/NSEC3NARROW'))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name + "/metadata/NSEC3NARROW"))
 
         data = r.json()
 
         print(data)
 
         self.assertEqual(r.status_code, 200)
-        self.assertEqual(len(data['metadata']), 1)
-        self.assertEqual(data['kind'], 'NSEC3NARROW')
-        self.assertEqual(data['metadata'][0], '1')
+        self.assertEqual(len(data["metadata"]), 1)
+        self.assertEqual(data["kind"], "NSEC3NARROW")
+        self.assertEqual(data["metadata"][0], "1")
 
     def test_create_zone_with_nsec3param_switch_to_nsec(self):
         """
         Create a zone with "nsec3param", then remove the params
         """
-        name, payload, data = self.create_zone(dnssec=True,
-                                               nsec3param='1 0 1 ab')
-        self.put_zone(name, {'nsec3param': ''})
+        name, payload, data = self.create_zone(dnssec=True, nsec3param="1 0 1 ab")
+        self.put_zone(name, {"nsec3param": ""})
 
         data = self.get_zone(name)
-        self.assertEqual(data['nsec3param'], '')
+        self.assertEqual(data["nsec3param"], "")
 
     def test_create_zone_without_dnssec_unset_nsec3parm(self):
         """
         Create a non dnssec zone and set an empty "nsec3param"
         """
         name, payload, data = self.create_zone(dnssec=False)
-        self.put_zone(name, {'nsec3param': ''})
+        self.put_zone(name, {"nsec3param": ""})
 
     def test_create_zone_without_dnssec_set_nsec3parm(self):
         """
         Create a non dnssec zone and set "nsec3param"
         """
         name, payload, data = self.create_zone(dnssec=False)
-        self.put_zone(name, {'nsec3param': '1 0 1 ab'}, expect_error=True)
+        self.put_zone(name, {"nsec3param": "1 0 1 ab"}, expect_error=True)
 
     def test_create_zone_dnssec_serial(self):
         """
@@ -783,42 +826,45 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
         after every step
         """
         # Use soa_edit_api='DEFAULT' to get predictable INCEPTION-INCREMENT serials
-        name, payload, data = self.create_zone(soa_edit_api='DEFAULT')
+        name, payload, data = self.create_zone(soa_edit_api="DEFAULT")
 
-        soa_serial = get_first_rec(data, name, 'SOA')['content'].split(' ')[2]
-        self.assertEqual(soa_serial[-2:], '01')
+        soa_serial = get_first_rec(data, name, "SOA")["content"].split(" ")[2]
+        self.assertEqual(soa_serial[-2:], "01")
 
-        self.put_zone(name, {'dnssec': True})
+        self.put_zone(name, {"dnssec": True})
 
         data = self.get_zone(name)
-        soa_serial = get_first_rec(data, name, 'SOA')['content'].split(' ')[2]
-        self.assertEqual(soa_serial[-2:], '02')
+        soa_serial = get_first_rec(data, name, "SOA")["content"].split(" ")[2]
+        self.assertEqual(soa_serial[-2:], "02")
 
-        self.put_zone(name, {'dnssec': False})
+        self.put_zone(name, {"dnssec": False})
 
         data = self.get_zone(name)
-        soa_serial = get_first_rec(data, name, 'SOA')['content'].split(' ')[2]
-        self.assertEqual(soa_serial[-2:], '03')
+        soa_serial = get_first_rec(data, name, "SOA")["content"].split(" ")[2]
+        self.assertEqual(soa_serial[-2:], "03")
 
     def test_zone_absolute_url(self):
         self.create_zone()
         r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         rdata = r.json()
         print(rdata[0])
-        self.assertTrue(rdata[0]['url'].startswith('/api/v'))
+        self.assertTrue(rdata[0]["url"].startswith("/api/v"))
 
     def test_create_zone_metadata(self):
         payload_metadata = {"type": "Metadata", "kind": "AXFR-SOURCE", "metadata": ["127.0.0.2"]}
-        r = self.session.post(self.url("/api/v1/servers/localhost/zones/example.com/metadata"),
-                              data=json.dumps(payload_metadata))
+        r = self.session.post(
+            self.url("/api/v1/servers/localhost/zones/example.com/metadata"), data=json.dumps(payload_metadata)
+        )
         rdata = r.json()
         self.assertEqual(r.status_code, 201)
         self.assertEqual(rdata["metadata"], payload_metadata["metadata"])
 
     def test_create_zone_metadata_kind(self):
         payload_metadata = {"metadata": ["127.0.0.2"]}
-        r = self.session.put(self.url("/api/v1/servers/localhost/zones/example.com/metadata/AXFR-SOURCE"),
-                             data=json.dumps(payload_metadata))
+        r = self.session.put(
+            self.url("/api/v1/servers/localhost/zones/example.com/metadata/AXFR-SOURCE"),
+            data=json.dumps(payload_metadata),
+        )
         rdata = r.json()
         self.assertEqual(r.status_code, 200)
         self.assertEqual(rdata["metadata"], payload_metadata["metadata"])
@@ -827,14 +873,16 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
         # test whether it prevents modification of certain kinds
         for k in ("NSEC3NARROW", "NSEC3PARAM", "PRESIGNED", "LUA-AXFR-SCRIPT"):
             payload = {"metadata": ["FOO", "BAR"]}
-            r = self.session.put(self.url("/api/v1/servers/localhost/zones/example.com/metadata/%s" % k),
-                                 data=json.dumps(payload))
+            r = self.session.put(
+                self.url("/api/v1/servers/localhost/zones/example.com/metadata/%s" % k), data=json.dumps(payload)
+            )
             self.assertEqual(r.status_code, 422)
 
     def test_retrieve_zone_metadata(self):
         payload_metadata = {"type": "Metadata", "kind": "AXFR-SOURCE", "metadata": ["127.0.0.2"]}
-        self.session.post(self.url("/api/v1/servers/localhost/zones/example.com/metadata"),
-                          data=json.dumps(payload_metadata))
+        self.session.post(
+            self.url("/api/v1/servers/localhost/zones/example.com/metadata"), data=json.dumps(payload_metadata)
+        )
         r = self.session.get(self.url("/api/v1/servers/localhost/zones/example.com/metadata"))
         rdata = r.json()
         self.assertEqual(r.status_code, 200)
@@ -850,24 +898,27 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
 
     def test_create_external_zone_metadata(self):
         payload_metadata = {"metadata": ["My very important message"]}
-        r = self.session.put(self.url("/api/v1/servers/localhost/zones/example.com/metadata/X-MYMETA"),
-                             data=json.dumps(payload_metadata))
+        r = self.session.put(
+            self.url("/api/v1/servers/localhost/zones/example.com/metadata/X-MYMETA"), data=json.dumps(payload_metadata)
+        )
         self.assertEqual(r.status_code, 200)
         rdata = r.json()
         self.assertEqual(rdata["metadata"], payload_metadata["metadata"])
 
     def test_create_metadata_in_non_existent_zone(self):
         payload_metadata = {"type": "Metadata", "kind": "AXFR-SOURCE", "metadata": ["127.0.0.2"]}
-        r = self.session.post(self.url("/api/v1/servers/localhost/zones/idonotexist.123.456.example./metadata"),
-                              data=json.dumps(payload_metadata))
+        r = self.session.post(
+            self.url("/api/v1/servers/localhost/zones/idonotexist.123.456.example./metadata"),
+            data=json.dumps(payload_metadata),
+        )
         self.assertEqual(r.status_code, 404)
         # Note: errors should probably contain json (see #5988)
         # self.assert_in_json_error('Could not find domain ', r.json())
 
     def test_create_slave_zone(self):
         # Test that nameservers can be absent for slave zones.
-        name, payload, data = self.create_zone(kind='Slave', nameservers=None, masters=['127.0.0.2'])
-        for k in ('name', 'masters', 'kind'):
+        name, payload, data = self.create_zone(kind="Slave", nameservers=None, masters=["127.0.0.2"])
+        for k in ("name", "masters", "kind"):
             self.assertIn(k, data)
             self.assertEqual(data[k], payload[k])
         print("payload:", payload)
@@ -876,96 +927,106 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
         r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         zonelist = r.json()
         print("zonelist:", zonelist)
-        self.assertIn(payload['name'], [zone['name'] for zone in zonelist])
+        self.assertIn(payload["name"], [zone["name"] for zone in zonelist])
         # Also test that fetching the zone works.
-        data = self.get_zone(data['id'])
+        data = self.get_zone(data["id"])
         print("zone (fetched):", data)
-        for k in ('name', 'masters', 'kind'):
+        for k in ("name", "masters", "kind"):
             self.assertIn(k, data)
             self.assertEqual(data[k], payload[k])
-        self.assertEqual(data['serial'], 0)
-        self.assertEqual(data['rrsets'], [])
+        self.assertEqual(data["serial"], 0)
+        self.assertEqual(data["rrsets"], [])
 
     def test_create_consumer_zone(self):
         # Test that nameservers can be absent for consumer zones.
-        _, payload, data = self.create_zone(kind='Consumer', nameservers=None, masters=['127.0.0.2'])
+        _, payload, data = self.create_zone(kind="Consumer", nameservers=None, masters=["127.0.0.2"])
         print("payload:", payload)
         print("data:", data)
         # Because consumer zones don't get a SOA, we need to test that they'll show up in the zone list.
         r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         zonelist = r.json()
         print("zonelist:", zonelist)
-        self.assertIn(payload['name'], [zone['name'] for zone in zonelist])
+        self.assertIn(payload["name"], [zone["name"] for zone in zonelist])
         # Also test that fetching the zone works.
-        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + data['id']))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + data["id"]))
         data = r.json()
         print("zone (fetched):", data)
-        for k in ('name', 'masters', 'kind'):
+        for k in ("name", "masters", "kind"):
             self.assertIn(k, data)
             self.assertEqual(data[k], payload[k])
-        self.assertEqual(data['serial'], 0)
-        self.assertEqual(data['rrsets'], [])
+        self.assertEqual(data["serial"], 0)
+        self.assertEqual(data["rrsets"], [])
 
     def test_create_consumer_zone_no_nameservers(self):
         """nameservers must be absent for Consumer zones"""
-        self.create_zone(kind="Consumer", nameservers=["127.0.0.1"], expect_error="Nameservers MUST NOT be given for Consumer zones")
+        self.create_zone(
+            kind="Consumer", nameservers=["127.0.0.1"], expect_error="Nameservers MUST NOT be given for Consumer zones"
+        )
 
     def test_create_consumer_zone_no_rrsets(self):
         """rrsets must be absent for Consumer zones"""
-        rrsets = [{
-            "name": "$NAME$",
-            "type": "SOA",
-            "ttl": 3600,
-            "records": [{
-                "content": "ns1.example.net. testmaster@example.net. 10 10800 3600 604800 3600",
-                "disabled": False,
-            }],
-        }]
-        self.create_zone(kind="Consumer", nameservers=None, rrsets=rrsets, expect_error="Zone data MUST NOT be given for Consumer zones")
+        rrsets = [
+            {
+                "name": "$NAME$",
+                "type": "SOA",
+                "ttl": 3600,
+                "records": [
+                    {
+                        "content": "ns1.example.net. testmaster@example.net. 10 10800 3600 604800 3600",
+                        "disabled": False,
+                    }
+                ],
+            }
+        ]
+        self.create_zone(
+            kind="Consumer",
+            nameservers=None,
+            rrsets=rrsets,
+            expect_error="Zone data MUST NOT be given for Consumer zones",
+        )
 
     def test_find_zone_by_name(self):
-        name = 'foo/' + unique_zone_name()
+        name = "foo/" + unique_zone_name()
         name, payload, data = self.create_zone(name=name)
         r = self.session.get(self.url("/api/v1/servers/localhost/zones?zone=" + name))
         data = r.json()
         print(data)
-        self.assertEqual(data[0]['name'], name)
+        self.assertEqual(data[0]["name"], name)
 
     def test_delete_slave_zone(self):
-        name, payload, data = self.create_zone(kind='Slave', nameservers=None, masters=['127.0.0.2'])
-        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + data['id']))
+        name, payload, data = self.create_zone(kind="Slave", nameservers=None, masters=["127.0.0.2"])
+        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + data["id"]))
         r.raise_for_status()
 
     def test_delete_consumer_zone(self):
-        name, payload, data = self.create_zone(kind='Consumer', nameservers=None, masters=['127.0.0.2'])
-        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + data['id']))
+        name, payload, data = self.create_zone(kind="Consumer", nameservers=None, masters=["127.0.0.2"])
+        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + data["id"]))
         r.raise_for_status()
 
     def test_retrieve_slave_zone(self):
-        name, payload, data = self.create_zone(kind='Slave', nameservers=None, masters=['127.0.0.2'])
+        name, payload, data = self.create_zone(kind="Slave", nameservers=None, masters=["127.0.0.2"])
         print("payload:", payload)
         print("data:", data)
-        r = self.session.put(self.url("/api/v1/servers/localhost/zones/" + data['id'] + "/axfr-retrieve"))
+        r = self.session.put(self.url("/api/v1/servers/localhost/zones/" + data["id"] + "/axfr-retrieve"))
         data = r.json()
         print("status for axfr-retrieve:", data)
-        self.assertEqual(data['result'], u'Added retrieval request for \'' + payload['name'] +
-                         '\' from primary 127.0.0.2')
+        self.assertEqual(data["result"], "Added retrieval request for '" + payload["name"] + "' from primary 127.0.0.2")
 
     def test_notify_master_zone(self):
-        name, payload, data = self.create_zone(kind='Master')
+        name, payload, data = self.create_zone(kind="Master")
         print("payload:", payload)
         print("data:", data)
-        r = self.session.put(self.url("/api/v1/servers/localhost/zones/" + data['id'] + "/notify"))
+        r = self.session.put(self.url("/api/v1/servers/localhost/zones/" + data["id"] + "/notify"))
         data = r.json()
         print("status for notify:", data)
-        self.assertEqual(data['result'], 'Notification queued')
+        self.assertEqual(data["result"], "Notification queued")
 
     def test_get_zone_with_symbols(self):
-        name, payload, data = self.create_zone(name='foo/bar.'+unique_zone_name())
-        name = payload['name']
-        zone_id = (name.replace('/', '=2F'))
+        name, payload, data = self.create_zone(name="foo/bar." + unique_zone_name())
+        name = payload["name"]
+        zone_id = name.replace("/", "=2F")
         data = self.get_zone(zone_id)
-        for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'dnssec'):
+        for k in ("id", "url", "name", "masters", "kind", "last_check", "notified_serial", "serial", "dnssec"):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
@@ -973,147 +1034,121 @@ class AuthZones(ZonesApiTestCase, AuthZonesHelperMixin):
     def test_get_zone(self):
         r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         domains = r.json()
-        example_com = [domain for domain in domains if domain['name'] == u'example.com.'][0]
-        data = self.get_zone(example_com['id'])
-        for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial'):
+        example_com = [domain for domain in domains if domain["name"] == "example.com."][0]
+        data = self.get_zone(example_com["id"])
+        for k in ("id", "url", "name", "masters", "kind", "last_check", "notified_serial", "serial"):
             self.assertIn(k, data)
-        self.assertEqual(data['name'], 'example.com.')
+        self.assertEqual(data["name"], "example.com.")
 
     def test_get_zone_rrset(self):
-        name = 'host-18000.example.com.'
+        name = "host-18000.example.com."
         r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         domains = r.json()
-        example_com = [domain for domain in domains if domain['name'] == u'example.com.'][0]
+        example_com = [domain for domain in domains if domain["name"] == "example.com."][0]
 
         # verify single record from name that has a single record
-        data = self.get_zone(example_com['id'], rrset_name="host-18000.example.com.")
-        for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'rrsets'):
+        data = self.get_zone(example_com["id"], rrset_name="host-18000.example.com.")
+        for k in ("id", "url", "name", "masters", "kind", "last_check", "notified_serial", "serial", "rrsets"):
             self.assertIn(k, data)
-        received_rrsets = data['rrsets']
+        received_rrsets = data["rrsets"]
         for rrset in received_rrsets:
-            remove_timestamp(rrset['records'])
-        self.assertEqual(received_rrsets,
+            remove_timestamp(rrset["records"])
+        self.assertEqual(
+            received_rrsets,
             [
                 {
-                    'comments': [],
-                    'name': name,
-                    'records':
-                    [
-                        {
-                            'content': '192.168.1.80',
-                            'disabled': False
-                        }
-                    ],
-                    'ttl': 120,
-                    'type': 'A'
+                    "comments": [],
+                    "name": name,
+                    "records": [{"content": "192.168.1.80", "disabled": False}],
+                    "ttl": 120,
+                    "type": "A",
                 }
-            ]
+            ],
         )
 
         # disable previous record
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'A',
-            'ttl': 120,
-            'records':
-            [
-                {
-                    'content': '192.168.1.80',
-                    'disabled': True
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "A",
+            "ttl": 120,
+            "records": [{"content": "192.168.1.80", "disabled": True}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/example.com"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
 
         # verify that the changed record is not found when asking for
         # disabled records not to be included
-        data = self.get_zone(example_com['id'], rrset_name="host-18000.example.com.", include_disabled="false")
-        self.assertEqual(len(data['rrsets']), 0)
+        data = self.get_zone(example_com["id"], rrset_name="host-18000.example.com.", include_disabled="false")
+        self.assertEqual(len(data["rrsets"]), 0)
 
         # verify that the changed record is found when explicitly asking for
         # disabled records, and by default.
-        data = self.get_zone(example_com['id'], rrset_name="host-18000.example.com.", include_disabled="true")
-        self.assertEqual(get_rrset(data, name, 'A')['records'], rrset['records'])
-        data = self.get_zone(example_com['id'], rrset_name="host-18000.example.com.")
-        self.assertEqual(get_rrset(data, name, 'A')['records'], rrset['records'])
+        data = self.get_zone(example_com["id"], rrset_name="host-18000.example.com.", include_disabled="true")
+        self.assertEqual(get_rrset(data, name, "A")["records"], rrset["records"])
+        data = self.get_zone(example_com["id"], rrset_name="host-18000.example.com.")
+        self.assertEqual(get_rrset(data, name, "A")["records"], rrset["records"])
 
         # verify two RRsets from a name that has two types with one record each
-        powerdnssec_org = [domain for domain in domains if domain['name'] == u'powerdnssec.org.'][0]
-        data = self.get_zone(powerdnssec_org['id'], rrset_name="localhost.powerdnssec.org.")
-        for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'rrsets'):
+        powerdnssec_org = [domain for domain in domains if domain["name"] == "powerdnssec.org."][0]
+        data = self.get_zone(powerdnssec_org["id"], rrset_name="localhost.powerdnssec.org.")
+        for k in ("id", "url", "name", "masters", "kind", "last_check", "notified_serial", "serial", "rrsets"):
             self.assertIn(k, data)
-        received_rrsets = data['rrsets']
+        received_rrsets = data["rrsets"]
         for rrset in received_rrsets:
-            remove_timestamp(rrset['records'])
-        self.assertEqual(sorted(received_rrsets, key=operator.itemgetter('type')),
+            remove_timestamp(rrset["records"])
+        self.assertEqual(
+            sorted(received_rrsets, key=operator.itemgetter("type")),
             [
                 {
-                    'comments': [],
-                    'name': 'localhost.powerdnssec.org.',
-                    'records':
-                    [
-                        {
-                            'content': '127.0.0.1',
-                            'disabled': False
-                        }
-                    ],
-                    'ttl': 3600,
-                    'type': 'A'
+                    "comments": [],
+                    "name": "localhost.powerdnssec.org.",
+                    "records": [{"content": "127.0.0.1", "disabled": False}],
+                    "ttl": 3600,
+                    "type": "A",
                 },
                 {
-                    'comments': [],
-                    'name': 'localhost.powerdnssec.org.',
-                    'records':
-                    [
-                        {
-                            'content': '::1',
-                            'disabled': False
-                        }
-                    ],
-                    'ttl': 3600,
-                    'type': 'AAAA'
+                    "comments": [],
+                    "name": "localhost.powerdnssec.org.",
+                    "records": [{"content": "::1", "disabled": False}],
+                    "ttl": 3600,
+                    "type": "AAAA",
                 },
-            ]
+            ],
         )
 
         # verify one RRset with one record from a name that has two, then filtered by type
-        data = self.get_zone(powerdnssec_org['id'], rrset_name="localhost.powerdnssec.org.", rrset_type="AAAA")
-        for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'rrsets'):
+        data = self.get_zone(powerdnssec_org["id"], rrset_name="localhost.powerdnssec.org.", rrset_type="AAAA")
+        for k in ("id", "url", "name", "masters", "kind", "last_check", "notified_serial", "serial", "rrsets"):
             self.assertIn(k, data)
-        received_rrsets = data['rrsets']
+        received_rrsets = data["rrsets"]
         for rrset in received_rrsets:
-            remove_timestamp(rrset['records'])
-        self.assertEqual(received_rrsets,
+            remove_timestamp(rrset["records"])
+        self.assertEqual(
+            received_rrsets,
             [
                 {
-                    'comments': [],
-                    'name': 'localhost.powerdnssec.org.',
-                    'records':
-                    [
-                        {
-                            'content': '::1',
-                            'disabled': False
-                        }
-                    ],
-                    'ttl': 3600,
-                    'type': 'AAAA'
+                    "comments": [],
+                    "name": "localhost.powerdnssec.org.",
+                    "records": [{"content": "::1", "disabled": False}],
+                    "ttl": 3600,
+                    "type": "AAAA",
                 }
-            ]
+            ],
         )
 
     def test_import_zone_broken(self):
         payload = {
-            'name': 'powerdns-broken.com',
-            'kind': 'Master',
-            'nameservers': [],
+            "name": "powerdns-broken.com",
+            "kind": "Master",
+            "nameservers": [],
         }
-        payload['zone'] = """
+        payload["zone"] = """
 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58571
 flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
 ;; WARNING: recursion requested but not available
@@ -1135,37 +1170,39 @@ powerdns-broken.com.           86400   IN      SOA     powerdnssec1.ds9a.nl. ahu
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
 
     def test_import_zone_axfr_outofzone(self):
         # Ensure we don't create out-of-zone records
         payload = {
-            'name': unique_zone_name(),
-            'kind': 'Master',
-            'nameservers': [],
+            "name": unique_zone_name(),
+            "kind": "Master",
+            "nameservers": [],
         }
-        payload['zone'] = """
+        payload["zone"] = """
 %NAME%           86400   IN      SOA     powerdnssec1.ds9a.nl. ahu.ds9a.nl. 1343746984 10800 3600 604800 10800
 %NAME%           3600    IN      NS      powerdnssec2.ds9a.nl.
 example.org.   3600    IN      AAAA    2001:888:2000:1d::2
 %NAME%           86400   IN      SOA     powerdnssec1.ds9a.nl. ahu.ds9a.nl. 1343746984 10800 3600 604800 10800
-""".replace('%NAME%', payload['name'])
+""".replace("%NAME%", payload["name"])
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('RRset example.org. IN AAAA: Name is out of zone', r.json())
+        self.assert_in_json_error("RRset example.org. IN AAAA: Name is out of zone", r.json())
 
     def test_import_zone_axfr(self):
         payload = {
-            'name': 'powerdns.com.',
-            'kind': 'Master',
-            'nameservers': [],
-            'soa_edit_api': '',  # turn off so exact SOA comparison works.
+            "name": "powerdns.com.",
+            "kind": "Master",
+            "nameservers": [],
+            "soa_edit_api": "",  # turn off so exact SOA comparison works.
         }
-        payload['zone'] = """
+        payload["zone"] = """
 ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58571
 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
 ;; WARNING: recursion requested but not available
@@ -1187,46 +1224,47 @@ powerdns.com.           86400   IN      SOA     powerdnssec1.ds9a.nl. ahu.ds9a.n
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success_json(r)
         data = r.json()
-        self.assertIn('name', data)
+        self.assertIn("name", data)
 
         expected = {
-            'NS': [
-                {'content': 'powerdnssec1.ds9a.nl.'},
-                {'content': 'powerdnssec2.ds9a.nl.'},
+            "NS": [
+                {"content": "powerdnssec1.ds9a.nl."},
+                {"content": "powerdnssec2.ds9a.nl."},
             ],
-            'SOA': [
-                {'content': 'powerdnssec1.ds9a.nl. ahu.ds9a.nl. 1343746984 10800 3600 604800 10800'},
+            "SOA": [
+                {"content": "powerdnssec1.ds9a.nl. ahu.ds9a.nl. 1343746984 10800 3600 604800 10800"},
             ],
-            'MX': [
-                {'content': '0 xs.powerdns.com.'},
+            "MX": [
+                {"content": "0 xs.powerdns.com."},
             ],
-            'A': [
-                {'content': '82.94.213.34', 'name': 'powerdns.com.'},
+            "A": [
+                {"content": "82.94.213.34", "name": "powerdns.com."},
             ],
-            'AAAA': [
-                {'content': '2001:888:2000:1d::2', 'name': 'powerdns.com.'},
+            "AAAA": [
+                {"content": "2001:888:2000:1d::2", "name": "powerdns.com."},
             ],
         }
 
-        eq_zone_rrsets(data['rrsets'], expected)
+        eq_zone_rrsets(data["rrsets"], expected)
 
         if not is_auth_lmdb():
             # check content in DB is stored WITHOUT trailing dot.
-            dbrecs = get_db_records(payload['name'], 'NS')
-            dbrec = next((dbrec for dbrec in dbrecs if dbrec['content'].startswith('powerdnssec1')))
-            self.assertEqual(dbrec['content'], 'powerdnssec1.ds9a.nl')
+            dbrecs = get_db_records(payload["name"], "NS")
+            dbrec = next((dbrec for dbrec in dbrecs if dbrec["content"].startswith("powerdnssec1")))
+            self.assertEqual(dbrec["content"], "powerdnssec1.ds9a.nl")
 
     def test_import_zone_bind(self):
         payload = {
-            'name': 'example.org.',
-            'kind': 'Master',
-            'nameservers': [],
-            'soa_edit_api': '',  # turn off so exact SOA comparison works.
+            "name": "example.org.",
+            "kind": "Master",
+            "nameservers": [],
+            "soa_edit_api": "",  # turn off so exact SOA comparison works.
         }
-        payload['zone'] = """
+        payload["zone"] = """
 $TTL    86400 ; 24 hours could have been written as 24h or 1d
 ; $TTL used for all RRs without explicit TTL value
 $ORIGIN example.org.
@@ -1251,70 +1289,76 @@ fred   IN  A      192.168.0.4
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success_json(r)
         data = r.json()
-        self.assertIn('name', data)
+        self.assertIn("name", data)
 
         expected = {
-            'NS': [
-                {'content': 'ns1.example.org.'},
-                {'content': 'ns2.smokeyjoe.com.'},
+            "NS": [
+                {"content": "ns1.example.org."},
+                {"content": "ns2.smokeyjoe.com."},
             ],
-            'SOA': [
-                {'content': 'ns1.example.org. hostmaster.example.org. 2002022401 10800 15 604800 10800'},
+            "SOA": [
+                {"content": "ns1.example.org. hostmaster.example.org. 2002022401 10800 15 604800 10800"},
             ],
-            'MX': [
-                {'content': '10 mail.another.com.'},
+            "MX": [
+                {"content": "10 mail.another.com."},
             ],
-            'A': [
-                {'content': '192.168.0.1', 'name': 'ns1.example.org.'},
-                {'content': '192.168.0.2', 'name': 'www.example.org.'},
-                {'content': '192.168.0.3', 'name': 'bill.example.org.'},
-                {'content': '192.168.0.4', 'name': 'fred.example.org.'},
+            "A": [
+                {"content": "192.168.0.1", "name": "ns1.example.org."},
+                {"content": "192.168.0.2", "name": "www.example.org."},
+                {"content": "192.168.0.3", "name": "bill.example.org."},
+                {"content": "192.168.0.4", "name": "fred.example.org."},
             ],
-            'CNAME': [
-                {'content': 'www.example.org.', 'name': 'ftp.example.org.'},
+            "CNAME": [
+                {"content": "www.example.org.", "name": "ftp.example.org."},
             ],
         }
 
-        eq_zone_rrsets(data['rrsets'], expected)
+        eq_zone_rrsets(data["rrsets"], expected)
 
     def test_import_zone_bind_cname_apex(self):
         payload = {
-            'name': unique_zone_name(),
-            'kind': 'Master',
-            'nameservers': [],
+            "name": unique_zone_name(),
+            "kind": "Master",
+            "nameservers": [],
         }
-        payload['zone'] = """
+        payload["zone"] = """
 $ORIGIN %NAME%
 @ IN SOA   ns1.example.org. hostmaster.example.org. (2002022401 3H 15 1W 3H)
 @ IN NS    ns1.example.org.
 @ IN NS    ns2.smokeyjoe.com.
 @ IN CNAME www.example.org.
-""".replace('%NAME%', payload['name'])
+""".replace("%NAME%", payload["name"])
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('conflicts with existing NS RRset', r.json())
+        self.assert_in_json_error("conflicts with existing NS RRset", r.json())
 
     def test_export_zone_json(self):
-        name, payload, zone = self.create_zone(nameservers=['ns1.foo.com.', 'ns2.foo.com.'], soa_edit_api='')
+        name, payload, zone = self.create_zone(nameservers=["ns1.foo.com.", "ns2.foo.com."], soa_edit_api="")
         # export it
         r = self.session.get(
             self.url("/api/v1/servers/localhost/zones/" + name + "/export"),
-            headers={'accept': 'application/json;q=0.9,*/*;q=0.8'}
+            headers={"accept": "application/json;q=0.9,*/*;q=0.8"},
         )
         self.assert_success_json(r)
         data = r.json()
-        self.assertIn('zone', data)
-        expected_data = [name + '\t3600\tIN\tNS\tns1.foo.com.',
-                         name + '\t3600\tIN\tNS\tns2.foo.com.',
-                         name + '\t3600\tIN\tSOA\ta.misconfigured.dns.server.invalid. hostmaster.' + name +
-                         ' 0 10800 3600 604800 3600']
-        self.assertCountEqual(data['zone'].strip().split('\n'), expected_data)
+        self.assertIn("zone", data)
+        expected_data = [
+            name + "\t3600\tIN\tNS\tns1.foo.com.",
+            name + "\t3600\tIN\tNS\tns2.foo.com.",
+            name
+            + "\t3600\tIN\tSOA\ta.misconfigured.dns.server.invalid. hostmaster."
+            + name
+            + " 0 10800 3600 604800 3600",
+        ]
+        self.assertCountEqual(data["zone"].strip().split("\n"), expected_data)
 
     def test_import_zone_consumer(self):
         zonestring = """
@@ -1326,31 +1370,38 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
                   3h ; minimum
                  )
         """
-        self.create_zone(kind="Consumer", nameservers=[], zone=zonestring, expect_error="Zone data MUST NOT be given for Consumer zones")
+        self.create_zone(
+            kind="Consumer",
+            nameservers=[],
+            zone=zonestring,
+            expect_error="Zone data MUST NOT be given for Consumer zones",
+        )
 
     def test_export_zone_text(self):
-        name, payload, zone = self.create_zone(nameservers=['ns1.foo.com.', 'ns2.foo.com.'], soa_edit_api='')
+        name, payload, zone = self.create_zone(nameservers=["ns1.foo.com.", "ns2.foo.com."], soa_edit_api="")
         # export it
-        r = self.session.get(
-            self.url("/api/v1/servers/localhost/zones/" + name + "/export")
-        )
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name + "/export"))
         data = r.text.strip().split("\n")
-        expected_data = [name + '\t3600\tIN\tNS\tns1.foo.com.',
-                         name + '\t3600\tIN\tNS\tns2.foo.com.',
-                         name + '\t3600\tIN\tSOA\ta.misconfigured.dns.server.invalid. hostmaster.' + name +
-                         ' 0 10800 3600 604800 3600']
+        expected_data = [
+            name + "\t3600\tIN\tNS\tns1.foo.com.",
+            name + "\t3600\tIN\tNS\tns2.foo.com.",
+            name
+            + "\t3600\tIN\tSOA\ta.misconfigured.dns.server.invalid. hostmaster."
+            + name
+            + " 0 10800 3600 604800 3600",
+        ]
         self.assertCountEqual(data, expected_data)
 
     def test_update_zone(self):
         name, payload, zone = self.create_zone()
-        name = payload['name']
+        name = payload["name"]
         # update, set as Master and enable SOA-EDIT-API
         payload = {
-            'kind': 'Master',
-            'masters': ['192.0.2.1', '192.0.2.2'],
-            'catalog': 'catalog.invalid.',
-            'soa_edit_api': 'EPOCH',
-            'soa_edit': 'EPOCH'
+            "kind": "Master",
+            "masters": ["192.0.2.1", "192.0.2.2"],
+            "catalog": "catalog.invalid.",
+            "soa_edit_api": "EPOCH",
+            "soa_edit": "EPOCH",
         }
         self.put_zone(name, payload)
         data = self.get_zone(name)
@@ -1358,12 +1409,7 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
             self.assertIn(k, data)
             self.assertEqual(data[k], payload[k])
         # update, back to Native and empty(off)
-        payload = {
-            'kind': 'Native',
-            'catalog': '',
-            'soa_edit_api': '',
-            'soa_edit': ''
-        }
+        payload = {"kind": "Native", "catalog": "", "soa_edit_api": "", "soa_edit": ""}
         self.put_zone(name, payload)
         data = self.get_zone(name)
         for k in payload.keys():
@@ -1374,39 +1420,31 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
         name, payload, zone = self.create_zone()
         # rrset with incorrect changetype value
         rrset = {
-            'changetype': 'ihavenoideawhatiamdoing',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "127.0.0.1",
-                    "disabled": False
-                }
-            ]
+            "changetype": "ihavenoideawhatiamdoing",
+            "name": "a." + name,
+            "type": "A",
+            "ttl": 3600,
+            "records": [{"content": "127.0.0.1", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
         self.assert_in_json_error("Changetype 'IHAVENOIDEAWHATIAMDOING' is not a valid value", r.json())
 
     def test_zone_rr_bogus_update_2(self):
         name, payload, zone = self.create_zone()
         # extend rrset with no records
-        rrset = {
-            'changetype': 'extend',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600
-        }
-        payload = {'rrsets': [rrset]}
+        rrset = {"changetype": "extend", "name": "a." + name, "type": "A", "ttl": 3600}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
         self.assert_in_json_error("No record provided", r.json())
 
@@ -1414,26 +1452,18 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
         name, payload, zone = self.create_zone()
         # prune rrset with two records
         rrset = {
-            'changetype': 'prune',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "127.0.0.1",
-                    "disabled": False
-                },
-                {
-                    "content": "127.0.0.2",
-                    "disabled": False
-                }
-            ]
+            "changetype": "prune",
+            "name": "a." + name,
+            "type": "A",
+            "ttl": 3600,
+            "records": [{"content": "127.0.0.1", "disabled": False}, {"content": "127.0.0.2", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
         self.assert_in_json_error("Exactly one record should be provided", r.json())
 
@@ -1441,42 +1471,34 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
         name, payload, zone = self.create_zone()
         # rrset with invalid characters which are not processed by parseRFC1035CharString
         rrset = {
-            'changetype': 'replace',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "(127.0.0.1)",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": "a." + name,
+            "type": "A",
+            "ttl": 3600,
+            "records": [{"content": "(127.0.0.1)", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
         self.assert_in_json_error("Invalid character '(' in record content", r.json())
         # rrset with empty contents
         rrset = {
-            'changetype': 'replace',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": "a." + name,
+            "type": "A",
+            "ttl": 3600,
+            "records": [{"content": "", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
         self.assert_in_json_error("missing field at the end of record content ''", r.json())
 
@@ -1484,472 +1506,393 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
         name, payload, zone = self.create_zone()
         # do a replace (= update)
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'ns',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "ns1.bar.com.",
-                    "disabled": False
-                },
-                {
-                    "content": "ns2-disabled.bar.com.",
-                    "disabled": True
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "ns",
+            "ttl": 3600,
+            "records": [
+                {"content": "ns1.bar.com.", "disabled": False},
+                {"content": "ns2-disabled.bar.com.", "disabled": True},
+            ],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that (only) the new record is there
         data = self.get_zone(name)
-        self.assertCountEqual(get_rrset(data, name, 'NS')['records'], rrset['records'])
+        self.assertCountEqual(get_rrset(data, name, "NS")["records"], rrset["records"])
 
     def test_zone_rr_update_lua(self):
         # Important to test with LUA records, as their contents should not be
         # normalized in any way.
         name, payload, zone = self.create_zone()
-        recname = 'lua.' + name
+        recname = "lua." + name
         # do a replace (= update)
         rrset = {
-            'changetype': 'replace',
-            'name': recname,
-            'type': 'LUA',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "TXT \"; return 'PowerDNS'\"",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": recname,
+            "type": "LUA",
+            "ttl": 3600,
+            "records": [{"content": "TXT \"; return 'PowerDNS'\"", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that (only) the new record is there
         data = self.get_zone(name)
-        self.assertEqual(get_rrset(data, recname, 'LUA')['records'], rrset['records'])
+        self.assertEqual(get_rrset(data, recname, "LUA")["records"], rrset["records"])
 
     def test_zone_rr_update_mx(self):
         # Important to test with MX records, as they have a priority field, which must end up in the content field.
         name, payload, zone = self.create_zone()
         # do a replace (= update)
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'MX',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "10 mail.example.org.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "MX",
+            "ttl": 3600,
+            "records": [{"content": "10 mail.example.org.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that (only) the new record is there
         data = self.get_zone(name)
-        self.assertEqual(get_rrset(data, name, 'MX')['records'], rrset['records'])
+        self.assertEqual(get_rrset(data, name, "MX")["records"], rrset["records"])
 
     def test_zone_rr_update_invalid_mx(self):
         name, payload, zone = self.create_zone()
         # do a replace (= update)
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'MX',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "10 mail@mx.example.org.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "MX",
+            "ttl": 3600,
+            "records": [{"content": "10 mail@mx.example.org.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('non-hostname content', r.json())
+        self.assert_in_json_error("non-hostname content", r.json())
         data = self.get_zone(name)
-        self.assertIsNone(get_rrset(data, name, 'MX'))
+        self.assertIsNone(get_rrset(data, name, "MX"))
 
     def test_zone_rr_update_invalid_txt(self):
         name, payload, zone = self.create_zone()
         # do a replace (= update)
         rrset = {
-            'changetype': 'replace',
-            'name': 'ill-formed-txt.' + name,
-            'type': 'txt',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "\"TEST\\1\" \"TEST2\"",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": "ill-formed-txt." + name,
+            "type": "txt",
+            "ttl": 3600,
+            "records": [{"content": '"TEST\\1" "TEST2"', "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assertIn('Not in expected format (parsed as', r.json()['error'])
+        self.assertIn("Not in expected format (parsed as", r.json()["error"])
 
     def test_zone_rr_update_with_escapes(self):
         name, payload, zone = self.create_zone()
         # do a replace (= update)
-        recname = 'well-formed-txt.' + name
-        content = "\"valid\\000record\""
+        recname = "well-formed-txt." + name
+        content = '"valid\\000record"'
         rrset = {
-            'changetype': 'replace',
-            'name': recname,
-            'type': 'txt',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": content,
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": recname,
+            "type": "txt",
+            "ttl": 3600,
+            "records": [{"content": content, "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that the new record has been correctly processed and the \000
         # escape is unchanged
         data = self.get_zone(name)
-        self.assertEqual(get_rrset(data, recname, 'TXT')['records'][0]['content'], content)
+        self.assertEqual(get_rrset(data, recname, "TXT")["records"][0]["content"], content)
 
     def test_zone_rr_update_opt(self):
         name, payload, zone = self.create_zone()
         # do a replace (= update)
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'OPT',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "9",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "OPT",
+            "ttl": 3600,
+            "records": [{"content": "9", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('OPT: invalid type given', r.json())
+        self.assert_in_json_error("OPT: invalid type given", r.json())
 
     def test_zone_rr_update_multiple_rrsets(self):
         name, payload, zone = self.create_zone()
         rrset1 = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'NS',
-            'ttl': 3600,
-            'records': [
-                {
-
-                    "content": "ns9999.example.com.",
-                    "disabled": False
-                }
-            ]
-        }
+            "changetype": "replace",
+            "name": name,
+            "type": "NS",
+            "ttl": 3600,
+            "records": [{"content": "ns9999.example.com.", "disabled": False}],
+        }
         rrset2 = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'MX',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "10 mx444.example.com.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "MX",
+            "ttl": 3600,
+            "records": [{"content": "10 mx444.example.com.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset1, rrset2]}
+        payload = {"rrsets": [rrset1, rrset2]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that all rrsets have been updated
         data = self.get_zone(name)
-        self.assertEqual(get_rrset(data, name, 'NS')['records'], rrset1['records'])
-        self.assertEqual(get_rrset(data, name, 'MX')['records'], rrset2['records'])
+        self.assertEqual(get_rrset(data, name, "NS")["records"], rrset1["records"])
+        self.assertEqual(get_rrset(data, name, "MX")["records"], rrset2["records"])
 
     def test_zone_rr_update_duplicate_record(self):
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'NS',
-            'ttl': 3600,
-            'records': [
+            "changetype": "replace",
+            "name": name,
+            "type": "NS",
+            "ttl": 3600,
+            "records": [
                 {"content": "ns9999.example.com.", "disabled": False},
                 {"content": "ns9996.example.com.", "disabled": False},
                 {"content": "ns9987.example.com.", "disabled": False},
                 {"content": "ns9988.example.com.", "disabled": False},
                 {"content": "ns9999.example.com.", "disabled": False},
-            ]
+            ],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('duplicate record with content', r.json())
+        self.assert_in_json_error("duplicate record with content", r.json())
 
     def test_zone_rr_update_duplicate_rrset(self):
         name, payload, zone = self.create_zone()
         rrset1 = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'NS',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "ns9999.example.com.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "NS",
+            "ttl": 3600,
+            "records": [{"content": "ns9999.example.com.", "disabled": False}],
         }
         rrset2 = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'NS',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "ns9998.example.com.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "NS",
+            "ttl": 3600,
+            "records": [{"content": "ns9998.example.com.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset1, rrset2]}
+        payload = {"rrsets": [rrset1, rrset2]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Duplicate RRset', r.json())
+        self.assert_in_json_error("Duplicate RRset", r.json())
 
     def test_zone_rr_delete(self):
         name, payload, zone = self.create_zone()
         # do a delete of all NS records (these are created with the zone)
-        rrset = {
-            'changetype': 'delete',
-            'name': name,
-            'type': 'NS'
-        }
-        payload = {'rrsets': [rrset]}
+        rrset = {"changetype": "delete", "name": name, "type": "NS"}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that the records are gone
         data = self.get_zone(name)
-        self.assertIsNone(get_rrset(data, name, 'NS'))
+        self.assertIsNone(get_rrset(data, name, "NS"))
 
     def test_zone_rr_update_rrset_combine_replace_and_delete(self):
         name, payload, zone = self.create_zone()
         rrset1 = {
-            'changetype': 'delete',
-            'name': 'sub.' + name,
-            'type': 'CNAME',
+            "changetype": "delete",
+            "name": "sub." + name,
+            "type": "CNAME",
         }
         rrset2 = {
-            'changetype': 'replace',
-            'name': 'sub.' + name,
-            'type': 'CNAME',
-            'ttl': 500,
-            'records': [
-                {
-                    "content": "www.example.org.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": "sub." + name,
+            "type": "CNAME",
+            "ttl": 500,
+            "records": [{"content": "www.example.org.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset1, rrset2]}
+        payload = {"rrsets": [rrset1, rrset2]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that (only) the new record is there
         data = self.get_zone(name)
-        self.assertEqual(get_rrset(data, 'sub.' + name, 'CNAME')['records'], rrset2['records'])
+        self.assertEqual(get_rrset(data, "sub." + name, "CNAME")["records"], rrset2["records"])
 
     def test_zone_rr_update_with_extend(self):
         name, payload, zone = self.create_zone()
         # add a single record with extend
         rrset = {
-            'changetype': 'extend',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "1.2.3.4",
-                    "disabled": False
-                }
-            ]
+            "changetype": "extend",
+            "name": "a." + name,
+            "type": "A",
+            "ttl": 3600,
+            "records": [{"content": "1.2.3.4", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that (only) the new record is there
         data = self.get_zone(name)
-        self.assertEqual(get_rrset(data, 'a.' + name, 'A')['records'], rrset['records'])
+        self.assertEqual(get_rrset(data, "a." + name, "A")["records"], rrset["records"])
         # add the same record again
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that the zone contents did not change
         data2 = self.get_zone(name)
-        self.assertEqual(get_rrset(data, 'a.'+name), get_rrset(data2, 'a.'+name))
+        self.assertEqual(get_rrset(data, "a." + name), get_rrset(data2, "a." + name))
 
     def test_zone_rr_bogus_extend(self):
         name, payload, zone = self.create_zone()
         # add a single record with extend
         rrset = {
-            'changetype': 'extend',
-            'name': 'txt.'+name,
-            'type': 'TXT',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "\"hello\"",
-                    "disabled": False
-                }
-            ]
+            "changetype": "extend",
+            "name": "txt." + name,
+            "type": "TXT",
+            "ttl": 3600,
+            "records": [{"content": '"hello"', "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # try and add another record with a mismatching ttl
         rrset2 = {
-            'changetype': 'extend',
-            'name': 'txt.'+name,
-            'type': 'TXT',
-            'ttl': 1234,
-            'records': [
-                {
-                    "content": "\"hello again\"",
-                    "disabled": False
-                }
-            ]
+            "changetype": "extend",
+            "name": "txt." + name,
+            "type": "TXT",
+            "ttl": 1234,
+            "records": [{"content": '"hello again"', "disabled": False}],
         }
-        payload2 = {'rrsets': [rrset2]}
+        payload2 = {"rrsets": [rrset2]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload2),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('uses a different TTL value than the remainder of the RRset', r.json())
+        self.assert_in_json_error("uses a different TTL value than the remainder of the RRset", r.json())
 
     def test_zone_rr_update_with_prune(self):
         name, payload, zone = self.create_zone()
         # fill a bunch of records
-        a1 = { "content": "1.2.3.4", "disabled": False }
-        a2 = { "content": "2.4.6.8", "disabled": False }
-        a3 = { "content": "3.6.9.12", "disabled": False }
-        a4 = { "content": "4.8.12.16", "disabled": False }
-        rrset = {
-            'changetype': 'replace',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [ a1, a2, a3 ]
-        }
-        payload = {'rrsets': [rrset]}
+        a1 = {"content": "1.2.3.4", "disabled": False}
+        a2 = {"content": "2.4.6.8", "disabled": False}
+        a3 = {"content": "3.6.9.12", "disabled": False}
+        a4 = {"content": "4.8.12.16", "disabled": False}
+        rrset = {"changetype": "replace", "name": "a." + name, "type": "A", "ttl": 3600, "records": [a1, a2, a3]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         data = self.get_zone(name)
-        self.assertEqual(get_rrset(data, 'a.' + name, 'A')['records'], rrset['records'])
+        self.assertEqual(get_rrset(data, "a." + name, "A")["records"], rrset["records"])
         # remove middle record
-        rrset = {
-            'changetype': 'prune',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [ a2 ]
-        }
-        payload = {'rrsets': [rrset]}
+        rrset = {"changetype": "prune", "name": "a." + name, "type": "A", "ttl": 3600, "records": [a2]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify the zone contents
         data1 = self.get_zone(name)
         # note that we can't assume anything about the order of the records
-        records = get_rrset(data1, 'a.' + name, 'A')['records']
+        records = get_rrset(data1, "a." + name, "A")["records"]
         self.assertEqual(len(records), 2)
         self.assertIn(a1, records)
         self.assertIn(a3, records)
         # get_rrset above has removed the timestamps from data1, fetch the
         # zone again, since we want to ensure the following operations do
         # not change anything.
-        if is_auth_lmdb(): # remove test when other backends support record imestamps
+        if is_auth_lmdb():  # remove test when other backends support record imestamps
             data1 = self.get_zone(name)
         # remove middle record again
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify the zone contents are unchanged, with no serial increase
         data2 = self.get_zone(name)
         self.assertEqual(data1, data2)
         # remove nonexisting record
-        rrset = {
-            'changetype': 'prune',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [ a4 ]
-        }
-        payload = {'rrsets': [rrset]}
+        rrset = {"changetype": "prune", "name": "a." + name, "type": "A", "ttl": 3600, "records": [a4]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify the zone contents are still unchanged
         data3 = self.get_zone(name)
@@ -1958,67 +1901,32 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
     def test_zone_rr_update_with_everything(self):
         name, payload, zone = self.create_zone()
         # our heroic records
-        a1 = { "content": "1.2.3.4", "disabled": False }
-        a2 = { "content": "2.4.6.8", "disabled": False }
-        a3 = { "content": "3.6.9.12", "disabled": False }
-        a4 = { "content": "4.8.12.16", "disabled": False }
+        a1 = {"content": "1.2.3.4", "disabled": False}
+        a2 = {"content": "2.4.6.8", "disabled": False}
+        a3 = {"content": "3.6.9.12", "disabled": False}
+        a4 = {"content": "4.8.12.16", "disabled": False}
         # timid record addition
-        rrset1 = {
-            'changetype': 'extend',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [ a1 ]
-        }
+        rrset1 = {"changetype": "extend", "name": "a." + name, "type": "A", "ttl": 3600, "records": [a1]}
         # delete all the things!
-        rrset2 = {
-            'changetype': 'delete',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': []
-        }
+        rrset2 = {"changetype": "delete", "name": "a." + name, "type": "A", "ttl": 3600, "records": []}
         # second half of the rrset
-        rrset3 = {
-            'changetype': 'replace',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [ a3, a4 ]
-        }
+        rrset3 = {"changetype": "replace", "name": "a." + name, "type": "A", "ttl": 3600, "records": [a3, a4]}
         # timid record deletion
-        rrset4 = {
-            'changetype': 'prune',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [ a3 ]
-        }
+        rrset4 = {"changetype": "prune", "name": "a." + name, "type": "A", "ttl": 3600, "records": [a3]}
         # first half of the rrset
-        rrset5 = {
-            'changetype': 'extend',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [ a1 ]
-        }
-        rrset6 = {
-            'changetype': 'extend',
-            'name': 'a.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [ a2 ]
-        }
-        payload = {'rrsets': [rrset1, rrset2, rrset3, rrset4, rrset5, rrset6]}
+        rrset5 = {"changetype": "extend", "name": "a." + name, "type": "A", "ttl": 3600, "records": [a1]}
+        rrset6 = {"changetype": "extend", "name": "a." + name, "type": "A", "ttl": 3600, "records": [a2]}
+        payload = {"rrsets": [rrset1, rrset2, rrset3, rrset4, rrset5, rrset6]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify zone contents
         data = self.get_zone(name)
         # note that we can't assume anything about the order of the records
-        records = get_rrset(data, 'a.' + name, 'A')['records']
+        records = get_rrset(data, "a." + name, "A")["records"]
         self.assertEqual(len(records), 3)
         self.assertIn(a1, records)
         self.assertIn(a2, records)
@@ -2026,457 +1934,439 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
 
     def test_zone_disable_reenable(self):
         # This also tests that SOA-EDIT-API works.
-        name, payload, zone = self.create_zone(soa_edit_api='EPOCH')
+        name, payload, zone = self.create_zone(soa_edit_api="EPOCH")
         # disable zone by disabling SOA
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'SOA',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "ns1.bar.com. hostmaster.foo.org. 1 1 1 1 1",
-                    "disabled": True
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "SOA",
+            "ttl": 3600,
+            "records": [{"content": "ns1.bar.com. hostmaster.foo.org. 1 1 1 1 1", "disabled": True}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # check SOA serial has been edited
         data = self.get_zone(name)
-        soa_serial1 = get_first_rec(data, name, 'SOA')['content'].split()[2]
-        self.assertNotEqual(soa_serial1, '1')
+        soa_serial1 = get_first_rec(data, name, "SOA")["content"].split()[2]
+        self.assertNotEqual(soa_serial1, "1")
         # make sure domain is still in zone list (disabled SOA!)
         r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         domains = r.json()
-        self.assertEqual(len([domain for domain in domains if domain['name'] == name]), 1)
+        self.assertEqual(len([domain for domain in domains if domain["name"] == name]), 1)
         # sleep 1sec to ensure the EPOCH value changes for the next request
         time.sleep(1)
         # verify that modifying it still works
-        rrset['records'][0]['disabled'] = False
-        payload = {'rrsets': [rrset]}
+        rrset["records"][0]["disabled"] = False
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # check SOA serial has been edited again
         data = self.get_zone(name)
-        soa_serial2 = get_first_rec(data, name, 'SOA')['content'].split()[2]
-        self.assertNotEqual(soa_serial2, '1')
+        soa_serial2 = get_first_rec(data, name, "SOA")["content"].split()[2]
+        self.assertNotEqual(soa_serial2, "1")
         self.assertNotEqual(soa_serial2, soa_serial1)
 
     def test_zone_rr_update_out_of_zone(self):
         name, payload, zone = self.create_zone()
         # replace with qname mismatch
         rrset = {
-            'changetype': 'replace',
-            'name': 'not-in-zone.',
-            'type': 'NS',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "ns1.bar.com.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": "not-in-zone.",
+            "type": "NS",
+            "ttl": 3600,
+            "records": [{"content": "ns1.bar.com.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('out of zone', r.json())
+        self.assert_in_json_error("out of zone", r.json())
 
     def test_zone_rr_update_restricted_chars(self):
         name, payload, zone = self.create_zone()
         # replace with qname mismatch
         rrset = {
-            'changetype': 'replace',
-            'name': 'test:' + name,
-            'type': 'NS',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "ns1.bar.com.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": "test:" + name,
+            "type": "NS",
+            "ttl": 3600,
+            "records": [{"content": "ns1.bar.com.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('contains unsupported characters', r.json())
+        self.assert_in_json_error("contains unsupported characters", r.json())
 
     def test_rrset_unknown_type(self):
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'FAFAFAFA', # obviously a FIPv6 address
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "4.3.2.1",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "FAFAFAFA",  # obviously a FIPv6 address
+            "ttl": 3600,
+            "records": [{"content": "4.3.2.1", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('unknown type', r.json())
+        self.assert_in_json_error("unknown type", r.json())
 
-    @parameterized.expand([
-        ('CNAME', ),
-    ])
+    @parameterized.expand(
+        [
+            ("CNAME",),
+        ]
+    )
     def test_rrset_exclusive_and_other(self, qtype):
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': qtype,
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "example.org.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": qtype,
+            "ttl": 3600,
+            "records": [{"content": "example.org.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Conflicts with pre-existing RRset', r.json())
+        self.assert_in_json_error("Conflicts with pre-existing RRset", r.json())
 
-    @parameterized.expand([
-        ('CNAME', ),
-    ])
+    @parameterized.expand(
+        [
+            ("CNAME",),
+        ]
+    )
     def test_rrset_other_and_exclusive(self, qtype):
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': 'sub.'+name,
-            'type': qtype,
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "example.org.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": "sub." + name,
+            "type": qtype,
+            "ttl": 3600,
+            "records": [{"content": "example.org.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         rrset = {
-            'changetype': 'replace',
-            'name': 'sub.'+name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "1.2.3.4",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": "sub." + name,
+            "type": "A",
+            "ttl": 3600,
+            "records": [{"content": "1.2.3.4", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Conflicts with pre-existing RRset', r.json())
-
-    @parameterized.expand([
-        ('', 'SOA', ['ns1.example.org. test@example.org. 10 10800 3600 604800 3600', 'ns2.example.org. test@example.org. 10 10800 3600 604800 3600']),
-        ('sub.', 'CNAME', ['01.example.org.', '02.example.org.']),
-    ])
+        self.assert_in_json_error("Conflicts with pre-existing RRset", r.json())
+
+    @parameterized.expand(
+        [
+            (
+                "",
+                "SOA",
+                [
+                    "ns1.example.org. test@example.org. 10 10800 3600 604800 3600",
+                    "ns2.example.org. test@example.org. 10 10800 3600 604800 3600",
+                ],
+            ),
+            ("sub.", "CNAME", ["01.example.org.", "02.example.org."]),
+        ]
+    )
     def test_rrset_single_qtypes(self, label, qtype, contents):
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': label + name,
-            'type': qtype,
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": contents[0],
-                    "disabled": False
-                },
-                {
-                    "content": contents[1],
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": label + name,
+            "type": qtype,
+            "ttl": 3600,
+            "records": [{"content": contents[0], "disabled": False}, {"content": contents[1], "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('IN ' + qtype + ': only one such record', r.json())
+        self.assert_in_json_error("IN " + qtype + ": only one such record", r.json())
 
     def test_rrset_zone_apex(self):
         name, payload, zone = self.create_zone()
         rrset1 = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'SOA',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": 'ns1.example.org. test@example.org. 10 10800 3600 604800 3600',
-                    "disabled": False
-                },
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "SOA",
+            "ttl": 3600,
+            "records": [
+                {"content": "ns1.example.org. test@example.org. 10 10800 3600 604800 3600", "disabled": False},
+            ],
         }
         rrset2 = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'DNAME',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": 'example.com.',
-                    "disabled": False
-                },
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "DNAME",
+            "ttl": 3600,
+            "records": [
+                {"content": "example.com.", "disabled": False},
+            ],
         }
 
-        payload = {'rrsets': [rrset1, rrset2]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset1, rrset2]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)  # user should be able to create DNAME at APEX as per RFC 6672 section 2.3
 
-    @parameterized.expand([
-        ('SOA', 'ns1.example.org. test@example.org. 10 10800 3600 604800 1800'),
-        ('DNSKEY', '257 3 8 AwEAAb/+pXOZWYQ8mv9WM5dFva8WU9jcIUdDuEjldbyfnkQ/xlrJC5zAEfhYhrea3SmIPmMTDimLqbh3/4SMTNPTUF+9+U1vpNfIRTFadqsmuU9Fddz3JqCcYwEpWbReg6DJOeyu+9oBoIQkPxFyLtIXEPGlQzrynKubn04Cx83I6NfzDTraJT3jLHKeW5PVc1ifqKzHz5TXdHHTA7NkJAa0sPcZCoNE1LpnJI/wcUpRUiuQhoLFeT1E432GuPuZ7y+agElGj0NnBxEgnHrhrnZWUbULpRa/il+Cr5Taj988HqX9Xdm6FjcP4Lbuds/44U7U8du224Q8jTrZ57Yvj4VDQKc='),
-    ])
+    @parameterized.expand(
+        [
+            ("SOA", "ns1.example.org. test@example.org. 10 10800 3600 604800 1800"),
+            (
+                "DNSKEY",
+                "257 3 8 AwEAAb/+pXOZWYQ8mv9WM5dFva8WU9jcIUdDuEjldbyfnkQ/xlrJC5zAEfhYhrea3SmIPmMTDimLqbh3/4SMTNPTUF+9+U1vpNfIRTFadqsmuU9Fddz3JqCcYwEpWbReg6DJOeyu+9oBoIQkPxFyLtIXEPGlQzrynKubn04Cx83I6NfzDTraJT3jLHKeW5PVc1ifqKzHz5TXdHHTA7NkJAa0sPcZCoNE1LpnJI/wcUpRUiuQhoLFeT1E432GuPuZ7y+agElGj0NnBxEgnHrhrnZWUbULpRa/il+Cr5Taj988HqX9Xdm6FjcP4Lbuds/44U7U8du224Q8jTrZ57Yvj4VDQKc=",
+            ),
+        ]
+    )
     def test_only_at_apex(self, qtype, content):
-        name, payload, zone = self.create_zone(soa_edit_api='')
+        name, payload, zone = self.create_zone(soa_edit_api="")
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': qtype,
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": content,
-                    "disabled": False
-                },
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": qtype,
+            "ttl": 3600,
+            "records": [
+                {"content": content, "disabled": False},
+            ],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that the new record is there
         data = self.get_zone(name)
-        self.assertEqual(get_rrset(data, name, qtype)['records'], rrset['records'])
+        self.assertEqual(get_rrset(data, name, qtype)["records"], rrset["records"])
 
         rrset = {
-            'changetype': 'replace',
-            'name': 'sub.' + name,
-            'type': qtype,
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": content,
-                    "disabled": False
-                },
-            ]
+            "changetype": "replace",
+            "name": "sub." + name,
+            "type": qtype,
+            "ttl": 3600,
+            "records": [
+                {"content": content, "disabled": False},
+            ],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('only allowed at apex', r.json())
+        self.assert_in_json_error("only allowed at apex", r.json())
         data = self.get_zone(name)
-        self.assertIsNone(get_rrset(data, 'sub.' + name, qtype))
+        self.assertIsNone(get_rrset(data, "sub." + name, qtype))
 
-    @parameterized.expand([
-        ('DS', '44030 8 2 d4c3d5552b8679faeebc317e5f048b614b2e5f607dc57f1553182d49ab2179f7'),
-    ])
+    @parameterized.expand(
+        [
+            ("DS", "44030 8 2 d4c3d5552b8679faeebc317e5f048b614b2e5f607dc57f1553182d49ab2179f7"),
+        ]
+    )
     def test_not_allowed_at_apex(self, qtype, content):
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': qtype,
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": content,
-                    "disabled": False
-                },
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": qtype,
+            "ttl": 3600,
+            "records": [
+                {"content": content, "disabled": False},
+            ],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('not allowed at apex', r.json())
+        self.assert_in_json_error("not allowed at apex", r.json())
         data = self.get_zone(name)
-        self.assertIsNone(get_rrset(data, 'sub.' + name, qtype))
+        self.assertIsNone(get_rrset(data, "sub." + name, qtype))
 
         rrset = {
-            'changetype': 'replace',
-            'name': 'sub.' + name,
-            'type': qtype,
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": content,
-                    "disabled": False
-                },
-            ]
+            "changetype": "replace",
+            "name": "sub." + name,
+            "type": qtype,
+            "ttl": 3600,
+            "records": [
+                {"content": content, "disabled": False},
+            ],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # verify that the new record is there
         data = self.get_zone(name)
-        self.assertEqual(get_rrset(data, 'sub.' + name, qtype)['records'], rrset['records'])
+        self.assertEqual(get_rrset(data, "sub." + name, qtype)["records"], rrset["records"])
 
     def test_rr_svcb(self):
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': 'svcb.' + name,
-            'type': 'SVCB',
-            'ttl': 3600,
-            'records': [
+            "changetype": "replace",
+            "name": "svcb." + name,
+            "type": "SVCB",
+            "ttl": 3600,
+            "records": [
                 {
                     "content": '40 . mandatory=alpn alpn=h2,h3 ipv4hint=192.0.2.1,192.0.2.2 ech="dG90YWxseSBib2d1cyBlY2hjb25maWcgdmFsdWU="',
-                    "disabled": False
+                    "disabled": False,
                 },
-            ]
+            ],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
 
     def test_rrset_ns_dname_exclude(self):
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': 'delegation.'+name,
-            'type': 'NS',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "ns.example.org.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": "delegation." + name,
+            "type": "NS",
+            "ttl": 3600,
+            "records": [{"content": "ns.example.org.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         rrset = {
-            'changetype': 'replace',
-            'name': 'delegation.'+name,
-            'type': 'DNAME',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "example.com.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": "delegation." + name,
+            "type": "DNAME",
+            "ttl": 3600,
+            "records": [{"content": "example.com.", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('Cannot have both NS and DNAME except in zone apex', r.json())
-
-## FIXME: Enable this when it's time for it
-#    def test_rrset_dname_nothing_under(self):
-#        name, payload, zone = self.create_zone()
-#        rrset = {
-#            'changetype': 'replace',
-#            'name': 'delegation.'+name,
-#            'type': 'DNAME',
-#            'ttl': 3600,
-#            'records': [
-#                {
-#                    "content": "example.com.",
-#                    "disabled": False
-#                }
-#            ]
-#        }
-#        payload = {'rrsets': [rrset]}
-#        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-#                               headers={'content-type': 'application/json'})
-#        self.assert_success(r)
-#        rrset = {
-#            'changetype': 'replace',
-#            'name': 'sub.delegation.'+name,
-#            'type': 'A',
-#            'ttl': 3600,
-#            'records': [
-#                {
-#                    "content": "1.2.3.4",
-#                    "disabled": False
-#                }
-#            ]
-#        }
-#        payload = {'rrsets': [rrset]}
-#        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-#                               headers={'content-type': 'application/json'})
-#        self.assertEqual(r.status_code, 422)
-#        self.assert_in_json_error('You cannot have record(s) under CNAME/DNAME', r.json())
+        self.assert_in_json_error("Cannot have both NS and DNAME except in zone apex", r.json())
+
+    ## FIXME: Enable this when it's time for it
+    #    def test_rrset_dname_nothing_under(self):
+    #        name, payload, zone = self.create_zone()
+    #        rrset = {
+    #            'changetype': 'replace',
+    #            'name': 'delegation.'+name,
+    #            'type': 'DNAME',
+    #            'ttl': 3600,
+    #            'records': [
+    #                {
+    #                    "content": "example.com.",
+    #                    "disabled": False
+    #                }
+    #            ]
+    #        }
+    #        payload = {'rrsets': [rrset]}
+    #        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
+    #                               headers={'content-type': 'application/json'})
+    #        self.assert_success(r)
+    #        rrset = {
+    #            'changetype': 'replace',
+    #            'name': 'sub.delegation.'+name,
+    #            'type': 'A',
+    #            'ttl': 3600,
+    #            'records': [
+    #                {
+    #                    "content": "1.2.3.4",
+    #                    "disabled": False
+    #                }
+    #            ]
+    #        }
+    #        payload = {'rrsets': [rrset]}
+    #        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
+    #                               headers={'content-type': 'application/json'})
+    #        self.assertEqual(r.status_code, 422)
+    #        self.assert_in_json_error('You cannot have record(s) under CNAME/DNAME', r.json())
 
     def test_create_zone_with_leading_space(self):
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'A',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": " 4.3.2.1",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "A",
+            "ttl": 3600,
+            "records": [{"content": " 4.3.2.1", "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
 
     @unittest.skipIf(is_auth_lmdb(), "No out-of-zone storage in LMDB")
     def test_zone_rr_delete_out_of_zone(self):
         name, payload, zone = self.create_zone()
-        rrset = {
-            'changetype': 'delete',
-            'name': 'not-in-zone.',
-            'type': 'NS'
-        }
-        payload = {'rrsets': [rrset]}
+        rrset = {"changetype": "delete", "name": "not-in-zone.", "type": "NS"}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         print(r.content)
         self.assert_success(r)  # succeed so users can fix their wrong, old data
 
@@ -2484,43 +2374,39 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
         name, payload, zone = self.create_zone()
         r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + name))
         self.assertEqual(r.status_code, 204)
-        self.assertNotIn('Content-Type', r.headers)
+        self.assertNotIn("Content-Type", r.headers)
 
     def test_zone_comment_create(self):
         name, payload, zone = self.create_zone()
         rrset1 = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'NS',
-            'ttl': 3600,
-            'comments': [
+            "changetype": "replace",
+            "name": name,
+            "type": "NS",
+            "ttl": 3600,
+            "comments": [
                 {
-                    'account': 'test1',
-                    'content': 'blah blah',
+                    "account": "test1",
+                    "content": "blah blah",
                 },
                 {
-                    'account': 'test2',
-                    'content': 'blah blah bleh',
-                }
-            ]
+                    "account": "test2",
+                    "content": "blah blah bleh",
+                },
+            ],
         }
         rrset2 = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'SOA',
-            'ttl': 3600,
-            'comments': [
-                {
-                    'account': 'test3',
-                    'content': 'this should not show up later'
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "SOA",
+            "ttl": 3600,
+            "comments": [{"account": "test3", "content": "this should not show up later"}],
         }
-        payload = {'rrsets': [rrset1, rrset2]}
+        payload = {"rrsets": [rrset1, rrset2]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         if is_auth_lmdb():
             self.assert_error_json(r)  # No comments in LMDB
             return
@@ -2529,60 +2415,51 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
         # make sure the comments have been set, and that the NS
         # records are still present
         data = self.get_zone(name, rrset_name=name, rrset_type="NS")
-        serverset = get_rrset(data, name, 'NS')
+        serverset = get_rrset(data, name, "NS")
         print(serverset)
-        self.assertNotEqual(serverset['records'], [])
-        self.assertNotEqual(serverset['comments'], [])
+        self.assertNotEqual(serverset["records"], [])
+        self.assertNotEqual(serverset["comments"], [])
         # verify that modified_at has been set by pdns
-        self.assertNotEqual([c for c in serverset['comments']][0]['modified_at'], 0)
+        self.assertNotEqual([c for c in serverset["comments"]][0]["modified_at"], 0)
         # verify that unrelated comments do not leak into the result
-        self.assertEqual(get_rrset(data, name, 'SOA'), None)
+        self.assertEqual(get_rrset(data, name, "SOA"), None)
         # verify that TTL is correct (regression test)
-        self.assertEqual(serverset['ttl'], 3600)
+        self.assertEqual(serverset["ttl"], 3600)
 
     def test_zone_comment_delete(self):
         # Test: Delete ONLY comments.
         name, payload, zone = self.create_zone()
-        rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'NS',
-            'comments': []
-        }
-        payload = {'rrsets': [rrset]}
+        rrset = {"changetype": "replace", "name": name, "type": "NS", "comments": []}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # make sure the NS records are still present
         data = self.get_zone(name)
-        serverset = get_rrset(data, name, 'NS')
+        serverset = get_rrset(data, name, "NS")
         print(serverset)
-        self.assertNotEqual(serverset['records'], [])
-        self.assertEqual(serverset['comments'], [])
+        self.assertNotEqual(serverset["records"], [])
+        self.assertEqual(serverset["comments"], [])
 
     @unittest.skipIf(is_auth_lmdb(), "No comments in LMDB")
     def test_zone_comment_out_of_range_modified_at(self):
         # Test if a modified_at outside of the 32 bit range throws an error
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'NS',
-            'comments': [
-                {
-                    'account': 'test1',
-                    'content': 'oh hi there',
-                    'modified_at': '4294967297'
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "NS",
+            "comments": [{"account": "test1", "content": "oh hi there", "modified_at": "4294967297"}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
         self.assert_in_json_error("Key 'modified_at' is out of range", r.json())
 
@@ -2592,101 +2469,147 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
         name, payload, zone = self.create_zone()
         # create a comment
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'NS',
-            'comments': [
-                {
-                    'account': 'test1',
-                    'content': 'oh hi there',
-                    'modified_at': 1111
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "NS",
+            "comments": [{"account": "test1", "content": "oh hi there", "modified_at": 1111}],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # replace rrset records
         rrset2 = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'NS',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "ns1.bar.com.",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "NS",
+            "ttl": 3600,
+            "records": [{"content": "ns1.bar.com.", "disabled": False}],
         }
-        payload2 = {'rrsets': [rrset2]}
+        payload2 = {"rrsets": [rrset2]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload2),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # make sure the comments still exist
         data = self.get_zone(name)
-        serverset = get_rrset(data, name, 'NS')
+        serverset = get_rrset(data, name, "NS")
         print(serverset)
-        self.assertEqual(serverset['records'], rrset2['records'])
-        self.assertEqual(serverset['comments'], rrset['comments'])
+        self.assertEqual(serverset["records"], rrset2["records"])
+        self.assertEqual(serverset["comments"], rrset["comments"])
 
     def test_search_rr_exact_zone(self):
         name = unique_zone_name()
-        self.create_zone(name=name, serial=22, soa_edit_api='')
-        r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=" + name.rstrip('.')))
+        self.create_zone(name=name, serial=22, soa_edit_api="")
+        r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=" + name.rstrip(".")))
         self.assert_success_json(r)
         json = r.json()
         print(json)
         remove_timestamp(json)
-        self.assertCountEqual(json, [
-            {u'object_type': u'zone', u'name': name, u'zone_id': name},
-            {u'content': u'ns1.example.com.',
-             u'zone_id': name, u'zone': name, u'object_type': u'record', u'disabled': False,
-             u'ttl': 3600, u'type': u'NS', u'name': name},
-            {u'content': u'ns2.example.com.',
-             u'zone_id': name, u'zone': name, u'object_type': u'record', u'disabled': False,
-             u'ttl': 3600, u'type': u'NS', u'name': name},
-            {u'content': u'a.misconfigured.dns.server.invalid. hostmaster.'+name+' 22 10800 3600 604800 3600',
-             u'zone_id': name, u'zone': name, u'object_type': u'record', u'disabled': False,
-             u'ttl': 3600, u'type': u'SOA', u'name': name},
-        ])
+        self.assertCountEqual(
+            json,
+            [
+                {"object_type": "zone", "name": name, "zone_id": name},
+                {
+                    "content": "ns1.example.com.",
+                    "zone_id": name,
+                    "zone": name,
+                    "object_type": "record",
+                    "disabled": False,
+                    "ttl": 3600,
+                    "type": "NS",
+                    "name": name,
+                },
+                {
+                    "content": "ns2.example.com.",
+                    "zone_id": name,
+                    "zone": name,
+                    "object_type": "record",
+                    "disabled": False,
+                    "ttl": 3600,
+                    "type": "NS",
+                    "name": name,
+                },
+                {
+                    "content": "a.misconfigured.dns.server.invalid. hostmaster." + name + " 22 10800 3600 604800 3600",
+                    "zone_id": name,
+                    "zone": name,
+                    "object_type": "record",
+                    "disabled": False,
+                    "ttl": 3600,
+                    "type": "SOA",
+                    "name": name,
+                },
+            ],
+        )
 
     def test_search_rr_exact_zone_filter_type_zone(self):
         name = unique_zone_name()
         data_type = "zone"
-        self.create_zone(name=name, serial=22, soa_edit_api='')
-        r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=" + name.rstrip('.') + "&object_type=" + data_type))
+        self.create_zone(name=name, serial=22, soa_edit_api="")
+        r = self.session.get(
+            self.url("/api/v1/servers/localhost/search-data?q=" + name.rstrip(".") + "&object_type=" + data_type)
+        )
         self.assert_success_json(r)
         print(r.json())
-        self.assertEqual(r.json(), [
-            {u'object_type': u'zone', u'name': name, u'zone_id': name},
-        ])
+        self.assertEqual(
+            r.json(),
+            [
+                {"object_type": "zone", "name": name, "zone_id": name},
+            ],
+        )
 
     def test_search_rr_exact_zone_filter_type_record(self):
         name = unique_zone_name()
         data_type = "record"
-        self.create_zone(name=name, serial=22, soa_edit_api='')
-        r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=" + name.rstrip('.') + "&object_type=" + data_type))
+        self.create_zone(name=name, serial=22, soa_edit_api="")
+        r = self.session.get(
+            self.url("/api/v1/servers/localhost/search-data?q=" + name.rstrip(".") + "&object_type=" + data_type)
+        )
         self.assert_success_json(r)
         json = r.json()
         print(json)
         remove_timestamp(json)
-        self.assertCountEqual(json, [
-            {u'content': u'ns1.example.com.',
-             u'zone_id': name, u'zone': name, u'object_type': u'record', u'disabled': False,
-             u'ttl': 3600, u'type': u'NS', u'name': name},
-            {u'content': u'ns2.example.com.',
-             u'zone_id': name, u'zone': name, u'object_type': u'record', u'disabled': False,
-             u'ttl': 3600, u'type': u'NS', u'name': name},
-            {u'content': u'a.misconfigured.dns.server.invalid. hostmaster.'+name+' 22 10800 3600 604800 3600',
-             u'zone_id': name, u'zone': name, u'object_type': u'record', u'disabled': False,
-             u'ttl': 3600, u'type': u'SOA', u'name': name},
-        ])
+        self.assertCountEqual(
+            json,
+            [
+                {
+                    "content": "ns1.example.com.",
+                    "zone_id": name,
+                    "zone": name,
+                    "object_type": "record",
+                    "disabled": False,
+                    "ttl": 3600,
+                    "type": "NS",
+                    "name": name,
+                },
+                {
+                    "content": "ns2.example.com.",
+                    "zone_id": name,
+                    "zone": name,
+                    "object_type": "record",
+                    "disabled": False,
+                    "ttl": 3600,
+                    "type": "NS",
+                    "name": name,
+                },
+                {
+                    "content": "a.misconfigured.dns.server.invalid. hostmaster." + name + " 22 10800 3600 604800 3600",
+                    "zone_id": name,
+                    "zone": name,
+                    "object_type": "record",
+                    "disabled": False,
+                    "ttl": 3600,
+                    "type": "SOA",
+                    "name": name,
+                },
+            ],
+        )
 
     def test_search_rr_substring(self):
         name = unique_zone_name()
@@ -2699,7 +2622,7 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
         self.assertEqual(len(r.json()), 4)
 
     def test_search_rr_case_insensitive(self):
-        name = unique_zone_name()+'testsuffix.'
+        name = unique_zone_name() + "testsuffix."
         self.create_zone(name=name)
         r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=*testSUFFIX*"))
         self.assert_success_json(r)
@@ -2710,42 +2633,50 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
     @unittest.skipIf(is_auth_lmdb(), "No comments in LMDB")
     def test_search_rr_comment(self):
         name = unique_zone_name()
-        rrsets = [{
-            "name": name,
-            "type": "AAAA",
-            "ttl": 3600,
-            "records": [{
-                "content": "2001:DB8::1",
-                "disabled": False,
-            }],
-            "comments": [{
-                "account": "test AAAA",
-                "content": "blah",
-                "modified_at": 11112,
-            }],
-        }]
+        rrsets = [
+            {
+                "name": name,
+                "type": "AAAA",
+                "ttl": 3600,
+                "records": [
+                    {
+                        "content": "2001:DB8::1",
+                        "disabled": False,
+                    }
+                ],
+                "comments": [
+                    {
+                        "account": "test AAAA",
+                        "content": "blah",
+                        "modified_at": 11112,
+                    }
+                ],
+            }
+        ]
         name, payload, data = self.create_zone(name=name, rrsets=rrsets)
         r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=blah"))
         self.assert_success_json(r)
         data = r.json()
         # should return the AAAA record
         self.assertEqual(len(data), 1)
-        self.assertEqual(data[0]['object_type'], 'comment')
-        self.assertEqual(data[0]['type'], 'AAAA')
-        self.assertEqual(data[0]['name'], name)
-        self.assertEqual(data[0]['content'], rrsets[0]['comments'][0]['content'])
+        self.assertEqual(data[0]["object_type"], "comment")
+        self.assertEqual(data[0]["type"], "AAAA")
+        self.assertEqual(data[0]["name"], name)
+        self.assertEqual(data[0]["content"], rrsets[0]["comments"][0]["content"])
 
     def test_search_after_rectify_with_ent(self):
         name = unique_zone_name()
-        search = name.split('.')[0]
+        search = name.split(".")[0]
         rrset = {
-            "name": 'sub.sub.' + name,
+            "name": "sub.sub." + name,
             "type": "A",
             "ttl": 3600,
-            "records": [{
-                "content": "4.3.2.1",
-                "disabled": False,
-            }],
+            "records": [
+                {
+                    "content": "4.3.2.1",
+                    "disabled": False,
+                }
+            ],
         }
         self.create_zone(name=name, rrsets=[rrset])
         pdnsutil_rectify(name)
@@ -2760,27 +2691,31 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
         name = unique_zone_name()
         rrsets = [
             {
-                "name": 'a.' + name,
+                "name": "a." + name,
                 "type": "AAAA",
                 "ttl": 3600,
-                "records": [{
-                    "content": "2001:DB8::1",
-                    "disabled": False,
-                }],
+                "records": [
+                    {
+                        "content": "2001:DB8::1",
+                        "disabled": False,
+                    }
+                ],
             },
             {
-                "name": 'b.' + name,
+                "name": "b." + name,
                 "type": "AAAA",
                 "ttl": 3600,
-                "records": [{
-                    "content": "2001:DB8::2",
-                    "disabled": False,
-                }],
+                "records": [
+                    {
+                        "content": "2001:DB8::2",
+                        "disabled": False,
+                    }
+                ],
             },
         ]
-        self.create_zone(name=name, rrsets=rrsets, dnssec=True, nsec3param='1 0 1 ab')
-        dbrecs = get_db_records(name, 'AAAA')
-        self.assertIsNotNone(dbrecs[0]['ordername'])
+        self.create_zone(name=name, rrsets=rrsets, dnssec=True, nsec3param="1 0 1 ab")
+        dbrecs = get_db_records(name, "AAAA")
+        self.assertIsNotNone(dbrecs[0]["ordername"])
 
     def test_default_api_rectify_nodnssec(self):
         """Without any DNSSEC settings, rectify should still add ENTs. Setup the zone
@@ -2789,420 +2724,531 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
         name = unique_zone_name()
         rrsets = [
             {
-                "name": 'a.sub.' + name,
+                "name": "a.sub." + name,
                 "type": "AAAA",
                 "ttl": 3600,
-                "records": [{
-                    "content": "2001:DB8::1",
-                    "disabled": False,
-                }],
+                "records": [
+                    {
+                        "content": "2001:DB8::1",
+                        "disabled": False,
+                    }
+                ],
             },
             {
-                "name": 'b.sub.' + name,
+                "name": "b.sub." + name,
                 "type": "AAAA",
                 "ttl": 3600,
-                "records": [{
-                    "content": "2001:DB8::2",
-                    "disabled": False,
-                }],
+                "records": [
+                    {
+                        "content": "2001:DB8::2",
+                        "disabled": False,
+                    }
+                ],
             },
         ]
         self.create_zone(name=name, rrsets=rrsets)
         # default-api-rectify is yes (by default). expect rectify to have happened.
-        assert 'Rcode: 0 ' in sdig('sub.' + name, 'TXT')
+        assert "Rcode: 0 " in sdig("sub." + name, "TXT")
 
     @unittest.skipIf(is_auth_lmdb(), "No get_db_records for LMDB")
     def test_override_api_rectify(self):
         name = unique_zone_name()
         rrsets = [
             {
-                "name": 'a.' + name,
+                "name": "a." + name,
                 "type": "AAAA",
                 "ttl": 3600,
-                "records": [{
-                    "content": "2001:DB8::1",
-                    "disabled": False,
-                }],
+                "records": [
+                    {
+                        "content": "2001:DB8::1",
+                        "disabled": False,
+                    }
+                ],
             },
             {
-                "name": 'b.' + name,
+                "name": "b." + name,
                 "type": "AAAA",
                 "ttl": 3600,
-                "records": [{
-                    "content": "2001:DB8::2",
-                    "disabled": False,
-                }],
+                "records": [
+                    {
+                        "content": "2001:DB8::2",
+                        "disabled": False,
+                    }
+                ],
             },
         ]
-        self.create_zone(name=name, rrsets=rrsets, api_rectify=False, dnssec=True, nsec3param='1 0 1 ab')
-        dbrecs = get_db_records(name, 'AAAA')
-        self.assertIsNone(dbrecs[0]['ordername'])
+        self.create_zone(name=name, rrsets=rrsets, api_rectify=False, dnssec=True, nsec3param="1 0 1 ab")
+        dbrecs = get_db_records(name, "AAAA")
+        self.assertIsNone(dbrecs[0]["ordername"])
 
     @unittest.skipIf(is_auth_lmdb(), "No get_db_records for LMDB")
     def test_explicit_rectify_success(self):
-        name, _, data = self.create_zone = self.create_zone(api_rectify=False, dnssec=True, nsec3param='1 0 1 ab')
-        dbrecs = get_db_records(name, 'SOA')
-        self.assertIsNone(dbrecs[0]['ordername'])
-        r = self.session.put(self.url("/api/v1/servers/localhost/zones/" + data['id'] + "/rectify"))
+        name, _, data = self.create_zone = self.create_zone(api_rectify=False, dnssec=True, nsec3param="1 0 1 ab")
+        dbrecs = get_db_records(name, "SOA")
+        self.assertIsNone(dbrecs[0]["ordername"])
+        r = self.session.put(self.url("/api/v1/servers/localhost/zones/" + data["id"] + "/rectify"))
         self.assertEqual(r.status_code, 200)
-        dbrecs = get_db_records(name, 'SOA')
-        self.assertIsNotNone(dbrecs[0]['ordername'])
+        dbrecs = get_db_records(name, "SOA")
+        self.assertIsNotNone(dbrecs[0]["ordername"])
 
     def test_explicit_rectify_slave(self):
         # Some users want to move a zone to kind=Slave and then rectify, without a re-transfer.
-        name, _, data = self.create_zone = self.create_zone(api_rectify=False, dnssec=True, nsec3param='1 0 1 ab')
-        self.put_zone(data['id'], {'kind': 'Slave'})
-        r = self.session.put(self.url("/api/v1/servers/localhost/zones/" + data['id'] + "/rectify"))
+        name, _, data = self.create_zone = self.create_zone(api_rectify=False, dnssec=True, nsec3param="1 0 1 ab")
+        self.put_zone(data["id"], {"kind": "Slave"})
+        r = self.session.put(self.url("/api/v1/servers/localhost/zones/" + data["id"] + "/rectify"))
         self.assertEqual(r.status_code, 200)
         if not is_auth_lmdb():
-            dbrecs = get_db_records(name, 'SOA')
-            self.assertIsNotNone(dbrecs[0]['ordername'])
+            dbrecs = get_db_records(name, "SOA")
+            self.assertIsNotNone(dbrecs[0]["ordername"])
 
     def test_cname_at_ent_place(self):
         name, payload, zone = self.create_zone(dnssec=True, api_rectify=True)
         rrset = {
-            'changetype': 'replace',
-            'name': 'sub2.sub1.' + name,
-            'type': "A",
-            'ttl': 3600,
-            'records': [{
-                'content': "4.3.2.1",
-                'disabled': False,
-            }],
-        }
-        payload = {'rrsets': [rrset]}
+            "changetype": "replace",
+            "name": "sub2.sub1." + name,
+            "type": "A",
+            "ttl": 3600,
+            "records": [
+                {
+                    "content": "4.3.2.1",
+                    "disabled": False,
+                }
+            ],
+        }
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
-            self.url("/api/v1/servers/localhost/zones/" + zone['id']),
+            self.url("/api/v1/servers/localhost/zones/" + zone["id"]),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
         rrset = {
-            'changetype': 'replace',
-            'name': 'sub1.' + name,
-            'type': "CNAME",
-            'ttl': 3600,
-            'records': [{
-                'content': "www.example.org.",
-                'disabled': False,
-            }],
-        }
-        payload = {'rrsets': [rrset]}
+            "changetype": "replace",
+            "name": "sub1." + name,
+            "type": "CNAME",
+            "ttl": 3600,
+            "records": [
+                {
+                    "content": "www.example.org.",
+                    "disabled": False,
+                }
+            ],
+        }
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
-            self.url("/api/v1/servers/localhost/zones/" + zone['id']),
+            self.url("/api/v1/servers/localhost/zones/" + zone["id"]),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
 
     def test_rrset_parameter_post_false(self):
         name = unique_zone_name()
-        payload = {
-            'name': name,
-            'kind': 'Native',
-            'nameservers': ['ns1.example.com.', 'ns2.example.com.']
-        }
+        payload = {"name": name, "kind": "Native", "nameservers": ["ns1.example.com.", "ns2.example.com."]}
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones?rrsets=false"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         print(r.json())
         self.assert_success_json(r)
         self.assertEqual(r.status_code, 201)
-        self.assertEqual(r.json().get('rrsets'), None)
+        self.assertEqual(r.json().get("rrsets"), None)
 
     def test_rrset_false_parameter(self):
         name = unique_zone_name()
-        self.create_zone(name=name, kind='Native')
+        self.create_zone(name=name, kind="Native")
         data = self.get_zone(name, rrsets="false")
-        self.assertEqual(data.get('rrsets'), None)
+        self.assertEqual(data.get("rrsets"), None)
 
     def test_rrset_true_parameter(self):
         name = unique_zone_name()
-        self.create_zone(name=name, kind='Native')
+        self.create_zone(name=name, kind="Native")
         data = self.get_zone(name, rrsets="true")
-        self.assertEqual(len(data['rrsets']), 2)
+        self.assertEqual(len(data["rrsets"]), 2)
 
     def test_wrong_rrset_parameter(self):
         name = unique_zone_name()
-        self.create_zone(name=name, kind='Native')
-        self.get_zone(
-            name, rrsets="foobar",
-            expect_error="'rrsets' request parameter value 'foobar' is not supported"
-        )
+        self.create_zone(name=name, kind="Native")
+        self.get_zone(name, rrsets="foobar", expect_error="'rrsets' request parameter value 'foobar' is not supported")
 
     def test_put_master_tsig_key_ids_non_existent(self):
         name = unique_zone_name()
-        keyname = unique_zone_name().split('.')[0]
-        self.create_zone(name=name, kind='Native')
-        payload = {
-            'master_tsig_key_ids': [keyname]
-        }
-        self.put_zone(name, payload, expect_error='A TSIG key with the name')
+        keyname = unique_zone_name().split(".")[0]
+        self.create_zone(name=name, kind="Native")
+        payload = {"master_tsig_key_ids": [keyname]}
+        self.put_zone(name, payload, expect_error="A TSIG key with the name")
 
     def test_put_slave_tsig_key_ids_non_existent(self):
         name = unique_zone_name()
-        keyname = unique_zone_name().split('.')[0]
-        self.create_zone(name=name, kind='Native')
-        payload = {
-            'slave_tsig_key_ids': [keyname]
-        }
-        self.put_zone(name, payload, expect_error='A TSIG key with the name')
+        keyname = unique_zone_name().split(".")[0]
+        self.create_zone(name=name, kind="Native")
+        payload = {"slave_tsig_key_ids": [keyname]}
+        self.put_zone(name, payload, expect_error="A TSIG key with the name")
 
     def test_zone_replace_rrsets_basic(self):
         """Basic test: all automatic modification is off, on replace the new rrsets are ingested as is."""
-        name, _, _ = self.create_zone(dnssec=False, soa_edit='', soa_edit_api='')
+        name, _, _ = self.create_zone(dnssec=False, soa_edit="", soa_edit_api="")
         rrsets = [
-            {'name': name, 'type': 'SOA', 'ttl': 3600, 'records': [{'content': 'invalid. hostmaster.invalid. 1 10800 3600 604800 3600'}]},
-            {'name': name, 'type': 'NS', 'ttl': 3600, 'records': [{'content': 'ns1.example.org.'}, {'content': 'ns2.example.org.'}]},
-            {'name': 'www.' + name, 'type': 'A', 'ttl': 3600, 'records': [{'content': '192.0.2.1'}]},
-            {'name': 'sub.' + name, 'type': 'NS', 'ttl': 3600, 'records': [{'content': 'ns1.example.org.'}]},
+            {
+                "name": name,
+                "type": "SOA",
+                "ttl": 3600,
+                "records": [{"content": "invalid. hostmaster.invalid. 1 10800 3600 604800 3600"}],
+            },
+            {
+                "name": name,
+                "type": "NS",
+                "ttl": 3600,
+                "records": [{"content": "ns1.example.org."}, {"content": "ns2.example.org."}],
+            },
+            {"name": "www." + name, "type": "A", "ttl": 3600, "records": [{"content": "192.0.2.1"}]},
+            {"name": "sub." + name, "type": "NS", "ttl": 3600, "records": [{"content": "ns1.example.org."}]},
         ]
-        self.put_zone(name, {'rrsets': rrsets})
+        self.put_zone(name, {"rrsets": rrsets})
 
         data = self.get_zone(name)
         for rrset in rrsets:
-            rrset.setdefault('comments', [])
-            for record in rrset['records']:
-                record.setdefault('disabled', False)
-        received_rrsets = data['rrsets']
+            rrset.setdefault("comments", [])
+            for record in rrset["records"]:
+                record.setdefault("disabled", False)
+        received_rrsets = data["rrsets"]
         for rrset in received_rrsets:
-            remove_timestamp(rrset['records'])
+            remove_timestamp(rrset["records"])
         assert_eq_rrsets(received_rrsets, rrsets)
 
     def test_zone_replace_rrsets_dnssec(self):
         """With dnssec: check automatic rectify is done"""
         name, _, _ = self.create_zone(dnssec=True)
         rrsets = [
-            {'name': name, 'type': 'SOA', 'ttl': 3600, 'records': [{'content': 'invalid. hostmaster.invalid. 1 10800 3600 604800 3600'}]},
-            {'name': name, 'type': 'NS', 'ttl': 3600, 'records': [{'content': 'ns1.example.org.'}, {'content': 'ns2.example.org.'}]},
-            {'name': 'www.' + name, 'type': 'A', 'ttl': 3600, 'records': [{'content': '192.0.2.1'}]},
+            {
+                "name": name,
+                "type": "SOA",
+                "ttl": 3600,
+                "records": [{"content": "invalid. hostmaster.invalid. 1 10800 3600 604800 3600"}],
+            },
+            {
+                "name": name,
+                "type": "NS",
+                "ttl": 3600,
+                "records": [{"content": "ns1.example.org."}, {"content": "ns2.example.org."}],
+            },
+            {"name": "www." + name, "type": "A", "ttl": 3600, "records": [{"content": "192.0.2.1"}]},
         ]
-        self.put_zone(name, {'rrsets': rrsets})
+        self.put_zone(name, {"rrsets": rrsets})
 
         if not is_auth_lmdb():
             # lmdb: skip, no get_db_records implementations
-            dbrecs = get_db_records(name, 'A')
-            assert dbrecs[0]['ordername'] is not None  # default = rectify enabled
+            dbrecs = get_db_records(name, "A")
+            assert dbrecs[0]["ordername"] is not None  # default = rectify enabled
 
     def test_zone_replace_rrsets_with_soa_edit(self):
         """SOA-EDIT was enabled before rrsets will be replaced"""
-        name, _, _ = self.create_zone(soa_edit='INCEPTION-INCREMENT', soa_edit_api='SOA-EDIT-INCREASE')
+        name, _, _ = self.create_zone(soa_edit="INCEPTION-INCREMENT", soa_edit_api="SOA-EDIT-INCREASE")
         rrsets = [
-            {'name': name, 'type': 'SOA', 'ttl': 3600, 'records': [{'content': 'invalid. hostmaster.invalid. 1 10800 3600 604800 3600'}]},
-            {'name': name, 'type': 'NS', 'ttl': 3600, 'records': [{'content': 'ns1.example.org.'}, {'content': 'ns2.example.org.'}]},
-            {'name': 'www.' + name, 'type': 'A', 'ttl': 3600, 'records': [{'content': '192.0.2.1'}]},
-            {'name': 'sub.' + name, 'type': 'NS', 'ttl': 3600, 'records': [{'content': 'ns1.example.org.'}]},
+            {
+                "name": name,
+                "type": "SOA",
+                "ttl": 3600,
+                "records": [{"content": "invalid. hostmaster.invalid. 1 10800 3600 604800 3600"}],
+            },
+            {
+                "name": name,
+                "type": "NS",
+                "ttl": 3600,
+                "records": [{"content": "ns1.example.org."}, {"content": "ns2.example.org."}],
+            },
+            {"name": "www." + name, "type": "A", "ttl": 3600, "records": [{"content": "192.0.2.1"}]},
+            {"name": "sub." + name, "type": "NS", "ttl": 3600, "records": [{"content": "ns1.example.org."}]},
         ]
-        self.put_zone(name, {'rrsets': rrsets})
+        self.put_zone(name, {"rrsets": rrsets})
 
         data = self.get_zone(name)
-        soa = [rrset['records'][0]['content'] for rrset in data['rrsets'] if rrset['type'] == 'SOA'][0]
+        soa = [rrset["records"][0]["content"] for rrset in data["rrsets"] if rrset["type"] == "SOA"][0]
         assert int(soa.split()[2]) > 1  # serial is larger than what we sent
 
     def test_zone_replace_rrsets_no_soa_primary(self):
         """Replace all RRsets but supply no SOA. Should fail."""
         name, _, _ = self.create_zone()
         rrsets = [
-            {'name': name, 'type': 'NS', 'ttl': 3600, 'records': [{'content': 'ns1.example.org.'}, {'content': 'ns2.example.org.'}]}
+            {
+                "name": name,
+                "type": "NS",
+                "ttl": 3600,
+                "records": [{"content": "ns1.example.org."}, {"content": "ns2.example.org."}],
+            }
+        ]
+        self.put_zone(name, {"rrsets": rrsets}, expect_error="Must give SOA record for zone when replacing all RR sets")
+
+    @parameterized.expand(
+        [
+            (None, []),
+            (
+                None,
+                [
+                    {
+                        "name": "$NAME$",
+                        "type": "SOA",
+                        "ttl": 3600,
+                        "records": [{"content": "invalid. hostmaster.invalid. 1 10800 3600 604800 3600"}],
+                    },
+                ],
+            ),
         ]
-        self.put_zone(name, {'rrsets': rrsets}, expect_error='Must give SOA record for zone when replacing all RR sets')
-
-    @parameterized.expand([
-        (None, []),
-        (None, [
-            {'name': '$NAME$', 'type': 'SOA', 'ttl': 3600, 'records': [{'content': 'invalid. hostmaster.invalid. 1 10800 3600 604800 3600'}]},
-        ]),
-    ])
+    )
     def test_zone_replace_rrsets_secondary(self, expected_error, rrsets):
         """
         Replace all RRsets in a SECONDARY zone.
 
         If no SOA is given, this should still succeed, also setting zone stale (but cannot assert this here).
         """
-        name, _, _ = self.create_zone(kind='Secondary', nameservers=None, masters=['127.0.0.2'])
-        self.put_zone(name, {'rrsets': templated_rrsets(rrsets, name)}, expect_error=expected_error)
-
-    @parameterized.expand([
-        (None, []),
-        ("Modifying RRsets in Consumer zones is unsupported", [
-            {'name': '$NAME$', 'type': 'SOA', 'ttl': 3600, 'records': [{'content': 'invalid. hostmaster.invalid. 1 10800 3600 604800 3600'}]},
-        ]),
-    ])
+        name, _, _ = self.create_zone(kind="Secondary", nameservers=None, masters=["127.0.0.2"])
+        self.put_zone(name, {"rrsets": templated_rrsets(rrsets, name)}, expect_error=expected_error)
+
+    @parameterized.expand(
+        [
+            (None, []),
+            (
+                "Modifying RRsets in Consumer zones is unsupported",
+                [
+                    {
+                        "name": "$NAME$",
+                        "type": "SOA",
+                        "ttl": 3600,
+                        "records": [{"content": "invalid. hostmaster.invalid. 1 10800 3600 604800 3600"}],
+                    },
+                ],
+            ),
+        ]
+    )
     def test_zone_replace_rrsets_consumer(self, expected_error, rrsets):
-        name, _, _ = self.create_zone(kind='Consumer', nameservers=None, masters=['127.0.0.2'])
-        self.put_zone(name, {'rrsets': templated_rrsets(rrsets, name)}, expect_error=expected_error)
+        name, _, _ = self.create_zone(kind="Consumer", nameservers=None, masters=["127.0.0.2"])
+        self.put_zone(name, {"rrsets": templated_rrsets(rrsets, name)}, expect_error=expected_error)
 
     def test_zone_replace_rrsets_negative_ttl(self):
-        name, _, _ = self.create_zone(dnssec=False, soa_edit='', soa_edit_api='')
+        name, _, _ = self.create_zone(dnssec=False, soa_edit="", soa_edit_api="")
         rrsets = [
-            {'name': name, 'type': 'SOA', 'ttl': -1, 'records': [{'content': 'invalid. hostmaster.invalid. 1 10800 3600 604800 3600'}]},
+            {
+                "name": name,
+                "type": "SOA",
+                "ttl": -1,
+                "records": [{"content": "invalid. hostmaster.invalid. 1 10800 3600 604800 3600"}],
+            },
+        ]
+        self.put_zone(name, {"rrsets": rrsets}, expect_error="Key 'ttl' is not a positive Integer")
+
+    @parameterized.expand(
+        [
+            (
+                "IN MX: non-hostname content",
+                [{"name": "$NAME$", "type": "MX", "ttl": 3600, "records": [{"content": "10 mail@mx.example.org."}]}],
+            ),
+            (
+                "out of zone",
+                [{"name": "not-in-zone.", "type": "NS", "ttl": 3600, "records": [{"content": "ns1.example.org."}]}],
+            ),
+            (
+                "contains unsupported characters",
+                [{"name": "test:.$NAME$", "type": "NS", "ttl": 3600, "records": [{"content": "ns1.example.org."}]}],
+            ),
+            (
+                "unknown type",
+                [{"name": "$NAME$", "type": "INVALID", "ttl": 3600, "records": [{"content": "192.0.2.1"}]}],
+            ),
+            (
+                "conflicts with existing NS RRset",
+                [{"name": "$NAME$", "type": "CNAME", "ttl": 3600, "records": [{"content": "example.org."}]}],
+            ),
         ]
-        self.put_zone(name, {'rrsets': rrsets}, expect_error="Key 'ttl' is not a positive Integer")
-
-    @parameterized.expand([
-        ("IN MX: non-hostname content", [{'name': '$NAME$', 'type': 'MX', 'ttl': 3600, 'records': [{"content": "10 mail@mx.example.org."}]}]),
-        ("out of zone", [{'name': 'not-in-zone.', 'type': 'NS', 'ttl': 3600, 'records': [{"content": "ns1.example.org."}]}]),
-        ("contains unsupported characters", [{'name': 'test:.$NAME$', 'type': 'NS', 'ttl': 3600, 'records': [{"content": "ns1.example.org."}]}]),
-        ("unknown type", [{'name': '$NAME$', 'type': 'INVALID', 'ttl': 3600, 'records': [{"content": "192.0.2.1"}]}]),
-        ("conflicts with existing NS RRset", [{'name': '$NAME$', 'type': 'CNAME', 'ttl': 3600, 'records': [{"content": "example.org."}]}]),
-    ])
+    )
     def test_zone_replace_rrsets_invalid(self, expected_error, invalid_rrsets):
         """Test validation of RRsets before replacing them"""
-        name, _, _ = self.create_zone(dnssec=False, soa_edit='', soa_edit_api='')
+        name, _, _ = self.create_zone(dnssec=False, soa_edit="", soa_edit_api="")
         base_rrsets = [
-            {'name': name, 'type': 'SOA', 'ttl': 3600, 'records': [{'content': 'invalid. hostmaster.invalid. 1 10800 3600 604800 3600'}]},
-            {'name': name, 'type': 'NS', 'ttl': 3600, 'records': [{'content': 'ns1.example.org.'}, {'content': 'ns2.example.org.'}]},
+            {
+                "name": name,
+                "type": "SOA",
+                "ttl": 3600,
+                "records": [{"content": "invalid. hostmaster.invalid. 1 10800 3600 604800 3600"}],
+            },
+            {
+                "name": name,
+                "type": "NS",
+                "ttl": 3600,
+                "records": [{"content": "ns1.example.org."}, {"content": "ns2.example.org."}],
+            },
         ]
         rrsets = base_rrsets + templated_rrsets(invalid_rrsets, name)
-        self.put_zone(name, {'rrsets': rrsets}, expect_error=expected_error)
+        self.put_zone(name, {"rrsets": rrsets}, expect_error=expected_error)
 
     @unittest.skipIf(not is_auth_lmdb(), "No rrset timestamps except with LMDB")
     def test_check_rrset_modified_at(self):
-        name = 'host-18000.example.com.'
+        name = "host-18000.example.com."
         r = self.session.get(self.url("/api/v1/servers/localhost/zones"))
         domains = r.json()
-        example_com = [domain for domain in domains if domain['name'] == u'example.com.'][0]
+        example_com = [domain for domain in domains if domain["name"] == "example.com."][0]
 
         # verify single record from name that has a single record
-        data = self.get_zone(example_com['id'], rrset_name="host-18000.example.com.")
-        modified_at = data['rrsets'][0]['records'][0]['modified_at']
+        data = self.get_zone(example_com["id"], rrset_name="host-18000.example.com.")
+        modified_at = data["rrsets"][0]["records"][0]["modified_at"]
 
         # write back the same data anyway, to get a new timestamp
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'A',
-            'ttl': 120,
-            'records':
-            [
+            "changetype": "replace",
+            "name": name,
+            "type": "A",
+            "ttl": 120,
+            "records": [
                 {
-                    'content': '192.168.1.80',
+                    "content": "192.168.1.80",
                 }
-            ]
+            ],
         }
-        payload = {'rrsets': [rrset]}
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/example.com"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
 
         # get the changed record.
-        data = self.get_zone(example_com['id'], rrset_name="host-18000.example.com.")
-        modified_at_new = data['rrsets'][0]['records'][0]['modified_at']
+        data = self.get_zone(example_com["id"], rrset_name="host-18000.example.com.")
+        modified_at_new = data["rrsets"][0]["records"][0]["modified_at"]
         self.assertGreater(modified_at_new, modified_at)
 
     @unittest.skipIf(is_auth_lmdb(), "Needs to perform database update")
     def test_access_zone_with_invalid_content(self):
         name, payload, zone = self.create_zone()
         rrset = {
-            'changetype': 'replace',
-            'name': name,
-            'type': 'TXT',
-            'ttl': 3600,
-            'records': [
-                {
-                    "content": "\"innocuous data\"",
-                    "disabled": False
-                }
-            ]
+            "changetype": "replace",
+            "name": name,
+            "type": "TXT",
+            "ttl": 3600,
+            "records": [{"content": '"innocuous data"', "disabled": False}],
         }
-        payload = {'rrsets': [rrset]}
-        r = self.session.patch(self.url("/api/v1/servers/localhost/zones/" + name), data=json.dumps(payload),
-                               headers={'content-type': 'application/json'})
+        payload = {"rrsets": [rrset]}
+        r = self.session.patch(
+            self.url("/api/v1/servers/localhost/zones/" + name),
+            data=json.dumps(payload),
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         # Now alter the data - see get_db_records() for inspiration
-        badcontent = 'invalid \"TXT data'
+        badcontent = 'invalid "TXT data'
         db, placeholder = get_auth_db()
         cur = db.cursor()
-        cur.execute("""
+        cur.execute(
+            """
             UPDATE records
-            SET content="""+placeholder+"""
-            WHERE name="""+placeholder+""" AND type='TXT'"""
-            ,
-            (badcontent, name.rstrip('.')))
-        cur.execute('COMMIT') # Figuring out how many hours I wasted on this test because of this missing line is left as an exercise to the reader
+            SET content="""
+            + placeholder
+            + """
+            WHERE name="""
+            + placeholder
+            + """ AND type='TXT'""",
+            (badcontent, name.rstrip(".")),
+        )
+        cur.execute(
+            "COMMIT"
+        )  # Figuring out how many hours I wasted on this test because of this missing line is left as an exercise to the reader
         cur.close()
         db.close()
         # Try and get the zone data
         r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + name))
         self.assertEqual(r.status_code, 422)
-        self.assertIn('Data field in DNS should end on a quote', r.json()['error'])
+        self.assertIn("Data field in DNS should end on a quote", r.json()["error"])
 
     def test_underscore_names(self):
         name = unique_zone_name()
-        self.create_zone(name=name, kind='Native')
+        self.create_zone(name=name, kind="Native")
 
         payload_metadata = {"type": "Metadata", "kind": "RFC1123-CONFORMANCE", "metadata": ["0"]}
-        r = self.session.post(self.url("/api/v1/servers/localhost/zones/" + name + "/metadata"),
-                              data=json.dumps(payload_metadata))
+        r = self.session.post(
+            self.url("/api/v1/servers/localhost/zones/" + name + "/metadata"), data=json.dumps(payload_metadata)
+        )
         rdata = r.json()
         self.assertEqual(r.status_code, 201)
         self.assertEqual(rdata["metadata"], payload_metadata["metadata"])
 
         rrset = {
-            'changetype': 'replace',
-            'name': "_underscores_r_us_."+name,
-            'type': "A",
-            'ttl': 3600,
-            'records': [{
-                "content": "42.42.42.42",
-                "disabled": False,
-            }],
-        }
-        payload = {'rrsets': [rrset]}
+            "changetype": "replace",
+            "name": "_underscores_r_us_." + name,
+            "type": "A",
+            "ttl": 3600,
+            "records": [
+                {
+                    "content": "42.42.42.42",
+                    "disabled": False,
+                }
+            ],
+        }
+        payload = {"rrsets": [rrset]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
         data = self.get_zone(name)
         # check our record has appeared
-        self.assertEqual(get_rrset(data, rrset['name'], 'A')['records'], rrset['records'])
+        self.assertEqual(get_rrset(data, rrset["name"], "A")["records"], rrset["records"])
+
 
 @unittest.skipIf(not is_auth(), "Not applicable")
 class AuthRootZone(ZonesApiTestCase, AuthZonesHelperMixin):
-
     def setUp(self):
         super(AuthRootZone, self).setUp()
         # zone name is not unique, so delete the zone before each individual test.
         self.session.delete(self.url("/api/v1/servers/localhost/zones/=2E"))
 
     def test_create_zone(self):
-        name, payload, data = self.create_zone(name='.', serial=22, soa_edit_api='')
-        for k in ('id', 'url', 'name', 'masters', 'kind', 'last_check', 'notified_serial', 'serial', 'soa_edit_api', 'soa_edit', 'account'):
+        name, payload, data = self.create_zone(name=".", serial=22, soa_edit_api="")
+        for k in (
+            "id",
+            "url",
+            "name",
+            "masters",
+            "kind",
+            "last_check",
+            "notified_serial",
+            "serial",
+            "soa_edit_api",
+            "soa_edit",
+            "account",
+        ):
             self.assertIn(k, data)
             if k in payload:
                 self.assertEqual(data[k], payload[k])
         # validate generated SOA
-        rec = get_first_rec(data, '.', 'SOA')
+        rec = get_first_rec(data, ".", "SOA")
         self.assertEqual(
-            rec['content'],
-            "a.misconfigured.dns.server.invalid. hostmaster. " + str(payload['serial']) +
-            " 10800 3600 604800 3600"
+            rec["content"],
+            "a.misconfigured.dns.server.invalid. hostmaster. " + str(payload["serial"]) + " 10800 3600 604800 3600",
         )
         # Regression test: verify zone list works
         zonelist = self.session.get(self.url("/api/v1/servers/localhost/zones")).json()
         print("zonelist:", zonelist)
-        self.assertIn(payload['name'], [zone['name'] for zone in zonelist])
+        self.assertIn(payload["name"], [zone["name"] for zone in zonelist])
         # Also test that fetching the zone works.
-        print("id:", data['id'])
-        self.assertEqual(data['id'], '=2E')
-        data = self.get_zone(data['id'])
+        print("id:", data["id"])
+        self.assertEqual(data["id"], "=2E")
+        data = self.get_zone(data["id"])
         print("zone (fetched):", data)
-        for k in ('name', 'kind'):
+        for k in ("name", "kind"):
             self.assertIn(k, data)
             self.assertEqual(data[k], payload[k])
-        self.assertEqual(data['rrsets'][0]['name'], '.')
+        self.assertEqual(data["rrsets"][0]["name"], ".")
 
     def test_update_zone(self):
-        name, payload, zone = self.create_zone(name='.')
-        zone_id = '=2E'
+        name, payload, zone = self.create_zone(name=".")
+        zone_id = "=2E"
         # update, set as Master and enable SOA-EDIT-API
         payload = {
-            'kind': 'Master',
-            'masters': ['192.0.2.1', '192.0.2.2'],
-            'soa_edit_api': 'EPOCH',
-            'soa_edit': 'EPOCH'
+            "kind": "Master",
+            "masters": ["192.0.2.1", "192.0.2.2"],
+            "soa_edit_api": "EPOCH",
+            "soa_edit": "EPOCH",
         }
         self.put_zone(zone_id, payload)
         data = self.get_zone(zone_id)
@@ -3210,11 +3256,7 @@ class AuthRootZone(ZonesApiTestCase, AuthZonesHelperMixin):
             self.assertIn(k, data)
             self.assertEqual(data[k], payload[k])
         # update, back to Native and empty(off)
-        payload = {
-            'kind': 'Native',
-            'soa_edit_api': '',
-            'soa_edit': ''
-        }
+        payload = {"kind": "Native", "soa_edit_api": "", "soa_edit": ""}
         self.put_zone(zone_id, payload)
         data = self.get_zone(zone_id)
         for k in payload.keys():
@@ -3224,176 +3266,175 @@ class AuthRootZone(ZonesApiTestCase, AuthZonesHelperMixin):
 
 @unittest.skipIf(not is_recursor(), "Not applicable")
 class RecursorZones(ZonesApiTestCase):
-
     def create_zone(self, name=None, kind=None, rd=False, servers=None, notify_allowed=False):
         if name is None:
             name = unique_zone_name()
         if servers is None:
             servers = []
         payload = {
-            'name': name,
-            'kind': kind,
-            'servers': servers,
-            'recursion_desired': rd,
-            'notify_allowed': notify_allowed
+            "name": name,
+            "kind": kind,
+            "servers": servers,
+            "recursion_desired": rd,
+            "notify_allowed": notify_allowed,
         }
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success_json(r)
         return payload, r.json()
 
     def test_create_auth_zone(self):
-        payload, data = self.create_zone(kind='Native')
+        payload, data = self.create_zone(kind="Native")
         for k in payload.keys():
             self.assertEqual(data[k], payload[k])
 
     def test_create_zone_no_name(self):
         payload = {
-            'name': '',
-            'kind': 'Native',
-            'servers': ['8.8.8.8'],
-            'recursion_desired': False,
+            "name": "",
+            "kind": "Native",
+            "servers": ["8.8.8.8"],
+            "recursion_desired": False,
         }
         print(payload)
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 422)
-        self.assert_in_json_error('is not canonical', r.json())
+        self.assert_in_json_error("is not canonical", r.json())
 
     def test_create_forwarded_zone(self):
-        payload, data = self.create_zone(kind='Forwarded', rd=False, servers=['8.8.8.8'])
+        payload, data = self.create_zone(kind="Forwarded", rd=False, servers=["8.8.8.8"])
         # return values are normalized
-        payload['servers'][0] += ':53'
+        payload["servers"][0] += ":53"
         for k in payload.keys():
             self.assertEqual(data[k], payload[k])
 
     def test_create_forwarded_zone_notify_allowed(self):
-        payload, data = self.create_zone(kind='Forwarded', rd=False, servers=['8.8.8.8'], notify_allowed=True)
+        payload, data = self.create_zone(kind="Forwarded", rd=False, servers=["8.8.8.8"], notify_allowed=True)
         # return values are normalized
-        payload['servers'][0] += ':53'
+        payload["servers"][0] += ":53"
         for k in payload.keys():
             self.assertEqual(data[k], payload[k])
 
     def test_create_forwarded_rd_zone(self):
-        payload, data = self.create_zone(name='google.com.', kind='Forwarded', rd=True, servers=['8.8.8.8'])
+        payload, data = self.create_zone(name="google.com.", kind="Forwarded", rd=True, servers=["8.8.8.8"])
         # return values are normalized
-        payload['servers'][0] += ':53'
+        payload["servers"][0] += ":53"
         for k in payload.keys():
             self.assertEqual(data[k], payload[k])
 
     def test_create_auth_zone_with_symbols(self):
-        payload, data = self.create_zone(name='foo/bar.'+unique_zone_name(), kind='Native')
-        expected_id = (payload['name'].replace('/', '=2F'))
+        payload, data = self.create_zone(name="foo/bar." + unique_zone_name(), kind="Native")
+        expected_id = payload["name"].replace("/", "=2F")
         for k in payload.keys():
             self.assertEqual(data[k], payload[k])
-        self.assertEqual(data['id'], expected_id)
+        self.assertEqual(data["id"], expected_id)
 
     def test_rename_auth_zone(self):
-        payload, data = self.create_zone(kind='Native')
-        name = payload['name']
+        payload, data = self.create_zone(kind="Native")
+        name = payload["name"]
         # now rename it
-        payload = {
-            'name': 'renamed-'+name,
-            'kind': 'Native',
-            'recursion_desired': False
-        }
+        payload = {"name": "renamed-" + name, "kind": "Native", "recursion_desired": False}
         r = self.session.put(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success(r)
-        data = self.session.get(self.url("/api/v1/servers/localhost/zones/" + payload['name'])).json()
+        data = self.session.get(self.url("/api/v1/servers/localhost/zones/" + payload["name"])).json()
         for k in payload.keys():
             self.assertEqual(data[k], payload[k])
 
     def test_zone_delete(self):
-        payload, zone = self.create_zone(kind='Native')
-        name = payload['name']
+        payload, zone = self.create_zone(kind="Native")
+        name = payload["name"]
         r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + name))
         self.assertEqual(r.status_code, 204)
-        self.assertNotIn('Content-Type', r.headers)
+        self.assertNotIn("Content-Type", r.headers)
 
     def test_search_rr_exact_zone(self):
         name = unique_zone_name()
-        self.create_zone(name=name, kind='Native')
+        self.create_zone(name=name, kind="Native")
         r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=" + name))
         self.assert_success_json(r)
         print(r.json())
-        self.assertEqual(r.json(), [{u'type': u'zone', u'name': name, u'zone_id': name}])
+        self.assertEqual(r.json(), [{"type": "zone", "name": name, "zone_id": name}])
 
     def test_search_rr_substring(self):
-        name = 'search-rr-zone.name.'
-        self.create_zone(name=name, kind='Native')
+        name = "search-rr-zone.name."
+        self.create_zone(name=name, kind="Native")
         r = self.session.get(self.url("/api/v1/servers/localhost/search-data?q=rr-zone"))
         self.assert_success_json(r)
         print(r.json())
         # should return zone, SOA
         self.assertEqual(len(r.json()), 2)
 
+
 @unittest.skipIf(not is_auth(), "Not applicable")
 class AuthZoneKeys(ZonesApiTestCase, AuthZonesHelperMixin):
-
     def test_get_keys(self):
-        r = self.session.get(
-            self.url("/api/v1/servers/localhost/zones/powerdnssec.org./cryptokeys"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/powerdnssec.org./cryptokeys"))
         self.assert_success_json(r)
         keys = r.json()
         self.assertGreater(len(keys), 0)
 
         key0 = deepcopy(keys[0])
-        del key0['dnskey']
-        del key0['ds']
+        del key0["dnskey"]
+        del key0["ds"]
         expected = {
-            u'algorithm': u'ECDSAP256SHA256',
-            u'bits': 256,
-            u'active': True,
-            u'type': u'Cryptokey',
-            u'keytype': u'csk',
-            u'flags': 257,
-            u'published': True,
-            u'id': 1}
+            "algorithm": "ECDSAP256SHA256",
+            "bits": 256,
+            "active": True,
+            "type": "Cryptokey",
+            "keytype": "csk",
+            "flags": 257,
+            "published": True,
+            "id": 1,
+        }
         self.assertEqual(key0, expected)
 
-        keydata = keys[0]['dnskey'].split()
+        keydata = keys[0]["dnskey"].split()
         self.assertEqual(len(keydata), 4)
 
     def test_get_keys_with_cds(self):
         payload_metadata = {"type": "Metadata", "kind": "PUBLISH-CDS", "metadata": ["4"]}
-        r = self.session.post(self.url("/api/v1/servers/localhost/zones/powerdnssec.org./metadata"),
-                              data=json.dumps(payload_metadata))
+        r = self.session.post(
+            self.url("/api/v1/servers/localhost/zones/powerdnssec.org./metadata"), data=json.dumps(payload_metadata)
+        )
         rdata = r.json()
         self.assertEqual(r.status_code, 201)
         self.assertEqual(rdata["metadata"], payload_metadata["metadata"])
 
-        r = self.session.get(
-            self.url("/api/v1/servers/localhost/zones/powerdnssec.org./cryptokeys"))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/powerdnssec.org./cryptokeys"))
         self.assert_success_json(r)
         keys = r.json()
         self.assertGreater(len(keys), 0)
 
         key0 = deepcopy(keys[0])
-        self.assertEqual(len(key0['cds']), 1)
-        self.assertIn(key0['cds'][0], key0['ds'])
-        self.assertEqual(key0['cds'][0].split()[2], '4')
-        del key0['dnskey']
-        del key0['ds']
-        del key0['cds']
+        self.assertEqual(len(key0["cds"]), 1)
+        self.assertIn(key0["cds"][0], key0["ds"])
+        self.assertEqual(key0["cds"][0].split()[2], "4")
+        del key0["dnskey"]
+        del key0["ds"]
+        del key0["cds"]
         expected = {
-            u'algorithm': u'ECDSAP256SHA256',
-            u'bits': 256,
-            u'active': True,
-            u'type': u'Cryptokey',
-            u'keytype': u'csk',
-            u'flags': 257,
-            u'published': True,
-            u'id': 1}
+            "algorithm": "ECDSAP256SHA256",
+            "bits": 256,
+            "active": True,
+            "type": "Cryptokey",
+            "keytype": "csk",
+            "flags": 257,
+            "published": True,
+            "id": 1,
+        }
         self.assertEqual(key0, expected)
 
-        keydata = keys[0]['dnskey'].split()
+        keydata = keys[0]["dnskey"].split()
         self.assertEqual(len(keydata), 4)
 
         r = self.session.delete(self.url("/api/v1/servers/localhost/zones/powerdnssec.org./metadata/PUBLISH-CDS"))
index 848b296d38200f18b134ae457f196eaf6e7c4b4a..f1d3290feedebdb4bc231b87adb175b961e330cd 100644 (file)
@@ -3,23 +3,20 @@ import unittest
 
 from test_helper import ApiTestCase, is_auth, pdnsutil, unique_zone_name
 
+
 @unittest.skipIf(not is_auth(), "Not applicable")
 class Cryptokeys(ApiTestCase):
-
     def setUp(self):
         super(Cryptokeys, self).setUp()
         self.keyid = 0
         self.zone = unique_zone_name()
         self.zone_nodot = self.zone[:-1]
-        payload = {
-            'name': self.zone,
-            'kind': 'Native',
-            'nameservers': ['ns1.example.com.', 'ns2.example.com.']
-        }
+        payload = {"name": self.zone, "kind": "Native", "nameservers": ["ns1.example.com.", "ns2.example.com."]}
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assert_success_json(r)
         self.assertEqual(r.status_code, 201)
 
@@ -28,7 +25,7 @@ class Cryptokeys(ApiTestCase):
         self.remove_zone_key(self.keyid)
 
     # Adding a key to self.zone using the pdnsutil command
-    def add_zone_key(self, status=['inactive']):
+    def add_zone_key(self, status=["inactive"]):
         return pdnsutil("add-zone-key", self.zone_nodot, "ksk", *status)
 
     # Removes a key from self.zone by id using the pdnsutil command
@@ -39,8 +36,8 @@ class Cryptokeys(ApiTestCase):
     def test_delete(self):
         self.keyid = self.add_zone_key()
 
-        #checks the status code. I don't know how to test explicit that the backend fail removing a key.
-        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid))
+        # checks the status code. I don't know how to test explicit that the backend fail removing a key.
+        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/" + self.keyid))
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
@@ -50,56 +47,59 @@ class Cryptokeys(ApiTestCase):
 
     def test_get_wrong_zone(self):
         self.keyid = self.add_zone_key()
-        r = self.session.get(self.url("/api/v1/servers/localhost/zones/"+self.zone+"fail/cryptokeys/"+self.keyid))
+        r = self.session.get(self.url("/api/v1/servers/localhost/zones/" + self.zone + "fail/cryptokeys/" + self.keyid))
         self.assertEqual(r.status_code, 404)
 
     def test_delete_wrong_id(self):
         self.keyid = self.add_zone_key()
-        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/1234567"))
+        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/1234567"))
         self.assertEqual(r.status_code, 404)
 
     def test_delete_wrong_zone(self):
         self.keyid = self.add_zone_key()
-        #checks for not covered zonename
-        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+self.zone+"fail/cryptokeys/"+self.keyid))
+        # checks for not covered zonename
+        r = self.session.delete(
+            self.url("/api/v1/servers/localhost/zones/" + self.zone + "fail/cryptokeys/" + self.keyid)
+        )
         self.assertEqual(r.status_code, 404)
 
     def test_delete_key_is_gone(self):
         self.keyid = self.add_zone_key()
         self.remove_zone_key(self.keyid)
-        #checks for key is gone. Its ok even if no key had to be deleted. Or something went wrong with the backend.
-        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid))
+        # checks for key is gone. Its ok even if no key had to be deleted. Or something went wrong with the backend.
+        r = self.session.delete(self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/" + self.keyid))
         self.assertEqual(r.status_code, 404)
 
     # Prepares the json object for Post and sends it to the server
-    def add_key(self, content='', type='ksk', active='true', algo='', bits=None):
+    def add_key(self, content="", type="ksk", active="true", algo="", bits=None):
         payload = {
-            'keytype': type,
-            'active': active,
+            "keytype": type,
+            "active": active,
         }
         if algo:
-            payload['algorithm'] = algo
+            payload["algorithm"] = algo
         if bits is not None:
-            payload['bits'] = bits
-        if content != '':
-            payload['content'] = content
+            payload["bits"] = bits
+        if content != "":
+            payload["content"] = content
         print("create key with payload:", payload)
         r = self.session.post(
-            self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys"),
+            self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys"),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
 
         return r
 
     # Test POST for a positive result and delete the added key
-    def post_helper(self, content='', algo='', bits=None):
+    def post_helper(self, content="", algo="", bits=None):
         r = self.add_key(content=content, algo=algo, bits=bits)
         self.assert_success_json(r)
         self.assertEqual(r.status_code, 201)
         response = r.json()
         # Only a ksk added, so expected type is csk
-        self.assertEqual(response['keytype'], 'csk')
-        self.keyid = response['id']
+        self.assertEqual(response["keytype"], "csk")
+        self.keyid = response["id"]
         # Check if the key is actually added
         out = pdnsutil("list-keys", self.zone_nodot)
         self.assertIn(self.zone_nodot, out)
@@ -118,84 +118,87 @@ class Cryptokeys(ApiTestCase):
 
     # Test POST to add a key with specific name
     def test_post_specific_name(self):
-        self.post_helper(algo='ecdsa256')
+        self.post_helper(algo="ecdsa256")
 
     # Test POST to add a private key from external resource
     def test_post_content(self):
-        self.post_helper(content="Private-key-format: v1.2\n"+
-                                 "Algorithm: 8 (RSASHA256)\n"+
-                                 "Modulus: 4GlYLGgDI7ohnP8SmEW8EBERbNRusDcg0VQda/EPVHU=\n"+
-                                 "PublicExponent: AQAB\n"+
-                                 "PrivateExponent: JBnuXF5zOtkjtSz3odV+Fk5UNUTTeCsiI16dkcM7TVU=\n"+
-                                 "Prime1: /w7TM4118RoSEvP8+dgnCw==\n"+
-                                 "Prime2: 4T2KhkYLa3w7rdK3Cb2ifw==\n"+
-                                 "Exponent1: 3aeKj9Ct4JuhfWsgPBhGxQ==\n"+
-                                 "Exponent2: tfh1OMPQKBdnU6iATjNR2w==\n"+
-                                 "Coefficient: eVrHe/kauqOewSKndIImrg==)\n")
+        self.post_helper(
+            content="Private-key-format: v1.2\n"
+            + "Algorithm: 8 (RSASHA256)\n"
+            + "Modulus: 4GlYLGgDI7ohnP8SmEW8EBERbNRusDcg0VQda/EPVHU=\n"
+            + "PublicExponent: AQAB\n"
+            + "PrivateExponent: JBnuXF5zOtkjtSz3odV+Fk5UNUTTeCsiI16dkcM7TVU=\n"
+            + "Prime1: /w7TM4118RoSEvP8+dgnCw==\n"
+            + "Prime2: 4T2KhkYLa3w7rdK3Cb2ifw==\n"
+            + "Exponent1: 3aeKj9Ct4JuhfWsgPBhGxQ==\n"
+            + "Exponent2: tfh1OMPQKBdnU6iATjNR2w==\n"
+            + "Coefficient: eVrHe/kauqOewSKndIImrg==)\n"
+        )
 
     def test_post_wrong_key_format(self):
         r = self.add_key(content="trollololoooolll")
         self.assert_error_json(r)
         self.assertEqual(r.status_code, 422)
-        self.assertIn("Key could not be parsed. Make sure your key format is correct.",r.json()['error'])
+        self.assertIn("Key could not be parsed. Make sure your key format is correct.", r.json()["error"])
 
     def test_post_wrong_keytype(self):
-        r = self.add_key(type='sdfdhhgj')
+        r = self.add_key(type="sdfdhhgj")
         self.assert_error_json(r)
         self.assertEqual(r.status_code, 422)
-        self.assertIn("Invalid keytype",r.json()['error'])
+        self.assertIn("Invalid keytype", r.json()["error"])
 
     def test_post_wrong_bits_format(self):
-        r = self.add_key(bits='sdfdhhgj')
+        r = self.add_key(bits="sdfdhhgj")
         self.assert_error_json(r)
         self.assertEqual(r.status_code, 422)
-        self.assertIn("'bits' must be a positive integer value",r.json()['error'])
+        self.assertIn("'bits' must be a positive integer value", r.json()["error"])
 
-        r = self.add_key(bits='5.5')
+        r = self.add_key(bits="5.5")
         self.assert_error_json(r)
         self.assertEqual(r.status_code, 422)
-        self.assertIn("'bits' must be a positive integer value",r.json()['error'])
+        self.assertIn("'bits' must be a positive integer value", r.json()["error"])
 
-        r = self.add_key(bits='-6')
+        r = self.add_key(bits="-6")
         self.assert_error_json(r)
         self.assertEqual(r.status_code, 422)
-        self.assertIn("'bits' must be a positive integer value",r.json()['error'])
+        self.assertIn("'bits' must be a positive integer value", r.json()["error"])
 
     def test_post_unsupported_algorithm(self):
-        r = self.add_key(algo='lkjhgf')
+        r = self.add_key(algo="lkjhgf")
         self.assert_error_json(r)
         self.assertEqual(r.status_code, 422)
-        self.assertIn("Unknown algorithm:",r.json()['error'])
+        self.assertIn("Unknown algorithm:", r.json()["error"])
 
     def test_post_forgot_bits(self):
         r = self.add_key(algo="rsasha256")
         self.assert_error_json(r)
         self.assertEqual(r.status_code, 422)
-        self.assertIn("key requires the size (in bits) to be passed", r.json()['error'])
+        self.assertIn("key requires the size (in bits) to be passed", r.json()["error"])
 
     def test_post_wrong_bit_size(self):
         r = self.add_key(algo=10, bits=30)
         self.assert_error_json(r)
-        self.assertEqual(r.status_code,422)
-        self.assertIn("The algorithm does not support the given bit size.", r.json()['error'])
+        self.assertEqual(r.status_code, 422)
+        self.assertIn("The algorithm does not support the given bit size.", r.json()["error"])
 
     def test_post_can_not_guess_key_size(self):
         r = self.add_key(algo=17)
         self.assert_error_json(r)
-        self.assertEqual(r.status_code,422)
-        self.assertIn("Can not guess key size for algorithm", r.json()['error'])
+        self.assertEqual(r.status_code, 422)
+        self.assertIn("Can not guess key size for algorithm", r.json()["error"])
 
     def test_put_activate_key(self):
         self.keyid = self.add_zone_key()
 
         payload = {
-            'active': True,
-            'published': True,
+            "active": True,
+            "published": True,
         }
         r = self.session.put(
-            self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+            self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/" + self.keyid),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
@@ -204,17 +207,18 @@ class Cryptokeys(ApiTestCase):
         self.assertIn("Active", out)
 
     def test_put_deactivate_key(self):
-        self.keyid = self.add_zone_key(status=['active'])
+        self.keyid = self.add_zone_key(status=["active"])
         # deactivate key
         payload2 = {
-            'active': False,
-            'published': True,
+            "active": False,
+            "published": True,
         }
 
         r = self.session.put(
-            self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+            self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/" + self.keyid),
             data=json.dumps(payload2),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
@@ -227,14 +231,15 @@ class Cryptokeys(ApiTestCase):
 
         # deactivate key
         payload = {
-            'active': False,
-            'published': True,
+            "active": False,
+            "published": True,
         }
 
         r = self.session.put(
-            self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+            self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/" + self.keyid),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
@@ -243,17 +248,18 @@ class Cryptokeys(ApiTestCase):
         self.assertIn("Inactive", out)
 
     def test_put_activate_active_key(self):
-        self.keyid = self.add_zone_key(status=['active'])
+        self.keyid = self.add_zone_key(status=["active"])
 
         # activate key
         payload2 = {
-            'active': True,
-            'published': True,
+            "active": True,
+            "published": True,
         }
         r = self.session.put(
-            self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+            self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/" + self.keyid),
             data=json.dumps(payload2),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
@@ -262,16 +268,17 @@ class Cryptokeys(ApiTestCase):
         self.assertIn("Active", out)
 
     def test_put_unpublish_key(self):
-        self.keyid = self.add_zone_key(status=['active'])
+        self.keyid = self.add_zone_key(status=["active"])
 
         payload = {
-            'active': True,
-            'published': False,
+            "active": True,
+            "published": False,
         }
         r = self.session.put(
-            self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+            self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/" + self.keyid),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
@@ -280,17 +287,18 @@ class Cryptokeys(ApiTestCase):
         self.assertIn("Unpublished", out)
 
     def test_put_publish_key(self):
-        self.keyid = self.add_zone_key(status=['active', 'unpublished'])
+        self.keyid = self.add_zone_key(status=["active", "unpublished"])
         # deactivate key
         payload2 = {
-            'active': True,
-            'published': True,
+            "active": True,
+            "published": True,
         }
 
         r = self.session.put(
-            self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+            self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/" + self.keyid),
             data=json.dumps(payload2),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
@@ -299,18 +307,19 @@ class Cryptokeys(ApiTestCase):
         self.assertIn("Published", out)
 
     def test_put_publish_published_key(self):
-        self.keyid = self.add_zone_key(status=['active'])
+        self.keyid = self.add_zone_key(status=["active"])
 
         # deactivate key
         payload = {
-            'active': True,
-            'published': True,
+            "active": True,
+            "published": True,
         }
 
         r = self.session.put(
-            self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+            self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/" + self.keyid),
             data=json.dumps(payload),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
@@ -319,17 +328,18 @@ class Cryptokeys(ApiTestCase):
         self.assertIn("Published", out)
 
     def test_put_unpublish_unpublished_key(self):
-        self.keyid = self.add_zone_key(status=['active', 'unpublished'])
+        self.keyid = self.add_zone_key(status=["active", "unpublished"])
 
         # activate key
         payload2 = {
-            'active': True,
-            'published': False,
+            "active": True,
+            "published": False,
         }
         r = self.session.put(
-            self.url("/api/v1/servers/localhost/zones/"+self.zone+"/cryptokeys/"+self.keyid),
+            self.url("/api/v1/servers/localhost/zones/" + self.zone + "/cryptokeys/" + self.keyid),
             data=json.dumps(payload2),
-            headers={'content-type': 'application/json'})
+            headers={"content-type": "application/json"},
+        )
         self.assertEqual(r.status_code, 204)
         self.assertEqual(r.content, b"")
 
index 4b412468b66602fe83e3b384eea07d2bb19d853d..616896d8e2ea34d69bef7067e950f4d1759f4520 100644 (file)
@@ -14,33 +14,36 @@ if sys.version_info[0] == 2:
 else:
     from urllib.parse import urljoin
 
-DAEMON = os.environ.get('DAEMON', 'authoritative')
-PDNSUTIL_CMD = os.environ.get('PDNSUTIL_CMD', 'NOT_SET BUT_THIS MIGHT_BE_A_LIST').split(' ')
-BACKEND =  os.environ.get('BACKEND', 'gsqlite3')
-MYSQL_DB = os.environ.get('MYSQL_DB', 'pdnsapi')
-MYSQL_USER = os.environ.get('MYSQL_USER', 'root')
-MYSQL_HOST = os.environ.get('MYSQL_HOST', 'localhost')
-MYSQL_PASSWD = os.environ.get('MYSQL_PASWORD', '')
-PGSQL_DB = os.environ.get('PGSQL_DB', 'pdnsapi')
-SQLITE_DB = os.environ.get('SQLITE_DB', 'pdns.sqlite3')
-LMDB_DB = os.environ.get('SQLITE_DB', 'pdns.lmdb')
-SDIG = os.environ.get('SDIG', 'sdig')
-DNSPORT = os.environ.get('DNSPORT', '53')
+DAEMON = os.environ.get("DAEMON", "authoritative")
+PDNSUTIL_CMD = os.environ.get("PDNSUTIL_CMD", "NOT_SET BUT_THIS MIGHT_BE_A_LIST").split(" ")
+BACKEND = os.environ.get("BACKEND", "gsqlite3")
+MYSQL_DB = os.environ.get("MYSQL_DB", "pdnsapi")
+MYSQL_USER = os.environ.get("MYSQL_USER", "root")
+MYSQL_HOST = os.environ.get("MYSQL_HOST", "localhost")
+MYSQL_PASSWD = os.environ.get("MYSQL_PASWORD", "")
+PGSQL_DB = os.environ.get("PGSQL_DB", "pdnsapi")
+SQLITE_DB = os.environ.get("SQLITE_DB", "pdns.sqlite3")
+LMDB_DB = os.environ.get("SQLITE_DB", "pdns.lmdb")
+SDIG = os.environ.get("SDIG", "sdig")
+DNSPORT = os.environ.get("DNSPORT", "53")
 
-class ApiTestCase(unittest.TestCase):
 
+class ApiTestCase(unittest.TestCase):
     def setUp(self):
         # TODO: config
-        self.server_address = '127.0.0.1'
-        self.webServerBasicAuthPassword = 'something'
-        self.server_port = int(os.environ.get('WEBPORT', '5580'))
-        self.server_url = 'http://%s:%s/' % (self.server_address, self.server_port)
-        self.server_web_password = os.environ.get('WEBPASSWORD', 'MISSING')
+        self.server_address = "127.0.0.1"
+        self.webServerBasicAuthPassword = "something"
+        self.server_port = int(os.environ.get("WEBPORT", "5580"))
+        self.server_url = "http://%s:%s/" % (self.server_address, self.server_port)
+        self.server_web_password = os.environ.get("WEBPASSWORD", "MISSING")
         self.session = requests.Session()
-        self.session.headers = {'X-API-Key': os.environ.get('APIKEY', 'changeme-key'), 'Origin': 'http://%s:%s' % (self.server_address, self.server_port)}
+        self.session.headers = {
+            "X-API-Key": os.environ.get("APIKEY", "changeme-key"),
+            "Origin": "http://%s:%s" % (self.server_address, self.server_port),
+        }
         if is_recursor():
-            self.server_url = 'https://%s:%s/' % (self.server_address, self.server_port)
-            self.session.verify = 'ca.pem'
+            self.server_url = "https://%s:%s/" % (self.server_address, self.server_port)
+            self.session.verify = "ca.pem"
 
     def url(self, relative_url):
         return urljoin(self.server_url, relative_url)
@@ -51,11 +54,13 @@ class ApiTestCase(unittest.TestCase):
         except Exception:
             print(result.content)
             raise
-        self.assertEqual(result.headers['Content-Type'], 'application/json')
+        self.assertEqual(result.headers["Content-Type"], "application/json")
 
     def assert_error_json(self, result):
-        self.assertTrue(400 <= result.status_code < 600, "Response has not an error code "+str(result.status_code))
-        self.assertEqual(result.headers['Content-Type'], 'application/json', "Response status code "+str(result.status_code))
+        self.assertTrue(400 <= result.status_code < 600, "Response has not an error code " + str(result.status_code))
+        self.assertEqual(
+            result.headers["Content-Type"], "application/json", "Response status code " + str(result.status_code)
+        )
 
     def assert_success(self, result):
         try:
@@ -66,26 +71,30 @@ class ApiTestCase(unittest.TestCase):
 
 
 def unique_zone_name():
-    return 'test-' + datetime.now().strftime('%d%H%S%M%f') + '.org.'
+    return "test-" + datetime.now().strftime("%d%H%S%M%f") + ".org."
+
 
 def unique_tsigkey_name():
-    return 'test-' + datetime.now().strftime('%d%H%S%M%f') + '-key'
+    return "test-" + datetime.now().strftime("%d%H%S%M%f") + "-key"
+
 
 def is_auth():
-    return DAEMON == 'authoritative'
+    return DAEMON == "authoritative"
+
 
 def is_auth_lmdb():
-    return DAEMON == 'authoritative' and BACKEND == 'lmdb'
+    return DAEMON == "authoritative" and BACKEND == "lmdb"
+
 
 def is_recursor():
-    return DAEMON == 'recursor'
+    return DAEMON == "recursor"
 
 
 def get_auth_db():
     """Return Connection to Authoritative backend DB."""
-    if BACKEND == 'gmysql':
+    if BACKEND == "gmysql":
         return mysql.connector.connect(database=MYSQL_DB, user=MYSQL_USER, host=MYSQL_HOST, password=MYSQL_PASSWD), "%s"
-    elif BACKEND == 'gpgsql':
+    elif BACKEND == "gpgsql":
         return psycopg2.connect(database=PGSQL_DB), "%s"
     else:
         return sqlite3.Connection(SQLITE_DB), "?"
@@ -94,36 +103,49 @@ def get_auth_db():
 def get_db_records(zonename, qtype):
     db, placeholder = get_auth_db()
     cur = db.cursor()
-    cur.execute("""
+    cur.execute(
+        """
         SELECT name, type, content, ttl, ordername
         FROM records
-        WHERE type = """+placeholder+""" AND domain_id = (
-            SELECT id FROM domains WHERE name = """+placeholder+"""
-        )""", (qtype, zonename.rstrip('.')))
+        WHERE type = """
+        + placeholder
+        + """ AND domain_id = (
+            SELECT id FROM domains WHERE name = """
+        + placeholder
+        + """
+        )""",
+        (qtype, zonename.rstrip(".")),
+    )
     rows = cur.fetchall()
     cur.close()
     db.close()
-    recs = [{'name': row[0], 'type': row[1], 'content': row[2], 'ttl': row[3], 'ordername': row[4]} for row in rows]
+    recs = [{"name": row[0], "type": row[1], "content": row[2], "ttl": row[3], "ordername": row[4]} for row in rows]
     print("DB Records:", recs)
     return recs
 
 
 def pdnsutil(subcommand, *args):
     try:
-        return subprocess.check_output(PDNSUTIL_CMD + [subcommand] + list(args), close_fds=True).decode('ascii')
+        return subprocess.check_output(PDNSUTIL_CMD + [subcommand] + list(args), close_fds=True).decode("ascii")
     except subprocess.CalledProcessError as except_inst:
-        raise RuntimeError("pdnsutil %s %s failed: %s" % (subcommand, args, except_inst.output.decode('ascii', errors='replace')))
+        raise RuntimeError(
+            "pdnsutil %s %s failed: %s" % (subcommand, args, except_inst.output.decode("ascii", errors="replace"))
+        )
+
 
 def pdnsutil_rectify(zonename):
     """Run pdnsutil rectify-zone on the given zone."""
-    pdnsutil('rectify-zone', zonename)
+    pdnsutil("rectify-zone", zonename)
+
 
 def sdig(*args):
     if is_auth():
-        sdig_command_line = [SDIG, '127.0.0.1', str(DNSPORT)] + list(args)
+        sdig_command_line = [SDIG, "127.0.0.1", str(DNSPORT)] + list(args)
     else:
-        sdig_command_line = [SDIG, '127.0.0.1', str(DNSPORT)] + list(args) + ["recurse"]
+        sdig_command_line = [SDIG, "127.0.0.1", str(DNSPORT)] + list(args) + ["recurse"]
     try:
-        return subprocess.check_output(sdig_command_line).decode('utf-8')
+        return subprocess.check_output(sdig_command_line).decode("utf-8")
     except subprocess.CalledProcessError as except_inst:
-        raise RuntimeError("sdig %s failed: %s" % (sdig_command_line, except_inst.output.decode('ascii', errors='replace')))
+        raise RuntimeError(
+            "sdig %s failed: %s" % (sdig_command_line, except_inst.output.decode("ascii", errors="replace"))
+        )
index 16808cfe71cb84fec1e8a21321a924e350e13de3..b3db557b42921bce3829a47f5a784dc7c41efef8 100644 (file)
@@ -15,12 +15,13 @@ import dns.message
 
 from eqdnsmessage import AssertEqualDNSMessageMixin
 
+
 class AuthTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     """
     Setup auth required for the tests
     """
 
-    _confdir = 'auth'
+    _confdir = "auth"
     _authPort = 5300
 
     _backend = os.getenv("AUTH_BACKEND", "bind")
@@ -38,7 +39,8 @@ zone-cache-refresh-interval=1
 """,
         gsqlite3="""
 zone-cache-refresh-interval=0
-""")
+""",
+    )
 
     _config_params = []
 
@@ -66,7 +68,7 @@ distributor-threads=1"""
     #   - {soa} => value of _SOA
     #   - {prefix} value of _PREFIX
     _zones = {
-        'example.org': """
+        "example.org": """
 example.org.                 3600 IN SOA  {soa}
 example.org.                 3600 IN NS   ns1.example.org.
 example.org.                 3600 IN NS   ns2.example.org.
@@ -76,26 +78,26 @@ ns2.example.org.             3600 IN A    {prefix}.11
     }
 
     _zone_keys = {
-        'example.org': """
+        "example.org": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: Lt0v0Gol3pRUFM7fDdcy0IWN0O/MnEmVPA+VylL8Y4U=
         """,
     }
 
-    _auth_cmd = [os.environ['PDNS']]
-    if sys.platform != 'darwin':
-        _auth_cmd = ['authbind'] + _auth_cmd
+    _auth_cmd = [os.environ["PDNS"]]
+    if sys.platform != "darwin":
+        _auth_cmd = ["authbind"] + _auth_cmd
 
     _auth_env = {}
     _auths = {}
 
-    _PREFIX = os.environ['PREFIX']
-    _PDNS_MODULE_DIR = os.environ['PDNS_MODULE_DIR']
+    _PREFIX = os.environ["PREFIX"]
+    _PDNS_MODULE_DIR = os.environ["PDNS_MODULE_DIR"]
 
     @classmethod
     def maybeAddVariant(cls, zone):
-        if cls._backend_variants and cls._backend == 'lmdb':
+        if cls._backend_variants and cls._backend == "lmdb":
             return zone + "..variant"
         else:
             return zone
@@ -111,150 +113,153 @@ PrivateKey: Lt0v0Gol3pRUFM7fDdcy0IWN0O/MnEmVPA+VylL8Y4U=
 
     @classmethod
     def generateAuthZone(cls, confdir, zonename, zonecontent):
-        with open(os.path.join(confdir, '%s.zone' % zonename), 'w') as zonefile:
+        with open(os.path.join(confdir, "%s.zone" % zonename), "w") as zonefile:
             zonefile.write(zonecontent.format(prefix=cls._PREFIX, soa=cls._SOA))
 
     @classmethod
     def generateAuthNamedConf(cls, confdir, zones):
-        with open(os.path.join(confdir, 'named.conf'), 'w') as namedconf:
-            namedconf.write("""
+        with open(os.path.join(confdir, "named.conf"), "w") as namedconf:
+            namedconf.write(
+                """
 options {
     directory "%s";
-};""" % confdir)
+};"""
+                % confdir
+            )
             for zonename in zones:
-                zone = '.' if zonename == 'ROOT' else zonename
+                zone = "." if zonename == "ROOT" else zonename
 
-                namedconf.write("""
+                namedconf.write(
+                    """
         zone "%s" {
             type primary;
             file "%s.zone";
-        };""" % (zone, zonename))
+        };"""
+                    % (zone, zonename)
+                )
 
     @classmethod
     def generateAuthConfig(cls, confdir):
-        bind_dnssec_db = os.path.join(confdir, 'bind-dnssec.sqlite3')
+        bind_dnssec_db = os.path.join(confdir, "bind-dnssec.sqlite3")
 
         params = tuple([getattr(cls, param) for param in cls._config_params])
 
-        with open(os.path.join(confdir, 'pdns.conf'), 'w') as pdnsconf:
-            args = dict(backend=cls._backend,
-                        confdir=confdir,
-                        prefix=cls._PREFIX,
-                        bind_dnssec_db=bind_dnssec_db,
-                        PDNS_MODULE_DIR=cls._PDNS_MODULE_DIR
-                        )
+        with open(os.path.join(confdir, "pdns.conf"), "w") as pdnsconf:
+            args = dict(
+                backend=cls._backend,
+                confdir=confdir,
+                prefix=cls._PREFIX,
+                bind_dnssec_db=bind_dnssec_db,
+                PDNS_MODULE_DIR=cls._PDNS_MODULE_DIR,
+            )
 
             pdnsconf.write((cls._config_template_default + cls._backend_configs[cls._backend]).format(**args))
             pdnsconf.write(cls._config_template.format(**args) % params)
 
-        if cls._backend == 'gsqlite3':
+        if cls._backend == "gsqlite3":
             os.system("sqlite3 ./configs/auth/powerdns.sqlite < ../modules/gsqlite3backend/schema.sqlite3.sql")
 
-        if cls._backend == 'lmdb':
+        if cls._backend == "lmdb":
             os.system("rm -f pdns.lmdb*")
 
-        if cls._backend == 'bind':
-            pdnsutilCmd = [os.environ['PDNSUTIL'],
-                           '--config-dir=%s' % confdir,
-                           'create-bind-db',
-                           bind_dnssec_db]
+        if cls._backend == "bind":
+            pdnsutilCmd = [os.environ["PDNSUTIL"], "--config-dir=%s" % confdir, "create-bind-db", bind_dnssec_db]
 
-            print(' '.join(pdnsutilCmd))
+            print(" ".join(pdnsutilCmd))
             try:
                 subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
             except subprocess.CalledProcessError as e:
-                raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+                raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
     @classmethod
     def secureZone(cls, confdir, zonename, key=None):
-        zone = '.' if zonename == 'ROOT' else zonename
+        zone = "." if zonename == "ROOT" else zonename
         if not key:
-            pdnsutilCmd = [os.environ['PDNSUTIL'],
-                           '--config-dir=%s' % confdir,
-                           'secure-zone',
-                           cls.maybeAddVariant(zone)]
+            pdnsutilCmd = [
+                os.environ["PDNSUTIL"],
+                "--config-dir=%s" % confdir,
+                "secure-zone",
+                cls.maybeAddVariant(zone),
+            ]
         else:
-            keyfile = os.path.join(confdir, 'dnssec.key')
-            with open(keyfile, 'w') as fdKeyfile:
+            keyfile = os.path.join(confdir, "dnssec.key")
+            with open(keyfile, "w") as fdKeyfile:
                 fdKeyfile.write(key)
 
-            pdnsutilCmd = [os.environ['PDNSUTIL'],
-                           '--config-dir=%s' % confdir,
-                           'import-zone-key',
-                           cls.maybeAddVariant(zone),
-                           keyfile,
-                           'active',
-                           'ksk']
-
-        print(' '.join(pdnsutilCmd))
+            pdnsutilCmd = [
+                os.environ["PDNSUTIL"],
+                "--config-dir=%s" % confdir,
+                "import-zone-key",
+                cls.maybeAddVariant(zone),
+                keyfile,
+                "active",
+                "ksk",
+            ]
+
+        print(" ".join(pdnsutilCmd))
         try:
             subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
     @classmethod
     def generateAllAuthConfig(cls, confdir):
         cls.generateAuthConfig(confdir)
 
-        if cls._backend == 'bind':
+        if cls._backend == "bind":
             cls.generateAuthNamedConf(confdir, cls._zones.keys())
 
             for zonename, zonecontent in cls._zones.items():
-                cls.generateAuthZone(confdir,
-                                     zonename,
-                                     zonecontent)
+                cls.generateAuthZone(confdir, zonename, zonecontent)
                 if cls._zone_keys.get(zonename, None):
                     cls.secureZone(confdir, zonename, cls._zone_keys.get(zonename))
-        elif cls._backend == 'lmdb':
+        elif cls._backend == "lmdb":
             for zonename, zonecontent in cls._zones.items():
-                cls.generateAuthZone(confdir,
-                                     zonename,
-                                     zonecontent)
-                pdnsutilCmd = [os.environ['PDNSUTIL'],
-                               '--config-dir=%s' % confdir,
-                               'load-zone',
-                               cls.maybeAddVariant(zonename),
-                               os.path.join(confdir, '%s.zone' % zonename)]
-
-                print(' '.join(pdnsutilCmd))
+                cls.generateAuthZone(confdir, zonename, zonecontent)
+                pdnsutilCmd = [
+                    os.environ["PDNSUTIL"],
+                    "--config-dir=%s" % confdir,
+                    "load-zone",
+                    cls.maybeAddVariant(zonename),
+                    os.path.join(confdir, "%s.zone" % zonename),
+                ]
+
+                print(" ".join(pdnsutilCmd))
                 try:
                     subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
                 except subprocess.CalledProcessError as e:
-                    raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+                    raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
                 if cls._zone_keys.get(zonename, None):
                     cls.secureZone(confdir, zonename, cls._zone_keys.get(zonename))
 
-                pdnsutilCmd = [os.environ['PDNSUTIL'],
-                               '--config-dir=%s' % confdir,
-                               'view-add-zone',
-                               'one-view',
-                               cls.maybeAddVariant(zonename)]
-                print(' '.join(pdnsutilCmd))
+                pdnsutilCmd = [
+                    os.environ["PDNSUTIL"],
+                    "--config-dir=%s" % confdir,
+                    "view-add-zone",
+                    "one-view",
+                    cls.maybeAddVariant(zonename),
+                ]
+                print(" ".join(pdnsutilCmd))
                 try:
                     subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
                 except subprocess.CalledProcessError as e:
-                    raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
-
-            for net in ['0.0.0.0/0', '::/0']:
-                pdnsutilCmd = [os.environ['PDNSUTIL'],
-                               '--config-dir=%s' % confdir,
-                               'set-network',
-                               net,
-                               'one-view']
-                print(' '.join(pdnsutilCmd))
+                    raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
+
+            for net in ["0.0.0.0/0", "::/0"]:
+                pdnsutilCmd = [os.environ["PDNSUTIL"], "--config-dir=%s" % confdir, "set-network", net, "one-view"]
+                print(" ".join(pdnsutilCmd))
                 try:
                     subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
                 except subprocess.CalledProcessError as e:
-                    raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+                    raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
-        elif cls._backend == 'gsqlite3':
+        elif cls._backend == "gsqlite3":
             # this is not a supported config from the user, but some of the test_*.py files use gsqlite3
             return
         else:
             raise RuntimeError("unknown backend " + cls._backend + " specified")
 
-
     @classmethod
     def waitForTCPSocket(cls, ipaddress, port):
         for try_number in range(0, 100):
@@ -266,7 +271,7 @@ options {
                 return
             except Exception as err:
                 if err.errno != errno.ECONNREFUSED:
-                    print(f'Error occurred: {try_number} {err}', file=sys.stderr)
+                    print(f"Error occurred: {try_number} {err}", file=sys.stderr)
             time.sleep(0.1)
 
     @classmethod
@@ -274,31 +279,31 @@ options {
 
         print("Launching pdns_server..")
         authcmd = list(cls._auth_cmd)
-        authcmd.append('--config-dir=%s' % confdir)
-        authcmd.append('--local-address=%s' % ipaddress)
-        authcmd.append('--local-port=%s' % cls._authPort)
-        authcmd.append('--loglevel=9')
-        print(' '.join(authcmd))
-        logFile = os.path.join(confdir, 'pdns.log')
-        with open(logFile, 'w') as fdLog:
-            cls._auths[ipaddress] = subprocess.Popen(authcmd, close_fds=True,
-                                                     stdout=fdLog, stderr=fdLog,
-                                                     env=cls._auth_env)
+        authcmd.append("--config-dir=%s" % confdir)
+        authcmd.append("--local-address=%s" % ipaddress)
+        authcmd.append("--local-port=%s" % cls._authPort)
+        authcmd.append("--loglevel=9")
+        print(" ".join(authcmd))
+        logFile = os.path.join(confdir, "pdns.log")
+        with open(logFile, "w") as fdLog:
+            cls._auths[ipaddress] = subprocess.Popen(
+                authcmd, close_fds=True, stdout=fdLog, stderr=fdLog, env=cls._auth_env
+            )
         cls.waitForTCPSocket(ipaddress, cls._authPort)
 
         if cls._auths[ipaddress].poll() is not None:
             print(f"\n*** startAuth log for {logFile} ***")
-            with open(logFile, 'r') as fdLog:
+            with open(logFile, "r") as fdLog:
                 print(fdLog.read())
             print(f"*** End startAuth log for {logFile} ***")
-            raise AssertionError('%s failed (%d)' % (authcmd, cls._auths[ipaddress].returncode))
+            raise AssertionError("%s failed (%d)" % (authcmd, cls._auths[ipaddress].returncode))
 
     @classmethod
     def setUpSockets(cls):
-         print("Setting up UDP socket..")
-         cls._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-         cls._sock.settimeout(2.0)
-         cls._sock.connect((cls._PREFIX + ".1", cls._authPort))
+        print("Setting up UDP socket..")
+        cls._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+        cls._sock.settimeout(2.0)
+        cls._sock.connect((cls._PREFIX + ".1", cls._authPort))
 
     @classmethod
     def startResponders(cls):
@@ -310,7 +315,7 @@ options {
 
         cls.startResponders()
 
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         cls.createConfigDir(confdir)
 
         cls.generateAllAuthConfig(confdir)
@@ -477,10 +482,10 @@ options {
         missingEdnsFlags = [ednsflag for ednsflag in ednsflags if ednsflag not in msgEdnsFlags]
 
         if len(missingFlags) or len(missingEdnsFlags) or len(msgFlags) > len(flags):
-            raise AssertionError("Expected flags '%s' (EDNS: '%s'), found '%s' (EDNS: '%s') in query %s" %
-                                 (' '.join(flags), ' '.join(ednsflags),
-                                  ' '.join(msgFlags), ' '.join(msgEdnsFlags),
-                                  msg.question[0]))
+            raise AssertionError(
+                "Expected flags '%s' (EDNS: '%s'), found '%s' (EDNS: '%s') in query %s"
+                % (" ".join(flags), " ".join(ednsflags), " ".join(msgFlags), " ".join(msgEdnsFlags), msg.question[0])
+            )
 
     def assertMessageIsAuthenticated(self, msg):
         """Asserts that the message has the AD bit set
@@ -491,7 +496,7 @@ options {
             raise TypeError("msg is not a dns.message.Message")
 
         msgFlags = dns.flags.to_text(msg.flags)
-        self.assertIn('AD', msgFlags, "No AD flag found in the message for %s" % msg.question[0].name)
+        self.assertIn("AD", msgFlags, "No AD flag found in the message for %s" % msg.question[0].name)
 
     def assertRRsetInAnswer(self, msg, rrset):
         """Asserts the rrset (without comparing TTL) exists in the
@@ -500,7 +505,7 @@ options {
         @param msg: the dns.message.Message to check
         @param rrset: a dns.rrset.RRset object"""
 
-        ret = ''
+        ret = ""
         if not isinstance(msg, dns.message.Message):
             raise TypeError("msg is not a dns.message.Message")
 
@@ -524,7 +529,7 @@ options {
         @param msg: the dns.message.Message to check
         @param rrset: a dns.rrset.RRset object"""
 
-        ret = ''
+        ret = ""
         if not isinstance(msg, dns.message.Message):
             raise TypeError("msg is not a dns.message.Message")
 
@@ -568,8 +573,7 @@ options {
                         found = True
 
         if not found:
-            raise AssertionError("RRset not found in answer\n%s" %
-                                 "\n".join(([ans.to_text() for ans in msg.answer])))
+            raise AssertionError("RRset not found in answer\n%s" % "\n".join(([ans.to_text() for ans in msg.answer])))
 
     def assertNoneRRsetInAnswer(self, msg, rrsets):
         """Asserts that none of the supplied rrsets exist (without comparing TTL)
@@ -591,8 +595,9 @@ options {
                         found = True
 
         if found:
-            raise AssertionError("RRset incorrectly found in answer\n%s" %
-                                 "\n".join(([ans.to_text() for ans in msg.answer])))
+            raise AssertionError(
+                "RRset incorrectly found in answer\n%s" % "\n".join(([ans.to_text() for ans in msg.answer]))
+            )
 
     def assertMatchingRRSIGInAnswer(self, msg, coveredRRset, keys=None):
         """Looks for coveredRRset in the answer section and if there is an RRSIG RRset
@@ -612,7 +617,7 @@ options {
         msgRRsigRRSet = None
         msgRRSet = None
 
-        ret = ''
+        ret = ""
         for ans in msg.answer:
             ret += ans.to_text() + "\n"
 
@@ -627,7 +632,9 @@ options {
             raise AssertionError("RRset for '%s' not found in answer" % msg.question[0].to_text())
 
         if not msgRRsigRRSet:
-            raise AssertionError("No RRSIGs found in answer for %s:\nFull answer:\n%s" % (msg.question[0].to_text(), ret))
+            raise AssertionError(
+                "No RRSIGs found in answer for %s:\nFull answer:\n%s" % (msg.question[0].to_text(), ret)
+            )
 
         if keys:
             try:
@@ -650,7 +657,12 @@ options {
             raise AssertionError("RRSIG found in answers for:\n%s" % ret)
 
     def assertAnswerEmpty(self, msg):
-        self.assertEqual(len(msg.answer), 0, "Data found in the answer section for %s:\n%s" % (msg.question[0].to_text(), '\n'.join([i.to_text() for i in msg.answer])))
+        self.assertEqual(
+            len(msg.answer),
+            0,
+            "Data found in the answer section for %s:\n%s"
+            % (msg.question[0].to_text(), "\n".join([i.to_text() for i in msg.answer])),
+        )
 
     def assertAnswerNotEmpty(self, msg):
         self.assertGreater(len(msg.answer), 0, "Answer is empty")
@@ -673,7 +685,9 @@ options {
                 msgRcode = msg.rcode()
                 wantedRcode = rcode
 
-            raise AssertionError("Rcode for %s is %s, expected %s." % (msg.question[0].to_text(), msgRcode, wantedRcode))
+            raise AssertionError(
+                "Rcode for %s is %s, expected %s." % (msg.question[0].to_text(), msgRcode, wantedRcode)
+            )
 
     def assertAuthorityHasSOA(self, msg):
         if not isinstance(msg, dns.message.Message):
index bb7022362287f62c9853075f484b2ca3c8d271e2..d8c2cac8bedce15ef8bcd419b59f214da5cfa102 100644 (file)
 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-""" Class to implement draft-ietf-dnsop-edns-client-subnet (previously known as
+"""Class to implement draft-ietf-dnsop-edns-client-subnet (previously known as
 draft-vandergaast-edns-client-subnet.
 
 The contained class supports both IPv4 and IPv6 addresses.
 Requirements:
   dnspython (http://www.dnspython.org/)
 """
+
 from __future__ import print_function
 from __future__ import division
 
@@ -77,11 +78,11 @@ class ClientSubnetOption(dns.edns.Option):
                 n = socket.inet_pton(family, ip)
                 if family == socket.AF_INET6:
                     f = FAMILY_IPV6
-                    hi, lo = struct.unpack('!QQ', n)
+                    hi, lo = struct.unpack("!QQ", n)
                     ip = hi << 64 | lo
                 elif family == socket.AF_INET:
                     f = FAMILY_IPV4
-                    ip = struct.unpack('!L', n)[0]
+                    ip = struct.unpack("!L", n)[0]
             except Exception:
                 pass
 
@@ -117,13 +118,13 @@ class ClientSubnetOption(dns.edns.Option):
 
         ip = self.ip >> bits - self.mask
 
-        if (self.mask % 8 != 0):
+        if self.mask % 8 != 0:
             ip = ip << 8 - (self.mask % 8)
 
         return ip
 
     def is_draft(self):
-        """" Determines whether this instance is using the draft option code """
+        """ " Determines whether this instance is using the draft option code"""
         return self.option == DRAFT_OPTION_CODE
 
     def to_wire(self, file=None):
@@ -133,13 +134,13 @@ class ClientSubnetOption(dns.edns.Option):
 
         mask_bits = self.mask
         if mask_bits % 8 != 0:
-                mask_bits += 8 - (self.mask % 8)
+            mask_bits += 8 - (self.mask % 8)
 
         if self.family == FAMILY_IPV4:
             test = struct.pack("!L", ip)
         elif self.family == FAMILY_IPV6:
-            test = struct.pack("!QQ", ip >> 64, ip & (2 ** 64 - 1))
-        test = test[-(mask_bits // 8):]
+            test = struct.pack("!QQ", ip >> 64, ip & (2**64 - 1))
+        test = test[-(mask_bits // 8) :]
 
         format = "!HBB%ds" % (mask_bits // 8)
         data = struct.pack(format, self.family, self.mask, self.scope, test)
@@ -155,7 +156,7 @@ class ClientSubnetOption(dns.edns.Option):
             An instance of ClientSubnetOption based on the ENDS packet
         """
 
-        data = wire[current:current + olen]
+        data = wire[current : current + olen]
         (family, mask, scope) = struct.unpack("!HBB", data[:4])
 
         c_mask = mask
@@ -164,11 +165,11 @@ class ClientSubnetOption(dns.edns.Option):
 
         ip = struct.unpack_from("!%ds" % (c_mask // 8), data, 4)[0]
 
-        if (family == FAMILY_IPV4):
-            ip = ip + b'\0' * ((32 - c_mask) // 8)
+        if family == FAMILY_IPV4:
+            ip = ip + b"\0" * ((32 - c_mask) // 8)
             ip = socket.inet_ntop(socket.AF_INET, ip)
-        elif (family == FAMILY_IPV6):
-            ip = ip + b'\0' * ((128 - c_mask) // 8)
+        elif family == FAMILY_IPV6:
+            ip = ip + b"\0" * ((128 - c_mask) // 8)
             ip = socket.inet_ntop(socket.AF_INET6, ip)
         else:
             raise Exception("Returned a family other then IPv4 or IPv6")
@@ -180,35 +181,27 @@ class ClientSubnetOption(dns.edns.Option):
     # needed in 2.0.0..
     @classmethod
     def from_wire_parser(cls, otype, parser):
-        family, src, scope = parser.get_struct('!HBB')
+        family, src, scope = parser.get_struct("!HBB")
         addrlen = int(math.ceil(src / 8.0))
         prefix = parser.get_bytes(addrlen)
         if family == 1:
             pad = 4 - addrlen
-            addr = dns.ipv4.inet_ntoa(prefix + b'\x00' * pad)
+            addr = dns.ipv4.inet_ntoa(prefix + b"\x00" * pad)
         elif family == 2:
             pad = 16 - addrlen
-            addr = dns.ipv6.inet_ntoa(prefix + b'\x00' * pad)
+            addr = dns.ipv6.inet_ntoa(prefix + b"\x00" * pad)
         else:
-            raise ValueError('unsupported family')
+            raise ValueError("unsupported family")
 
         return cls(addr, src, scope, otype)
 
     def __repr__(self):
         if self.family == FAMILY_IPV4:
-            ip = socket.inet_ntop(socket.AF_INET, struct.pack('!L', self.ip))
+            ip = socket.inet_ntop(socket.AF_INET, struct.pack("!L", self.ip))
         elif self.family == FAMILY_IPV6:
-            ip = socket.inet_ntop(socket.AF_INET6,
-                                  struct.pack('!QQ',
-                                              self.ip >> 64,
-                                              self.ip & (2 ** 64 - 1)))
-
-        return "%s(%s, %s, %s)" % (
-            self.__class__.__name__,
-            ip,
-            self.mask,
-            self.scope
-        )
+            ip = socket.inet_ntop(socket.AF_INET6, struct.pack("!QQ", self.ip >> 64, self.ip & (2**64 - 1)))
+
+        return "%s(%s, %s, %s)" % (self.__class__.__name__, ip, self.mask, self.scope)
 
     def to_text(self):
         return self.__repr__()
@@ -282,13 +275,25 @@ if __name__ == "__main__":
                 print("Found ClientSubnetOption...", end=None, file=sys.stderr)
                 if not cso.family == options.family:
                     error = True
-                    print("\nFailed: returned family (%d) is different from the passed family (%d)" % (options.family, cso.family), file=sys.stderr)
+                    print(
+                        "\nFailed: returned family (%d) is different from the passed family (%d)"
+                        % (options.family, cso.family),
+                        file=sys.stderr,
+                    )
                 if not cso.calculate_ip() == options.calculate_ip():
                     error = True
-                    print("\nFailed: returned ip (%s) is different from the passed ip (%s)." % (options.calculate_ip(), cso.calculate_ip()), file=sys.stderr)
+                    print(
+                        "\nFailed: returned ip (%s) is different from the passed ip (%s)."
+                        % (options.calculate_ip(), cso.calculate_ip()),
+                        file=sys.stderr,
+                    )
                 if not options.mask == cso.mask:
                     error = True
-                    print("\nFailed: returned mask bits (%d) is different from the passed mask bits (%d)" % (options.mask, cso.mask), file=sys.stderr)
+                    print(
+                        "\nFailed: returned mask bits (%d) is different from the passed mask bits (%d)"
+                        % (options.mask, cso.mask),
+                        file=sys.stderr,
+                    )
                 if not options.scope != 0:
                     print("\nWarning: scope indicates edns-clientsubnet data is not used", file=sys.stderr)
                 if options.is_draft():
@@ -301,17 +306,19 @@ if __name__ == "__main__":
         else:
             print("Failed: No ClientSubnetOption returned", file=sys.stderr)
 
-    parser = argparse.ArgumentParser(description='draft-vandergaast-edns-client-subnet-01 tester')
-    parser.add_argument('nameserver', help='The nameserver to test')
-    parser.add_argument('rr', help='DNS record that should return an EDNS enabled response')
-    parser.add_argument('-s', '--subnet', help='Specifies an IP to pass as the client subnet.', default='192.0.2.0')
-    parser.add_argument('-m', '--mask', type=int, help='CIDR mask to use for subnet')
-    parser.add_argument('--timeout', type=int, help='Set the timeout for query to TIMEOUT seconds, default=10', default=10)
-    parser.add_argument('-t', '--type', help='DNS query type, default=A', default='A')
+    parser = argparse.ArgumentParser(description="draft-vandergaast-edns-client-subnet-01 tester")
+    parser.add_argument("nameserver", help="The nameserver to test")
+    parser.add_argument("rr", help="DNS record that should return an EDNS enabled response")
+    parser.add_argument("-s", "--subnet", help="Specifies an IP to pass as the client subnet.", default="192.0.2.0")
+    parser.add_argument("-m", "--mask", type=int, help="CIDR mask to use for subnet")
+    parser.add_argument(
+        "--timeout", type=int, help="Set the timeout for query to TIMEOUT seconds, default=10", default=10
+    )
+    parser.add_argument("-t", "--type", help="DNS query type, default=A", default="A")
     args = parser.parse_args()
 
     if not args.mask:
-        if ':' in args.subnet:
+        if ":" in args.subnet:
             args.mask = 48
         else:
             args.mask = 24
index 766e3e831ea1b7961d29ed8d94985719ad44257b..6c899188d4f4b4d867088eed48b97629ca05b37c 100644 (file)
@@ -23,10 +23,10 @@ launch={backend}
 edns-subnet-processing=yes
 """
 
-    _config_params = ['_PREFIX']
+    _config_params = ["_PREFIX"]
 
     _zones = {
-        'example.org': """
+        "example.org": """
 example.org.                 3600 IN SOA  {soa}
 example.org.                 3600 IN NS   ns1.example.org.
 example.org.                 3600 IN NS   ns2.example.org.
@@ -45,7 +45,7 @@ subnetwrong.example.org.     3600 IN ALIAS subnetwrong.example.com.
     def startResponders(cls):
         global aliasUDPReactorRunning
 
-        address = cls._PREFIX + '.1'
+        address = cls._PREFIX + ".1"
         port = 5301
 
         if not aliasUDPReactorRunning:
@@ -54,199 +54,180 @@ subnetwrong.example.org.     3600 IN ALIAS subnetwrong.example.com.
             aliasUDPReactorRunning = True
 
         if not reactor.running:
-            cls._ALIASResponder = threading.Thread(name='ALIAS Responder',
-                                                   target=reactor.run,
-                                                   args=(False,))
+            cls._ALIASResponder = threading.Thread(name="ALIAS Responder", target=reactor.run, args=(False,))
             cls._ALIASResponder.setDaemon(True)
             cls._ALIASResponder.start()
 
     def testNoError(self):
-        expected_a = [dns.rrset.from_text('noerror.example.org.',
-                                          0, dns.rdataclass.IN, 'A',
-                                          '192.0.2.1')]
-        expected_aaaa = [dns.rrset.from_text('noerror.example.org.',
-                                             0, dns.rdataclass.IN, 'AAAA',
-                                             '2001:DB8::1')]
-
-        query = dns.message.make_query('noerror.example.org', 'A')
+        expected_a = [dns.rrset.from_text("noerror.example.org.", 0, dns.rdataclass.IN, "A", "192.0.2.1")]
+        expected_aaaa = [dns.rrset.from_text("noerror.example.org.", 0, dns.rdataclass.IN, "AAAA", "2001:DB8::1")]
+
+        query = dns.message.make_query("noerror.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_a)
         self.assertEqual(len(res.options), 0)  # this checks that we don't invent ECS on non-ECS queries
 
-        query = dns.message.make_query('noerror.example.org', 'AAAA')
+        query = dns.message.make_query("noerror.example.org", "AAAA")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_aaaa)
 
-        query = dns.message.make_query('noerror.example.org', 'ANY')
+        query = dns.message.make_query("noerror.example.org", "ANY")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_a)
         self.assertAnyRRsetInAnswer(res, expected_aaaa)
 
         # NODATA
-        query = dns.message.make_query('noerror.example.org', 'MX')
+        query = dns.message.make_query("noerror.example.org", "MX")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(len(res.answer), 0)
 
     def testNxDomain(self):
-        query = dns.message.make_query('nxd.example.org', 'A')
+        query = dns.message.make_query("nxd.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
-        query = dns.message.make_query('nxd.example.org', 'AAAA')
+        query = dns.message.make_query("nxd.example.org", "AAAA")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
         # TODO this should actually return SOA + NS?
-        query = dns.message.make_query('nxd.example.org', 'ANY')
+        query = dns.message.make_query("nxd.example.org", "ANY")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
     def testServFail(self):
-        query = dns.message.make_query('servfail.example.org', 'A')
+        query = dns.message.make_query("servfail.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
-        query = dns.message.make_query('servfail.example.org', 'AAAA')
+        query = dns.message.make_query("servfail.example.org", "AAAA")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
         # TODO this should actually return SOA + NS?
-        query = dns.message.make_query('servfail.example.org', 'ANY')
+        query = dns.message.make_query("servfail.example.org", "ANY")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
     def testNoErrorTCP(self):
-        expected_a = [dns.rrset.from_text('noerror.example.org.',
-                                          0, dns.rdataclass.IN, 'A',
-                                          '192.0.2.1')]
-        expected_aaaa = [dns.rrset.from_text('noerror.example.org.',
-                                             0, dns.rdataclass.IN, 'AAAA',
-                                             '2001:DB8::1')]
-
-        query = dns.message.make_query('noerror.example.org', 'A')
+        expected_a = [dns.rrset.from_text("noerror.example.org.", 0, dns.rdataclass.IN, "A", "192.0.2.1")]
+        expected_aaaa = [dns.rrset.from_text("noerror.example.org.", 0, dns.rdataclass.IN, "AAAA", "2001:DB8::1")]
+
+        query = dns.message.make_query("noerror.example.org", "A")
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_a)
 
-        query = dns.message.make_query('noerror.example.org', 'AAAA')
+        query = dns.message.make_query("noerror.example.org", "AAAA")
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_aaaa)
 
-        query = dns.message.make_query('noerror.example.org', 'ANY')
+        query = dns.message.make_query("noerror.example.org", "ANY")
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_a)
         self.assertAnyRRsetInAnswer(res, expected_aaaa)
 
         # NODATA
-        query = dns.message.make_query('noerror.example.org', 'MX')
+        query = dns.message.make_query("noerror.example.org", "MX")
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(len(res.answer), 0)
 
     def testNxDomainTCP(self):
-        query = dns.message.make_query('nxd.example.org', 'A')
+        query = dns.message.make_query("nxd.example.org", "A")
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
-        query = dns.message.make_query('nxd.example.org', 'AAAA')
+        query = dns.message.make_query("nxd.example.org", "AAAA")
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
-        query = dns.message.make_query('nxd.example.org', 'ANY')
+        query = dns.message.make_query("nxd.example.org", "ANY")
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
     def testServFailTCP(self):
-        query = dns.message.make_query('servfail.example.org', 'A')
+        query = dns.message.make_query("servfail.example.org", "A")
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
-        query = dns.message.make_query('servfail.example.org', 'AAAA')
+        query = dns.message.make_query("servfail.example.org", "AAAA")
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
-        query = dns.message.make_query('servfail.example.org', 'ANY')
+        query = dns.message.make_query("servfail.example.org", "ANY")
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
     def testECS(self):
-        expected_a = [dns.rrset.from_text('subnet.example.org.',
-                                          0, dns.rdataclass.IN, 'A',
-                                          '192.0.2.1')]
-        expected_aaaa = [dns.rrset.from_text('subnet.example.org.',
-                                             0, dns.rdataclass.IN, 'AAAA',
-                                             '2001:DB8::1')]
-
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.0', 24)
-        ecso2 = clientsubnetoption.ClientSubnetOption('1.2.3.0', 24, 22)
-        query = dns.message.make_query('subnet.example.org', 'A', use_edns=True, options=[ecso])
+        expected_a = [dns.rrset.from_text("subnet.example.org.", 0, dns.rdataclass.IN, "A", "192.0.2.1")]
+        expected_aaaa = [dns.rrset.from_text("subnet.example.org.", 0, dns.rdataclass.IN, "AAAA", "2001:DB8::1")]
+
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.0", 24)
+        ecso2 = clientsubnetoption.ClientSubnetOption("1.2.3.0", 24, 22)
+        query = dns.message.make_query("subnet.example.org", "A", use_edns=True, options=[ecso])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_a)
         self.assertEqual(res.options[0], ecso2)
 
-        ecso = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64)
-        ecso2 = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64, 48)
-        query = dns.message.make_query('subnet.example.org', 'AAAA', use_edns=True, options=[ecso])
+        ecso = clientsubnetoption.ClientSubnetOption("2001:db8:db6:db5::", 64)
+        ecso2 = clientsubnetoption.ClientSubnetOption("2001:db8:db6:db5::", 64, 48)
+        query = dns.message.make_query("subnet.example.org", "AAAA", use_edns=True, options=[ecso])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_aaaa)
         self.assertEqual(res.options[0], ecso2)
 
     def testECSWrong(self):
-        expected_a = [dns.rrset.from_text('subnetwrong.example.org.',
-                                          0, dns.rdataclass.IN, 'A',
-                                          '192.0.2.1')]
-        expected_aaaa = [dns.rrset.from_text('subnetwrong.example.org.',
-                                             0, dns.rdataclass.IN, 'AAAA',
-                                             '2001:DB8::1')]
-
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.0', 24) # FIXME change all IPs to documentation space in this file
-        ecso2 = clientsubnetoption.ClientSubnetOption('1.2.3.0', 24, 22)
-        query = dns.message.make_query('subnetwrong.example.org', 'A', use_edns=True, options=[ecso])
+        expected_a = [dns.rrset.from_text("subnetwrong.example.org.", 0, dns.rdataclass.IN, "A", "192.0.2.1")]
+        expected_aaaa = [dns.rrset.from_text("subnetwrong.example.org.", 0, dns.rdataclass.IN, "AAAA", "2001:DB8::1")]
+
+        ecso = clientsubnetoption.ClientSubnetOption(
+            "1.2.3.0", 24
+        )  # FIXME change all IPs to documentation space in this file
+        ecso2 = clientsubnetoption.ClientSubnetOption("1.2.3.0", 24, 22)
+        query = dns.message.make_query("subnetwrong.example.org", "A", use_edns=True, options=[ecso])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_a)
         self.assertEqual(res.options[0], ecso2)
 
-        ecso = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64)
-        ecso2 = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64, 48)
-        query = dns.message.make_query('subnetwrong.example.org', 'AAAA', use_edns=True, options=[ecso])
+        ecso = clientsubnetoption.ClientSubnetOption("2001:db8:db6:db5::", 64)
+        ecso2 = clientsubnetoption.ClientSubnetOption("2001:db8:db6:db5::", 64, 48)
+        query = dns.message.make_query("subnetwrong.example.org", "AAAA", use_edns=True, options=[ecso])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_aaaa)
         self.assertEqual(res.options[0], ecso2)
 
     def testECSNone(self):
-        expected_a = [dns.rrset.from_text('noerror.example.org.',
-                                          0, dns.rdataclass.IN, 'A',
-                                          '192.0.2.1')]
-        expected_aaaa = [dns.rrset.from_text('noerror.example.org.',
-                                             0, dns.rdataclass.IN, 'AAAA',
-                                             '2001:DB8::1')]
-
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.0', 24)
-        ecso2 = clientsubnetoption.ClientSubnetOption('1.2.3.0', 24, 0)
-        query = dns.message.make_query('noerror.example.org', 'A', use_edns=True, options=[ecso])
+        expected_a = [dns.rrset.from_text("noerror.example.org.", 0, dns.rdataclass.IN, "A", "192.0.2.1")]
+        expected_aaaa = [dns.rrset.from_text("noerror.example.org.", 0, dns.rdataclass.IN, "AAAA", "2001:DB8::1")]
+
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.0", 24)
+        ecso2 = clientsubnetoption.ClientSubnetOption("1.2.3.0", 24, 0)
+        query = dns.message.make_query("noerror.example.org", "A", use_edns=True, options=[ecso])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_a)
         self.assertEqual(res.options[0], ecso2)
 
-        ecso = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64)
-        ecso2 = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64, 0)
-        query = dns.message.make_query('noerror.example.org', 'AAAA', use_edns=True, options=[ecso])
+        ecso = clientsubnetoption.ClientSubnetOption("2001:db8:db6:db5::", 64)
+        ecso2 = clientsubnetoption.ClientSubnetOption("2001:db8:db6:db5::", 64, 0)
+        query = dns.message.make_query("noerror.example.org", "AAAA", use_edns=True, options=[ecso])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected_aaaa)
         self.assertEqual(res.options[0], ecso2)
 
+
 class AliasUDPResponder(DatagramProtocol):
     def datagramReceived(self, datagram, address):
         request = dns.message.from_wire(datagram)
@@ -258,46 +239,44 @@ class AliasUDPResponder(DatagramProtocol):
         name = question.name
         name_text = name.to_text()
 
-        if name_text in ('noerror.example.com.', 'subnet.example.com.', 'subnetwrong.example.com.'):
-
+        if name_text in ("noerror.example.com.", "subnet.example.com.", "subnetwrong.example.com."):
             do_ecs = False
             do_ecs_wrong = False
-            if name_text == 'subnet.example.com.':
+            if name_text == "subnet.example.com.":
                 do_ecs = True
-            elif name_text == 'subnetwrong.example.com.':
+            elif name_text == "subnetwrong.example.com.":
                 do_ecs = True
                 do_ecs_wrong = True
 
             response.set_rcode(dns.rcode.NOERROR)
-            if question.rdtype in [dns.rdatatype.A,
-                                              dns.rdatatype.ANY]:
-                response.answer.append(
-                    dns.rrset.from_text(
-                        name,
-                        0, dns.rdataclass.IN, 'A', '192.0.2.1'))
-
-            if question.rdtype in [dns.rdatatype.AAAA,
-                                              dns.rdatatype.ANY]:
-                response.answer.append(
-                    dns.rrset.from_text(name,
-                                        0, dns.rdataclass.IN, 'AAAA',
-                                        '2001:DB8::1'))
+            if question.rdtype in [dns.rdatatype.A, dns.rdatatype.ANY]:
+                response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.1"))
+
+            if question.rdtype in [dns.rdatatype.AAAA, dns.rdatatype.ANY]:
+                response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, "AAAA", "2001:DB8::1"))
 
             if do_ecs:
                 if request.options[0].family == clientsubnetoption.FAMILY_IPV4:
-                    ecso = clientsubnetoption.ClientSubnetOption('5.6.7.0' if do_ecs_wrong else '1.2.3.0', 24, 22)
+                    ecso = clientsubnetoption.ClientSubnetOption("5.6.7.0" if do_ecs_wrong else "1.2.3.0", 24, 22)
                 else:
-                    ecso = clientsubnetoption.ClientSubnetOption('2600::' if do_ecs_wrong else '2001:db8:db6:db5::', 64, 48)
+                    ecso = clientsubnetoption.ClientSubnetOption(
+                        "2600::" if do_ecs_wrong else "2001:db8:db6:db5::", 64, 48
+                    )
                 response.use_edns(edns=True, options=[ecso])
 
-        if name_text == 'nxd.example.com.':
+        if name_text == "nxd.example.com.":
             response.set_rcode(dns.rcode.NXDOMAIN)
             response.authority.append(
                 dns.rrset.from_text(
-                    'example.com.',
-                    0, dns.rdataclass.IN, 'SOA', 'ns1.example.com. hostmaster.example.com. 2018062101 1 2 3 4'))
-
-        if name_text == 'servfail.example.com.':
+                    "example.com.",
+                    0,
+                    dns.rdataclass.IN,
+                    "SOA",
+                    "ns1.example.com. hostmaster.example.com. 2018062101 1 2 3 4",
+                )
+            )
+
+        if name_text == "servfail.example.com.":
             response.set_rcode(dns.rcode.SERVFAIL)
 
         self.transport.write(response.to_wire(max_size=65535), address)
index 1b85f3ebeb59d188d446860ade4d573ab3e2f6a7..e2f5690587b8372b8a8f881e53656f928b9d9062 100644 (file)
@@ -12,7 +12,7 @@ launch={backend}
 """
 
     _zones = {
-        'example.org': """
+        "example.org": """
 example.org.                 3600 IN SOA  {soa}
 example.org.                 3600 IN NS   ns1.example.org.
 example.org.                 3600 IN NS   ns2.example.org.
@@ -29,7 +29,7 @@ www.example.org.             3600 IN A    192.0.2.5
 
         cls.startResponders()
 
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         cls.createConfigDir(confdir)
 
         cls.generateAllAuthConfig(confdir)
@@ -39,13 +39,13 @@ www.example.org.             3600 IN A    192.0.2.5
 
     @classmethod
     def setUpSockets(cls):
-         print("Setting up UDP socket..")
-         cls._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-         cls._sock.settimeout(2.0)
-         cls._sock.connect((cls._PREFIX + ".2", cls._authPort))
+        print("Setting up UDP socket..")
+        cls._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+        cls._sock.settimeout(2.0)
+        cls._sock.connect((cls._PREFIX + ".2", cls._authPort))
 
     def testA(self):
         """Test to see if we get a reply from 127.0.0.2 if auth is bound to ANY address"""
-        query = dns.message.make_query('www.example.org', 'A')
+        query = dns.message.make_query("www.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, 0)
index c5faaa939da275cdc3710f3417d2f2962f3cde0e..4afe929a660c5051e12a7a03aa401d96d5c6ea6d 100644 (file)
@@ -7,7 +7,7 @@ from authtests import AuthTest
 
 
 class TestAuthSignal(AuthTest):
-    _backend = 'gsqlite3'
+    _backend = "gsqlite3"
 
     _config_template_default = """
 module-dir={PDNS_MODULE_DIR}
@@ -27,16 +27,17 @@ gsqlite3-database=configs/auth/powerdns.sqlite
 gsqlite3-pragma-foreign-keys=yes
 gsqlite3-dnssec=yes
 """
+
     @classmethod
     def setUpClass(cls):
         super().setUpClass()
-        cls.signaling_domain = dns.name.from_text('_signal.ns1.example.net')
-        cls.signaling_prefix = dns.name.from_text('_dsboot.cds-cdnskey.test').relativize(dns.name.root)
+        cls.signaling_domain = dns.name.from_text("_signal.ns1.example.net")
+        cls.signaling_prefix = dns.name.from_text("_dsboot.cds-cdnskey.test").relativize(dns.name.root)
         cls.signaling_qname = cls.signaling_prefix.concatenate(cls.signaling_domain)
 
         os.system("$PDNSUTIL --config-dir=configs/auth zone create _signal.ns1.example.net")
         os.system("$PDNSUTIL --config-dir=configs/auth zone set-signaling _signal.ns1.example.net")
-        query = dns.message.make_query('_signal.ns1.example.net', 'DNSKEY')
+        query = dns.message.make_query("_signal.ns1.example.net", "DNSKEY")
         res = cls.sendUDPQuery(query)
         cls.signaling_keytag = dns.dnssec.key_id(res.answer[0][0])
 
@@ -46,7 +47,7 @@ gsqlite3-dnssec=yes
         os.system("$PDNSUTIL --config-dir=configs/auth zone set-publish-cdnskey cds-cdnskey.test")
 
     def _signalingQuery(self, rdtype):
-        query = dns.message.make_query('cds-cdnskey.test', rdtype)
+        query = dns.message.make_query("cds-cdnskey.test", rdtype)
         res1 = self.sendUDPQuery(query)
 
         query = dns.message.make_query(self.signaling_qname, rdtype, use_edns=True, want_dnssec=True)
@@ -67,7 +68,10 @@ gsqlite3-dnssec=yes
         self.assertEqual(rrset1.to_rdataset(), rrset2.to_rdataset())
 
         # ... and signed by the signaling zone
-        rrsig_correct = any(rrset.rdtype == dns.rdatatype.RRSIG and rrset.covers == rdtype and rrset[0].key_tag == self.signaling_keytag for rrset in res2.answer)
+        rrsig_correct = any(
+            rrset.rdtype == dns.rdatatype.RRSIG and rrset.covers == rdtype and rrset[0].key_tag == self.signaling_keytag
+            for rrset in res2.answer
+        )
         self.assertTrue(rrsig_correct, f"RRSIG({rdtype}) with proper keytag not found")
 
     def testSignalingCDSQuery(self):
@@ -80,11 +84,11 @@ gsqlite3-dnssec=yes
         os.system("$PDNSUTIL --config-dir=configs/auth zone create no-signaling.test")
         os.system("$PDNSUTIL --config-dir=configs/auth zone secure no-signaling.test")
 
-        signaling_prefix = dns.name.from_text('_dsboot.no-signaling.test').relativize(dns.name.root)
+        signaling_prefix = dns.name.from_text("_dsboot.no-signaling.test").relativize(dns.name.root)
         qname = signaling_prefix.concatenate(self.signaling_domain)
         for rdtype, nsec3windows in {
-            dns.rdatatype.CDS: ((0, b'\x00\x00\x00\x00\x00\x02\x00\x08'),),  # RRSIG CDNSKEY
-            dns.rdatatype.CDNSKEY: ((0, b'\x00\x00\x00\x00\x00\x02\x00\x10'),)  # RRSIG CDS
+            dns.rdatatype.CDS: ((0, b"\x00\x00\x00\x00\x00\x02\x00\x08"),),  # RRSIG CDNSKEY
+            dns.rdatatype.CDNSKEY: ((0, b"\x00\x00\x00\x00\x00\x02\x00\x10"),),  # RRSIG CDS
         }.items():
             query = dns.message.make_query(qname, rdtype, use_edns=True, want_dnssec=True)
             res = self.sendUDPQuery(query)
@@ -102,7 +106,7 @@ gsqlite3-dnssec=yes
                     self.assertEqual(rrset.to_rdataset()[0].windows, nsec3windows)
 
     def testSignalingQueryNXDOMAIN(self):
-        signaling_prefix = dns.name.from_text('_dsboot.othername.test').relativize(dns.name.root)
+        signaling_prefix = dns.name.from_text("_dsboot.othername.test").relativize(dns.name.root)
         qname = signaling_prefix.concatenate(self.signaling_domain)
         for rdtype in (dns.rdatatype.CDS, dns.rdatatype.CDNSKEY):
             query = dns.message.make_query(qname, rdtype, use_edns=True, want_dnssec=True)
index 6aeadbcbf34ee1d196a0a9b4ce6c3e50dcf7afa5..afae932c4c3640756d2d2723b5f431b9ddb95fff 100644 (file)
@@ -7,9 +7,10 @@ from queue import Queue
 
 from authtests import AuthTest
 
+
 class TestCarbon(AuthTest):
-    _carbonNamespace = 'NS'
-    _carbonInstance = 'Instance'
+    _carbonNamespace = "NS"
+    _carbonInstance = "Instance"
     _carbonServerName = "carbonname1"
     _carbonInterval = 2
     _carbonServer1Port = 8000
@@ -24,7 +25,14 @@ class TestCarbon(AuthTest):
     carbon-interval=%s
     carbon-ourname=%s
     carbon-server=127.0.0.1:%s,127.0.01:%s
-    """ % (_carbonNamespace, _carbonInstance, _carbonInterval, _carbonServerName, _carbonServer1Port,  _carbonServer2Port)
+    """ % (
+        _carbonNamespace,
+        _carbonInstance,
+        _carbonInterval,
+        _carbonServerName,
+        _carbonServer1Port,
+        _carbonServer2Port,
+    )
 
     @classmethod
     def CarbonResponder(cls, port):
@@ -40,7 +48,7 @@ class TestCarbon(AuthTest):
         while True:
             (conn, _) = sock.accept()
             conn.settimeout(2.0)
-            lines = b''
+            lines = b""
             while True:
                 data = conn.recv(4096)
                 if not data:
@@ -60,11 +68,15 @@ class TestCarbon(AuthTest):
 
     @classmethod
     def startResponders(cls):
-        cls._CarbonResponder1 = threading.Thread(name='Carbon Responder 1', target=cls.CarbonResponder, args=[cls._carbonServer1Port])
+        cls._CarbonResponder1 = threading.Thread(
+            name="Carbon Responder 1", target=cls.CarbonResponder, args=[cls._carbonServer1Port]
+        )
         cls._CarbonResponder1.setDaemon(True)
         cls._CarbonResponder1.start()
 
-        cls._CarbonResponder2 = threading.Thread(name='Carbon Responder 2', target=cls.CarbonResponder, args=[cls._carbonServer2Port])
+        cls._CarbonResponder2 = threading.Thread(
+            name="Carbon Responder 2", target=cls.CarbonResponder, args=[cls._carbonServer2Port]
+        )
         cls._CarbonResponder2.setDaemon(True)
         cls._CarbonResponder2.start()
 
@@ -86,10 +98,14 @@ class TestCarbon(AuthTest):
 
         self.assertTrue(data1)
         self.assertGreater(len(data1.splitlines()), 1)
-        expectedStart = b"%s.%s.%s." % (self._carbonNamespace.encode('UTF8'), self._carbonServerName.encode('UTF-8'), self._carbonInstance.encode('UTF8'))
+        expectedStart = b"%s.%s.%s." % (
+            self._carbonNamespace.encode("UTF8"),
+            self._carbonServerName.encode("UTF-8"),
+            self._carbonInstance.encode("UTF8"),
+        )
         for line in data1.splitlines():
             self.assertTrue(line.startswith(expectedStart))
-            parts = line.split(b' ')
+            parts = line.split(b" ")
             self.assertEqual(len(parts), 3)
             self.assertTrue(parts[1].isdigit())
             self.assertTrue(parts[2].isdigit())
@@ -97,10 +113,14 @@ class TestCarbon(AuthTest):
 
         self.assertTrue(data2)
         self.assertGreater(len(data2.splitlines()), 1)
-        expectedStart = b"%s.%s.%s." % (self._carbonNamespace.encode('UTF8'), self._carbonServerName.encode('UTF-8'), self._carbonInstance.encode('UTF8'))
+        expectedStart = b"%s.%s.%s." % (
+            self._carbonNamespace.encode("UTF8"),
+            self._carbonServerName.encode("UTF-8"),
+            self._carbonInstance.encode("UTF8"),
+        )
         for line in data2.splitlines():
             self.assertTrue(line.startswith(expectedStart))
-            parts = line.split(b' ')
+            parts = line.split(b" ")
             self.assertEqual(len(parts), 3)
             self.assertTrue(parts[1].isdigit())
             self.assertTrue(parts[2].isdigit())
@@ -110,4 +130,3 @@ class TestCarbon(AuthTest):
         for key in self._carbonCounters:
             value = self._carbonCounters[key]
             self.assertGreaterEqual(value, 1)
-
index 3d7828de92b125b5ea7f45fad55eb31cbeb43cfb..7bb009965720f9a3ea65d686e0efd5a6eb25e618 100644 (file)
@@ -5,6 +5,7 @@ import dns.message
 
 from authtests import AuthTest
 
+
 class TestEdnsCookies(AuthTest):
     _config_template = """
 launch={backend}
@@ -12,7 +13,7 @@ edns-cookie-secret=aabbccddeeff11223344556677889900
 """
 
     _zones = {
-        'example.org': """
+        "example.org": """
 example.org.                 3600 IN SOA  {soa}
 example.org.                 3600 IN NS   ns1.example.org.
 example.org.                 3600 IN NS   ns2.example.org.
@@ -26,14 +27,11 @@ www.example.org.             3600 IN A    192.0.2.5
     def sendAndExpectNoCookie(self, msg, rcode):
         res = self.sendUDPQuery(msg)
         self.assertRcodeEqual(res, rcode)
-        self.assertFalse(any([opt.otype == dns.edns.COOKIE for
-                              opt in res.options]))
+        self.assertFalse(any([opt.otype == dns.edns.COOKIE for opt in res.options]))
 
     def getCookieFromServer(self):
-        opts = [
-            dns.edns.GenericOption(dns.edns.COOKIE,
-                                   b'\x22\x11\x33\x44\x55\x66\x77\x88')]
-        query = dns.message.make_query('www.example.org', 'A', options=opts)
+        opts = [dns.edns.GenericOption(dns.edns.COOKIE, b"\x22\x11\x33\x44\x55\x66\x77\x88")]
+        query = dns.message.make_query("www.example.org", "A", options=opts)
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, 23)  # BADCOOKIE
         for opt in res.options:
@@ -43,66 +41,57 @@ www.example.org.             3600 IN A    192.0.2.5
         return None
 
     def testNoCookie(self):
-        query = dns.message.make_query('www.example.org', 'A', use_edns=0)
+        query = dns.message.make_query("www.example.org", "A", use_edns=0)
         self.sendAndExpectNoCookie(query, dns.rcode.NOERROR)
 
     def testClientCookieTooShort(self):
-        opts = [dns.edns.GenericOption(dns.edns.COOKIE, b'\x22')]
-        query = dns.message.make_query('www.example.org', 'A', options=opts)
+        opts = [dns.edns.GenericOption(dns.edns.COOKIE, b"\x22")]
+        query = dns.message.make_query("www.example.org", "A", options=opts)
         self.sendAndExpectNoCookie(query, dns.rcode.FORMERR)
 
-        opts = [dns.edns.GenericOption(dns.edns.COOKIE,
-                                       b'\x22\x11\x33\x44\x55\x66\x77')]
-        query = dns.message.make_query('www.example.org', 'A', options=opts)
+        opts = [dns.edns.GenericOption(dns.edns.COOKIE, b"\x22\x11\x33\x44\x55\x66\x77")]
+        query = dns.message.make_query("www.example.org", "A", options=opts)
         self.sendAndExpectNoCookie(query, dns.rcode.FORMERR)
 
     def testServerCookieTooShort(self):
-        opts = [
-            dns.edns.GenericOption(dns.edns.COOKIE,
-                                   b'\x22\x11\x33\x44\x55\x66\x77\x88\x99')]
-        query = dns.message.make_query('www.example.org', 'A', options=opts)
+        opts = [dns.edns.GenericOption(dns.edns.COOKIE, b"\x22\x11\x33\x44\x55\x66\x77\x88\x99")]
+        query = dns.message.make_query("www.example.org", "A", options=opts)
         self.sendAndExpectNoCookie(query, dns.rcode.FORMERR)
 
         opts = [
-            dns.edns.GenericOption(dns.edns.COOKIE,
-                                   b'\x22\x11\x33\x44\x55\x66\x77\x88' +
-                                   b'\x22\x11\x33\x44\x55\x66\x77')]
-        query = dns.message.make_query('www.example.org', 'A', options=opts)
+            dns.edns.GenericOption(
+                dns.edns.COOKIE, b"\x22\x11\x33\x44\x55\x66\x77\x88" + b"\x22\x11\x33\x44\x55\x66\x77"
+            )
+        ]
+        query = dns.message.make_query("www.example.org", "A", options=opts)
         self.sendAndExpectNoCookie(query, dns.rcode.FORMERR)
 
     def testOnlyClientCookie(self):
-        opts = [
-            dns.edns.GenericOption(dns.edns.COOKIE,
-                                   b'\x22\x11\x33\x44\x55\x66\x77\x88')]
-        query = dns.message.make_query('www.example.org', 'A', options=opts)
+        opts = [dns.edns.GenericOption(dns.edns.COOKIE, b"\x22\x11\x33\x44\x55\x66\x77\x88")]
+        query = dns.message.make_query("www.example.org", "A", options=opts)
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, 23)  # BADCOOKIE
-        self.assertTrue(any([opt.otype == dns.edns.COOKIE for
-                             opt in res.options]))
+        self.assertTrue(any([opt.otype == dns.edns.COOKIE for opt in res.options]))
 
     def testOnlyClientCookieTCP(self):
-        opts = [
-            dns.edns.GenericOption(dns.edns.COOKIE,
-                                   b'\x22\x11\x33\x44\x55\x66\x77\x88')]
-        query = dns.message.make_query('www.example.org', 'A', options=opts)
+        opts = [dns.edns.GenericOption(dns.edns.COOKIE, b"\x22\x11\x33\x44\x55\x66\x77\x88")]
+        query = dns.message.make_query("www.example.org", "A", options=opts)
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertTrue(any(opt.otype == dns.edns.COOKIE for
-                            opt in res.options))
-
+        self.assertTrue(any(opt.otype == dns.edns.COOKIE for opt in res.options))
 
     def testCorrectCookie(self):
         opts = [self.getCookieFromServer()]
-        query = dns.message.make_query('www.example.org', 'A', options=opts)
+        query = dns.message.make_query("www.example.org", "A", options=opts)
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testBrokenCookie(self):
         data = self.getCookieFromServer().to_wire()
         # replace a byte in the client cookie
-        data = data.replace(b'\x11', b'\x12')
+        data = data.replace(b"\x11", b"\x12")
         opts = [dns.edns.GenericOption(dns.edns.COOKIE, data)]
-        query = dns.message.make_query('www.example.org', 'A', options=opts)
+        query = dns.message.make_query("www.example.org", "A", options=opts)
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, 23)
         for opt in res.options:
@@ -111,6 +100,7 @@ www.example.org.             3600 IN A    192.0.2.5
                 return
         self.fail()
 
+
 class TestEdnsRandomCookies(TestEdnsCookies):
     _config_template = """
 launch={backend}
index b11a641ab5afefdb0ebd1f35bb766ab542af5b8e..bf16d155a9a189dd279dc92d3150f7d2eb9d99a0 100644 (file)
@@ -5,6 +5,7 @@ import os
 import socket
 from authtests import AuthTest
 
+
 class TestDirectDNSKEYSignature(AuthTest):
     _config_template = """
     launch={backend}
@@ -13,7 +14,7 @@ class TestDirectDNSKEYSignature(AuthTest):
     """
 
     _zones = {
-        'example.org': """
+        "example.org": """
 example.org.                 3600 IN SOA     {soa}
 example.org.                 3600 IN NS      ns1.example.org.
 example.org.                 3600 IN NS      ns2.example.org.
@@ -29,7 +30,7 @@ example.org.                 3600 IN RRSIG   DNSKEY 13 2 3600 20250118211239 202
     def setUpClass(cls):
         cls.setUpSockets()
         cls.startResponders()
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         cls.createConfigDir(confdir)
         cls.generateAllAuthConfig(confdir)
         cls.startAuth(confdir, "0.0.0.0")
@@ -44,7 +45,7 @@ example.org.                 3600 IN RRSIG   DNSKEY 13 2 3600 20250118211239 202
 
     def testDNSKEYQuery(self):
         """Test to verify DNSKEY and RRSIG records are served correctly"""
-        query = dns.message.make_query('example.org', 'DNSKEY', use_edns=True, want_dnssec=True)
+        query = dns.message.make_query("example.org", "DNSKEY", use_edns=True, want_dnssec=True)
         res = self.sendUDPQuery(query)
 
         # Ensure no error in response
@@ -55,12 +56,15 @@ example.org.                 3600 IN RRSIG   DNSKEY 13 2 3600 20250118211239 202
         self.assertTrue(dnskey_found, "DNSKEY record not found in the answer section")
 
         # Validate RRSIG record for DNSKEY
-        rrsig_found = any(rrset.rdtype == dns.rdatatype.RRSIG and rrset.covers == dns.rdatatype.DNSKEY and rrset[0].key_tag == 22273 for rrset in res.answer)
+        rrsig_found = any(
+            rrset.rdtype == dns.rdatatype.RRSIG and rrset.covers == dns.rdatatype.DNSKEY and rrset[0].key_tag == 22273
+            for rrset in res.answer
+        )
         self.assertTrue(rrsig_found, "RRSIG for DNSKEY not found in the answer section")
 
     def testDNSKEYQueryWithoutDNSSEC(self):
         """Test to ensure no RRSIG records are returned without the DNSSEC flag"""
-        query = dns.message.make_query('example.org', 'DNSKEY', use_edns=True, want_dnssec=False)
+        query = dns.message.make_query("example.org", "DNSKEY", use_edns=True, want_dnssec=False)
         res = self.sendUDPQuery(query)
 
         # Ensure no error in response
index f6df803568480ad5fa68d8f05a0155272b2f5641..3d08d837e0f20c0ed094d7c07db78fa5a1c44c57 100644 (file)
@@ -6,7 +6,7 @@ from authtests import AuthTest
 
 
 class GSSTSIGBase(AuthTest):
-    _backend = 'gsqlite3'
+    _backend = "gsqlite3"
 
     _config_template_default = """
 module-dir={PDNS_MODULE_DIR}
@@ -30,9 +30,7 @@ allow-dnsupdate-from=0.0.0.0/0
 dnsupdate=yes
 dnsupdate-require-tsig=no
 """
-    _auth_env = {'KRB5_CONFIG' : './kerberos-client/krb5.conf',
-                 'KRB5_KTNAME' : './kerberos-client/kt.keytab'
-                 }
+    _auth_env = {"KRB5_CONFIG": "./kerberos-client/krb5.conf", "KRB5_KTNAME": "./kerberos-client/kt.keytab"}
 
     @classmethod
     def secureZone(cls, confdir, zonename, key=None):
@@ -40,16 +38,13 @@ dnsupdate-require-tsig=no
         # all the other tests in that directory. Because of this, we
         # need to perform an explicit create-zone, otherwise import-zone-key
         # would fail.
-        zone = '.' if zonename == 'ROOT' else zonename
-        pdnsutilCmd = [os.environ['PDNSUTIL'],
-                       '--config-dir=%s' % confdir,
-                       'create-zone',
-                       zone]
-        print(' '.join(pdnsutilCmd))
+        zone = "." if zonename == "ROOT" else zonename
+        pdnsutilCmd = [os.environ["PDNSUTIL"], "--config-dir=%s" % confdir, "create-zone", zone]
+        print(" ".join(pdnsutilCmd))
         try:
             subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
         super(GSSTSIGBase, cls).secureZone(confdir, zonename, key)
 
     @classmethod
@@ -62,12 +57,22 @@ dnsupdate-require-tsig=no
         os.system("$PDNSUTIL --config-dir=configs/auth create-zone noacceptor.net")
         os.system("$PDNSUTIL --config-dir=configs/auth create-zone wrongacceptor.net")
 
-        os.system("$PDNSUTIL --config-dir=configs/auth replace-rrset example.net example.net SOA 3600 'ns1.example.net otto.example.net 2022010403 10800 3600 604800 3600'")
-        os.system("$PDNSUTIL --config-dir=configs/auth replace-rrset noacceptor.net noacceptor.net SOA 3600 'ns1.noacceptor.net otto.example.net 2022010403 10800 3600 604800 3600'")
-        os.system("$PDNSUTIL --config-dir=configs/auth replace-rrset wrongacceptor.net wrongacceptor.net SOA 3600 'ns1.wrongacceptor.net otto.example.net 2022010403 10800 3600 604800 3600'")
-
-        os.system("$PDNSUTIL --config-dir=configs/auth set-meta example.net GSS-ACCEPTOR-PRINCIPAL DNS/ns1.example.net@EXAMPLE.COM")
-        os.system("$PDNSUTIL --config-dir=configs/auth set-meta wrongacceptor.net GSS-ACCEPTOR-PRINCIPAL DNS/ns1.example.net@EXAMPLE.COM")
+        os.system(
+            "$PDNSUTIL --config-dir=configs/auth replace-rrset example.net example.net SOA 3600 'ns1.example.net otto.example.net 2022010403 10800 3600 604800 3600'"
+        )
+        os.system(
+            "$PDNSUTIL --config-dir=configs/auth replace-rrset noacceptor.net noacceptor.net SOA 3600 'ns1.noacceptor.net otto.example.net 2022010403 10800 3600 604800 3600'"
+        )
+        os.system(
+            "$PDNSUTIL --config-dir=configs/auth replace-rrset wrongacceptor.net wrongacceptor.net SOA 3600 'ns1.wrongacceptor.net otto.example.net 2022010403 10800 3600 604800 3600'"
+        )
+
+        os.system(
+            "$PDNSUTIL --config-dir=configs/auth set-meta example.net GSS-ACCEPTOR-PRINCIPAL DNS/ns1.example.net@EXAMPLE.COM"
+        )
+        os.system(
+            "$PDNSUTIL --config-dir=configs/auth set-meta wrongacceptor.net GSS-ACCEPTOR-PRINCIPAL DNS/ns1.example.net@EXAMPLE.COM"
+        )
         os.system("$PDNSUTIL --config-dir=configs/auth set-meta example.net TSIG-ALLOW-DNSUPDATE testuser1@EXAMPLE.COM")
 
     def kinit(self, user):
@@ -91,8 +96,8 @@ dnsupdate-require-tsig=no
         ret = os.system("$PDNSUTIL --config-dir=configs/auth list-zone %s | fgrep -q %s" % (zone, record))
         self.assertNotEqual(ret, 0)
 
-class TestBasicGSSTSIG(GSSTSIGBase):
 
+class TestBasicGSSTSIG(GSSTSIGBase):
     _config_template = """
 launch=gsqlite3
 gsqlite3-database=configs/auth/powerdns.sqlite
@@ -102,29 +107,30 @@ enable-gss-tsig=yes
 allow-dnsupdate-from=0.0.0.0/0
 dnsupdate=yes
 """
+
     def testAllowedUpdate(self):
-        self.checkNotInDB('example.net', 'inserted1.example.net')
+        self.checkNotInDB("example.net", "inserted1.example.net")
         self.kinit("testuser1")
         self.nsupdate("add inserted1.example.net 10 A 1.2.3.1")
-        self.checkInDB('example.net', '^inserted1.example.net.*10.*IN.*A.*1.2.3.1$')
+        self.checkInDB("example.net", "^inserted1.example.net.*10.*IN.*A.*1.2.3.1$")
 
     def testDisallowedUpdate(self):
         self.kinit("testuser2")
         self.nsupdate("add inserted2.example.net 10 A 1.2.3.2", 2)
-        self.checkNotInDB('example.net', 'inserted2.example.net')
+        self.checkNotInDB("example.net", "inserted2.example.net")
 
     def testNoAcceptor(self):
         self.kinit("testuser1")
         self.nsupdate("add inserted3.noacceptor.net 10 A 1.2.3.3", 2)
-        self.checkNotInDB('noacceptor.net', 'inserted3.noacceptor.net')
+        self.checkNotInDB("noacceptor.net", "inserted3.noacceptor.net")
 
     def testWrongAcceptor(self):
         self.kinit("testuser1")
         self.nsupdate("add inserted4.wrongacceptor.net 10 A 1.2.3.4", 2)
-        self.checkNotInDB('wrongacceptor.net', 'inserted4.wrongacceptor.net')
+        self.checkNotInDB("wrongacceptor.net", "inserted4.wrongacceptor.net")
 
-class TestLuaGSSTSIG(GSSTSIGBase):
 
+class TestLuaGSSTSIG(GSSTSIGBase):
     _config_template = """
 launch=gsqlite3
 gsqlite3-database=configs/auth/powerdns.sqlite
@@ -135,29 +141,29 @@ allow-dnsupdate-from=0.0.0.0/0
 dnsupdate=yes
 lua-dnsupdate-policy-script=kerberos-client/update-policy.lua
 """
+
     def testDisallowedByLuaUpdate(self):
         self.kinit("testuser1")
         self.nsupdate("add inserted10.example.net 10 A 1.2.3.10", 2)
-        self.checkNotInDB('example.net', 'inserted10.example.net')
+        self.checkNotInDB("example.net", "inserted10.example.net")
 
     def testAllowedByLuaUpdate(self):
         self.kinit("testuser2")
         self.nsupdate("add inserted11.example.net 10 A 1.2.3.11")
-        self.checkInDB('example.net', '^inserted11.example.net.*10.*IN.*A.*1.2.3.11$')
-
+        self.checkInDB("example.net", "^inserted11.example.net.*10.*IN.*A.*1.2.3.11$")
 
     def testNoAcceptor(self):
         self.kinit("testuser1")
         self.nsupdate("add inserted12.noacceptor.net 10 A 1.2.3.12", 2)
-        self.checkNotInDB('noacceptor.net', 'inserted12.noacceptor.net')
+        self.checkNotInDB("noacceptor.net", "inserted12.noacceptor.net")
 
     def testWrongAcceptor(self):
         self.kinit("testuser1")
         self.nsupdate("add inserted13.wrongacceptor.net 10 A 1.2.3.13", 2)
-        self.checkNotInDB('wrongacceptor.net', 'inserted13.wrongacceptor.net')
+        self.checkNotInDB("wrongacceptor.net", "inserted13.wrongacceptor.net")
 
-class TestUnauthTSIG(GSSTSIGBase):
 
+class TestUnauthTSIG(GSSTSIGBase):
     _config_template = """
 launch=gsqlite3
 gsqlite3-database=configs/auth/powerdns.sqlite
@@ -167,13 +173,14 @@ enable-gss-tsig=no
 allow-dnsupdate-from=0.0.0.0/0
 dnsupdate=yes
 """
+
     def testNoAcceptor(self):
-        self.checkNotInDB('noacceptor.net', 'inserted20.noacceptor.net')
+        self.checkNotInDB("noacceptor.net", "inserted20.noacceptor.net")
         self.nsupdate("add inserted20.noacceptor.net 10 A 1.2.3.3", 0, True)
-        self.checkInDB('noacceptor.net', 'inserted20.noacceptor.net')
+        self.checkInDB("noacceptor.net", "inserted20.noacceptor.net")
 
-class TestAuthTSIG(GSSTSIGBase):
 
+class TestAuthTSIG(GSSTSIGBase):
     _config_template = """
 launch=gsqlite3
 gsqlite3-database=configs/auth/powerdns.sqlite
@@ -184,12 +191,13 @@ allow-dnsupdate-from=0.0.0.0/0
 dnsupdate=yes
 dnsupdate-require-tsig=yes
 """
+
     def testNoAcceptor(self):
         self.nsupdate("add inserted30.noacceptor.net 10 A 1.2.3.3", 2, True)
-        self.checkNotInDB('noacceptor.net', 'inserted30.noacceptor.net')
+        self.checkNotInDB("noacceptor.net", "inserted30.noacceptor.net")
 
-class TestBasicRequiredGSSTSIG(GSSTSIGBase):
 
+class TestBasicRequiredGSSTSIG(GSSTSIGBase):
     _config_template = """
 launch=gsqlite3
 gsqlite3-database=configs/auth/powerdns.sqlite
@@ -200,25 +208,24 @@ allow-dnsupdate-from=0.0.0.0/0
 dnsupdate=yes
 dnsupdate-require-tsig=yes
 """
+
     def testAllowedUpdate(self):
-        self.checkNotInDB('example.net', 'inserted40.example.net')
+        self.checkNotInDB("example.net", "inserted40.example.net")
         self.kinit("testuser1")
         self.nsupdate("add inserted40.example.net 10 A 1.2.3.1")
-        self.checkInDB('example.net', '^inserted40.example.net.*10.*IN.*A.*1.2.3.1$')
+        self.checkInDB("example.net", "^inserted40.example.net.*10.*IN.*A.*1.2.3.1$")
 
     def testDisallowedUpdate(self):
         self.kinit("testuser2")
         self.nsupdate("add inserted41.example.net 10 A 1.2.3.2", 2)
-        self.checkNotInDB('example.net', 'inserted41.example.net')
+        self.checkNotInDB("example.net", "inserted41.example.net")
 
     def testNoAcceptor(self):
         self.kinit("testuser1")
         self.nsupdate("add inserted42.noacceptor.net 10 A 1.2.3.3", 2)
-        self.checkNotInDB('noacceptor.net', 'inserted42.noacceptor.net')
+        self.checkNotInDB("noacceptor.net", "inserted42.noacceptor.net")
 
     def testWrongAcceptor(self):
         self.kinit("testuser1")
         self.nsupdate("add inserted43.wrongacceptor.net 10 A 1.2.3.4", 2)
-        self.checkNotInDB('wrongacceptor.net', 'inserted43.wrongacceptor.net')
-
-
+        self.checkNotInDB("wrongacceptor.net", "inserted43.wrongacceptor.net")
index 9f353a39367fce6bc11ec6a15245401e3dd003fc..3a18dda407e983c9d6d55d73b0e07ae771cfd5c1 100644 (file)
@@ -7,59 +7,88 @@ from authtests import AuthTest
 from xfrserver.xfrserver import AXFRServer
 
 zones = {
-    1: ["""
-$ORIGIN example.""","""
+    1: [
+        """
+$ORIGIN example.""",
+        """
 @        86400   SOA    foo bar 1 2 3 4 5
 @        4242    NS     ns1.example.
 @        4242    NS     ns2.example.
 ns1.example.    4242    A       192.0.2.1
 ns2.example.    4242    A       192.0.2.2
-"""],
-    2: ["""
-$ORIGIN example.""","""
+""",
+    ],
+    2: [
+        """
+$ORIGIN example.""",
+        """
 @        86400   SOA    foo bar 2 2 3 4 5
 @        4242    NS     ns1.example.
 @        4242    NS     ns2.example.
 ns1.example.    4242    A       192.0.2.1
 ns2.example.    4242    A       192.0.2.2
 newrecord.example.        8484    A       192.0.2.42
-"""],
-    3: ["""
-$ORIGIN example.""","""
-@        86400   SOA    foo bar 3 2 3 4 5""","""
-@        86400   SOA    foo bar 2 2 3 4 5""","""
-@        86400   SOA    foo bar 3 2 3 4 5""","""
+""",
+    ],
+    3: [
+        """
+$ORIGIN example.""",
+        """
+@        86400   SOA    foo bar 3 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 2 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 3 2 3 4 5""",
+        """
 @        4242    NS     ns3.example.
-"""],
-    5: ["""
-$ORIGIN example.""","""
-@        86400   SOA    foo bar 5 2 3 4 5""","""
-@        86400   SOA    foo bar 3 2 3 4 5""","""
-@        86400   SOA    foo bar 4 2 3 4 5""","""
-@        86400   SOA    foo bar 4 2 3 4 5""","""
-@        86400   SOA    foo bar 5 2 3 4 5""","""
+""",
+    ],
+    5: [
+        """
+$ORIGIN example.""",
+        """
+@        86400   SOA    foo bar 5 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 3 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 4 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 4 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 5 2 3 4 5""",
+        """
 @        4242    NS     ns5.example.
-"""],
-    8: ["""
-$ORIGIN example.""","""
-@        86400   SOA    foo bar 8 2 3 4 5""","""
-@        86400   SOA    foo bar 5 2 3 4 5""","""
-@        86400   SOA    foo bar 6 2 3 4 5""","""
-@        86400   SOA    foo bar 6 2 3 4 5""","""
-@        86400   SOA    foo bar 7 2 3 4 5""","""
-@        86400   SOA    foo bar 7 2 3 4 5""","""
-@        86400   SOA    foo bar 8 2 3 4 5""","""
-"""]
-
-
+""",
+    ],
+    8: [
+        """
+$ORIGIN example.""",
+        """
+@        86400   SOA    foo bar 8 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 5 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 6 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 6 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 7 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 7 2 3 4 5""",
+        """
+@        86400   SOA    foo bar 8 2 3 4 5""",
+        """
+""",
+    ],
 }
 
 
 xfrServerPort = 4244
 xfrServer = AXFRServer(xfrServerPort, zones)
 
+
 class TestIXFR(AuthTest):
-    _backend = 'gsqlite3'
+    _backend = "gsqlite3"
 
     _config_template = """
 launch=gsqlite3
@@ -88,9 +117,9 @@ negquery-cache-ttl=60
 
         attempts = 0
         while attempts < timeout:
-            print('attempts=%s timeout=%s' % (attempts, timeout))
+            print("attempts=%s timeout=%s" % (attempts, timeout))
             servedSerial = xfrServer.getServedSerial()
-            print('servedSerial=%s' % servedSerial)
+            print("servedSerial=%s" % servedSerial)
             if servedSerial > serial:
                 raise AssertionError("Expected serial %d, got %d" % (serial, servedSerial))
             if servedSerial == serial:
@@ -101,7 +130,10 @@ negquery-cache-ttl=60
             attempts = attempts + 1
             time.sleep(1)
 
-        raise AssertionError("Waited %d seconds for the serial to be updated to %d but the last served serial is still %d" % (timeout, serial, servedSerial))
+        raise AssertionError(
+            "Waited %d seconds for the serial to be updated to %d but the last served serial is still %d"
+            % (timeout, serial, servedSerial)
+        )
 
     def checkFullZone(self, serial, data=None):
         global zones
@@ -110,15 +142,19 @@ negquery-cache-ttl=60
         zone = []
         if not data:
             data = zones[serial]
-        for i in dns.zone.from_text('\n'.join(data), relativize=False).iterate_rdatasets():
+        for i in dns.zone.from_text("\n".join(data), relativize=False).iterate_rdatasets():
             n, rds = i
-            rrs=dns.rrset.RRset(n, rds.rdclass, rds.rdtype)
+            rrs = dns.rrset.RRset(n, rds.rdclass, rds.rdtype)
             rrs.update(rds)
             zone.append(rrs)
 
-        expected =[[zone[0]], sorted(zone[1:], key=lambda rrset: (rrset.name, rrset.rdtype)), [zone[0]]] # AXFRs are SOA-wrapped
+        expected = [
+            [zone[0]],
+            sorted(zone[1:], key=lambda rrset: (rrset.name, rrset.rdtype)),
+            [zone[0]],
+        ]  # AXFRs are SOA-wrapped
 
-        query = dns.message.make_query('example.', 'AXFR')
+        query = dns.message.make_query("example.", "AXFR")
         res = self.sendTCPQueryMultiResponse(query, count=len(expected))
         answers = [r.answer for r in res]
         answers[1].sort(key=lambda rrset: (rrset.name, rrset.rdtype))
@@ -129,8 +165,10 @@ negquery-cache-ttl=60
 
         soa1 = xfrServer._getSOAForSerial(fromserial)
         soa2 = xfrServer._getSOAForSerial(toserial)
-        newrecord = [r for r in xfrServer._getRecordsForSerial(toserial) if r.name==dns.name.from_text('newrecord.example.')]
-        query = dns.message.make_query('example.', 'IXFR')
+        newrecord = [
+            r for r in xfrServer._getRecordsForSerial(toserial) if r.name == dns.name.from_text("newrecord.example.")
+        ]
+        query = dns.message.make_query("example.", "IXFR")
         query.authority = [soa1]
 
         expected = [[soa2], [soa1], [soa2], newrecord, [soa2]]
@@ -156,8 +194,12 @@ negquery-cache-ttl=60
         self.checkFullZone(2)
 
         self.waitUntilCorrectSerialIsLoaded(3)
-        self.checkFullZone(3, data=["""
-$ORIGIN example.""","""
+        self.checkFullZone(
+            3,
+            data=[
+                """
+$ORIGIN example.""",
+                """
 @        86400   SOA    foo bar 3 2 3 4 5
 @        4242    NS     ns1.example.
 @        4242    NS     ns2.example.
@@ -165,11 +207,17 @@ $ORIGIN example.""","""
 ns1.example.    4242    A       192.0.2.1
 ns2.example.    4242    A       192.0.2.2
 newrecord.example.        8484    A       192.0.2.42
-"""])
+""",
+            ],
+        )
 
         self.waitUntilCorrectSerialIsLoaded(5)
-        self.checkFullZone(5, data=["""
-$ORIGIN example.""","""
+        self.checkFullZone(
+            5,
+            data=[
+                """
+$ORIGIN example.""",
+                """
 @        86400   SOA    foo bar 5 2 3 4 5
 @        4242    NS     ns1.example.
 @        4242    NS     ns2.example.
@@ -178,12 +226,13 @@ $ORIGIN example.""","""
 ns1.example.    4242    A       192.0.2.1
 ns2.example.    4242    A       192.0.2.2
 newrecord.example.        8484    A       192.0.2.42
-"""])
-
+""",
+            ],
+        )
 
     # _b_ because we expect post-XFR testing state
     def test_b_UDP_SOA_existing(self):
-        query = dns.message.make_query('example.', 'SOA')
+        query = dns.message.make_query("example.", "SOA")
         expected = dns.message.make_response(query)
         expected.answer.append(xfrServer._getSOAForSerial(5))
         expected.flags |= dns.flags.AA
@@ -198,7 +247,7 @@ newrecord.example.        8484    A       192.0.2.42
             pos = pos + 1
 
     def test_b_UDP_SOA_not_loaded(self):
-        query = dns.message.make_query('example2.', 'SOA')
+        query = dns.message.make_query("example2.", "SOA")
         expected = dns.message.make_response(query)
         expected.set_rcode(dns.rcode.REFUSED)
 
@@ -206,7 +255,7 @@ newrecord.example.        8484    A       192.0.2.42
         self.assertEqual(expected, response)
 
     def test_b_UDP_SOA_not_configured(self):
-        query = dns.message.make_query('example3.', 'SOA')
+        query = dns.message.make_query("example3.", "SOA")
         expected = dns.message.make_response(query)
         expected.set_rcode(dns.rcode.REFUSED)
 
@@ -215,8 +264,12 @@ newrecord.example.        8484    A       192.0.2.42
 
     def test_d_XFR(self):
         self.waitUntilCorrectSerialIsLoaded(8)
-        self.checkFullZone(7, data=["""
-$ORIGIN example.""","""
+        self.checkFullZone(
+            7,
+            data=[
+                """
+$ORIGIN example.""",
+                """
 @        86400   SOA    foo bar 8 2 3 4 5
 @        4242    NS     ns1.example.
 @        4242    NS     ns2.example.
@@ -225,10 +278,12 @@ $ORIGIN example.""","""
 ns1.example.    4242    A       192.0.2.1
 ns2.example.    4242    A       192.0.2.2
 newrecord.example.        8484    A       192.0.2.42
-"""])
-        ret = subprocess.check_output([os.environ['PDNSUTIL'],
-                           '--config-dir=configs/auth',
-                           'list-zone', 'example'], stderr=subprocess.STDOUT)
-        rets = ret.split(b'\n')
-
-        self.assertEqual(1, sum(b'SOA' in l for l in rets))
+""",
+            ],
+        )
+        ret = subprocess.check_output(
+            [os.environ["PDNSUTIL"], "--config-dir=configs/auth", "list-zone", "example"], stderr=subprocess.STDOUT
+        )
+        rets = ret.split(b"\n")
+
+        self.assertEqual(1, sum(b"SOA" in l for l in rets))
index bfcef3ea12c66c08b9cbebf66ffed46f90861786..027eb365ed09fd33cdcc29ae46edd1a663cb432a 100644 (file)
@@ -14,29 +14,30 @@ from http.server import BaseHTTPRequestHandler, HTTPServer
 
 webserver = None
 
+
 class FakeHTTPServer(BaseHTTPRequestHandler):
     def _set_headers(self, response_code=200):
         self.send_response(response_code)
-        self.send_header('Content-type', 'text/html')
+        self.send_header("Content-type", "text/html")
         self.end_headers()
 
     def do_GET(self):
-        if self.path == '/404':
+        if self.path == "/404":
             self._set_headers(404)
-            self.wfile.write(bytes('this page does not exist', 'utf-8'))
+            self.wfile.write(bytes("this page does not exist", "utf-8"))
             return
 
         if self.path == "/check-headers":
             if self.headers.get("my-header", "") != "myvalue":
                 self._set_headers(400)
-                self.wfile.write(bytes('Wrong Header value!', 'utf-8'))
+                self.wfile.write(bytes("Wrong Header value!", "utf-8"))
                 return
 
         self._set_headers()
-        if self.path == '/ping.json':
-            self.wfile.write(bytes('{"ping":"pong"}', 'utf-8'))
-        if self.path == '/weight.txt':
-            self.wfile.write(bytes('12', 'utf-8'))
+        if self.path == "/ping.json":
+            self.wfile.write(bytes('{"ping":"pong"}', "utf-8"))
+        if self.path == "/weight.txt":
+            self.wfile.write(bytes("12", "utf-8"))
         else:
             self.wfile.write(bytes("<html><body><h1>hi!</h1><h2>Programming in Lua !</h2></body></html>", "utf-8"))
 
@@ -46,6 +47,7 @@ class FakeHTTPServer(BaseHTTPRequestHandler):
     def do_HEAD(self):
         self._set_headers()
 
+
 class BaseLuaTest(AuthTest):
     _config_template = """
 geoip-database-files=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb
@@ -58,7 +60,7 @@ lua-health-checks-interval=1
 """
 
     _zones = {
-        'example.org': """
+        "example.org": """
 example.org.                 3600 IN SOA  {soa}
 example.org.                 3600 IN NS   ns1.example.org.
 example.org.                 3600 IN NS   ns2.example.org.
@@ -214,18 +216,16 @@ geoipqueryattribute IN LUA    TXT ("string.format('%d %d %d %d %d %d %d',"
     @classmethod
     def startResponders(cls):
         global webserver
-        if webserver: return  # it is already running
+        if webserver:
+            return  # it is already running
 
-        webserver = threading.Thread(name='HTTP Listener',
-                                     target=cls.HTTPResponder,
-                                     args=[8080]
-        )
+        webserver = threading.Thread(name="HTTP Listener", target=cls.HTTPResponder, args=[8080])
         webserver.setDaemon(True)
         webserver.start()
 
     @classmethod
     def HTTPResponder(cls, port):
-        server_address = ('', port)
+        server_address = ("", port)
         httpd = HTTPServer(server_address, FakeHTTPServer)
         httpd.serve_forever()
 
@@ -234,25 +234,33 @@ geoipqueryattribute IN LUA    TXT ("string.format('%d %d %d %d %d %d %d',"
 
         super(BaseLuaTest, cls).setUpClass()
 
-        cls._web_rrsets = [dns.rrset.from_text('web1.example.org.', 0, dns.rdataclass.IN, 'A',
-                                               '{prefix}.101'.format(prefix=cls._PREFIX)),
-                           dns.rrset.from_text('web2.example.org.', 0, dns.rdataclass.IN, 'A',
-                                               '{prefix}.102'.format(prefix=cls._PREFIX)),
-                           dns.rrset.from_text('web3.example.org.', 0, dns.rdataclass.IN, 'A',
-                                               '{prefix}.103'.format(prefix=cls._PREFIX))
+        cls._web_rrsets = [
+            dns.rrset.from_text(
+                "web1.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.101".format(prefix=cls._PREFIX)
+            ),
+            dns.rrset.from_text(
+                "web2.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.102".format(prefix=cls._PREFIX)
+            ),
+            dns.rrset.from_text(
+                "web3.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.103".format(prefix=cls._PREFIX)
+            ),
         ]
 
-class TestLuaRecords(BaseLuaTest):
 
+class TestLuaRecords(BaseLuaTest):
     def testPickRandom(self):
         """
         Basic pickrandom() test with a set of A records
         """
-        expected = [dns.rrset.from_text('rand.example.org.', 0, dns.rdataclass.IN, 'A',
-                                        '{prefix}.101'.format(prefix=self._PREFIX)),
-                    dns.rrset.from_text('rand.example.org.', 0, dns.rdataclass.IN, 'A',
-                                        '{prefix}.102'.format(prefix=self._PREFIX))]
-        query = dns.message.make_query('rand.example.org', 'A')
+        expected = [
+            dns.rrset.from_text(
+                "rand.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.101".format(prefix=self._PREFIX)
+            ),
+            dns.rrset.from_text(
+                "rand.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.102".format(prefix=self._PREFIX)
+            ),
+        ]
+        query = dns.message.make_query("rand.example.org", "A")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -262,9 +270,11 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic pickrandom() test with a set of TXT records
         """
-        expected = [dns.rrset.from_text('rand-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'bob'),
-                    dns.rrset.from_text('rand-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'alice')]
-        query = dns.message.make_query('rand-txt.example.org', 'TXT')
+        expected = [
+            dns.rrset.from_text("rand-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "bob"),
+            dns.rrset.from_text("rand-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "alice"),
+        ]
+        query = dns.message.make_query("rand-txt.example.org", "TXT")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -274,7 +284,7 @@ class TestLuaRecords(BaseLuaTest):
         """
         Test a bogus AAAA pickrandom() record  with a set of v4 addr
         """
-        query = dns.message.make_query('v6-bogus.rand.example.org', 'AAAA')
+        query = dns.message.make_query("v6-bogus.rand.example.org", "AAAA")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
@@ -283,11 +293,11 @@ class TestLuaRecords(BaseLuaTest):
         """
         Test pickrandom() AAAA record
         """
-        expected = [dns.rrset.from_text('v6.rand.example.org.', 0, dns.rdataclass.IN, 'AAAA',
-                                        '2001:db8:a0b:12f0::1'),
-                    dns.rrset.from_text('v6.rand.example.org.', 0, dns.rdataclass.IN, 'AAAA',
-                                        'fe80::2a1:9bff:fe9b:f268')]
-        query = dns.message.make_query('v6.rand.example.org', 'AAAA')
+        expected = [
+            dns.rrset.from_text("v6.rand.example.org.", 0, dns.rdataclass.IN, "AAAA", "2001:db8:a0b:12f0::1"),
+            dns.rrset.from_text("v6.rand.example.org.", 0, dns.rdataclass.IN, "AAAA", "fe80::2a1:9bff:fe9b:f268"),
+        ]
+        query = dns.message.make_query("v6.rand.example.org", "AAAA")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -297,7 +307,7 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic pickrandom() test with an empty set
         """
-        query = dns.message.make_query('empty.rand.example.org', 'A')
+        query = dns.message.make_query("empty.rand.example.org", "A")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
@@ -306,11 +316,15 @@ class TestLuaRecords(BaseLuaTest):
         """
         Test the selfweighted() function with a set of A records
         """
-        expected = [dns.rrset.from_text('selfweighted.example.org.', 0, dns.rdataclass.IN, 'A',
-                                        '{prefix}.101'.format(prefix=self._PREFIX)),
-                    dns.rrset.from_text('selfweighted.example.org.', 0, dns.rdataclass.IN, 'A',
-                                        '{prefix}.102'.format(prefix=self._PREFIX))]
-        query = dns.message.make_query('selfweighted.example.org', 'A')
+        expected = [
+            dns.rrset.from_text(
+                "selfweighted.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.101".format(prefix=self._PREFIX)
+            ),
+            dns.rrset.from_text(
+                "selfweighted.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.102".format(prefix=self._PREFIX)
+            ),
+        ]
+        query = dns.message.make_query("selfweighted.example.org", "A")
         self.sendUDPQuery(query)
 
         # wait for health checks to happen
@@ -324,13 +338,15 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic pickrandomsample() test with a set of TXT records
         """
-        expected = [dns.rrset.from_text('randn-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'bob', 'alice'),
-                    dns.rrset.from_text('randn-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'bob', 'john'),
-                    dns.rrset.from_text('randn-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'alice', 'bob'),
-                    dns.rrset.from_text('randn-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'alice', 'john'),
-                    dns.rrset.from_text('randn-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'john', 'bob'),
-                    dns.rrset.from_text('randn-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'john', 'alice')]
-        query = dns.message.make_query('randn-txt.example.org', 'TXT')
+        expected = [
+            dns.rrset.from_text("randn-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "bob", "alice"),
+            dns.rrset.from_text("randn-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "bob", "john"),
+            dns.rrset.from_text("randn-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "alice", "bob"),
+            dns.rrset.from_text("randn-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "alice", "john"),
+            dns.rrset.from_text("randn-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "john", "bob"),
+            dns.rrset.from_text("randn-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "john", "alice"),
+        ]
+        query = dns.message.make_query("randn-txt.example.org", "TXT")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -340,11 +356,15 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic pickwrandom() test with a set of A records
         """
-        expected = [dns.rrset.from_text('wrand.example.org.', 0, dns.rdataclass.IN, 'A',
-                                        '{prefix}.103'.format(prefix=self._PREFIX)),
-                    dns.rrset.from_text('wrand.example.org.', 0, dns.rdataclass.IN, 'A',
-                                        '{prefix}.102'.format(prefix=self._PREFIX))]
-        query = dns.message.make_query('wrand.example.org', 'A')
+        expected = [
+            dns.rrset.from_text(
+                "wrand.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.103".format(prefix=self._PREFIX)
+            ),
+            dns.rrset.from_text(
+                "wrand.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.102".format(prefix=self._PREFIX)
+            ),
+        ]
+        query = dns.message.make_query("wrand.example.org", "A")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -354,9 +374,11 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic pickwrandom() test with a set of TXT records
         """
-        expected = [dns.rrset.from_text('wrand-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'bob'),
-                    dns.rrset.from_text('wrand-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'alice')]
-        query = dns.message.make_query('wrand-txt.example.org', 'TXT')
+        expected = [
+            dns.rrset.from_text("wrand-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "bob"),
+            dns.rrset.from_text("wrand-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "alice"),
+        ]
+        query = dns.message.make_query("wrand-txt.example.org", "TXT")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -366,12 +388,15 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic ifportup() test
         """
-        query = dns.message.make_query('all.ifportup.example.org', 'A')
+        query = dns.message.make_query("all.ifportup.example.org", "A")
         expected = [
-            dns.rrset.from_text('all.ifportup.example.org.', 0, dns.rdataclass.IN, 'A',
-                                '{prefix}.101'.format(prefix=self._PREFIX)),
-            dns.rrset.from_text('all.ifportup.example.org.', 0, dns.rdataclass.IN, 'A',
-                                '{prefix}.102'.format(prefix=self._PREFIX))]
+            dns.rrset.from_text(
+                "all.ifportup.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.101".format(prefix=self._PREFIX)
+            ),
+            dns.rrset.from_text(
+                "all.ifportup.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.102".format(prefix=self._PREFIX)
+            ),
+        ]
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -381,12 +406,13 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic ifportup() test with some ports DOWN
         """
-        query = dns.message.make_query('some.ifportup.example.org', 'A')
+        query = dns.message.make_query("some.ifportup.example.org", "A")
         expected = [
-            dns.rrset.from_text('some.ifportup.example.org.', 0, dns.rdataclass.IN, 'A',
-                                '192.168.42.21'),
-            dns.rrset.from_text('some.ifportup.example.org.', 0, dns.rdataclass.IN, 'A',
-                                '{prefix}.102'.format(prefix=self._PREFIX))]
+            dns.rrset.from_text("some.ifportup.example.org.", 0, dns.rdataclass.IN, "A", "192.168.42.21"),
+            dns.rrset.from_text(
+                "some.ifportup.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.102".format(prefix=self._PREFIX)
+            ),
+        ]
 
         # we first expect any of the IPs as no check has been performed yet
         res = self.sendUDPQuery(query)
@@ -403,16 +429,16 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic ifportup() test with some ports DOWN from multiple sets
         """
-        query = dns.message.make_query('multi.ifportup.example.org', 'A')
+        query = dns.message.make_query("multi.ifportup.example.org", "A")
         expected = [
-            dns.rrset.from_text('multi.ifportup.example.org.', 0, dns.rdataclass.IN, 'A',
-                                '192.168.42.21'),
-            dns.rrset.from_text('multi.ifportup.example.org.', 0, dns.rdataclass.IN, 'A',
-                                '192.168.42.23'),
-            dns.rrset.from_text('multi.ifportup.example.org.', 0, dns.rdataclass.IN, 'A',
-                                '{prefix}.102'.format(prefix=self._PREFIX)),
-            dns.rrset.from_text('multi.ifportup.example.org.', 0, dns.rdataclass.IN, 'A',
-                                '{prefix}.101'.format(prefix=self._PREFIX))
+            dns.rrset.from_text("multi.ifportup.example.org.", 0, dns.rdataclass.IN, "A", "192.168.42.21"),
+            dns.rrset.from_text("multi.ifportup.example.org.", 0, dns.rdataclass.IN, "A", "192.168.42.23"),
+            dns.rrset.from_text(
+                "multi.ifportup.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.102".format(prefix=self._PREFIX)
+            ),
+            dns.rrset.from_text(
+                "multi.ifportup.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.101".format(prefix=self._PREFIX)
+            ),
         ]
 
         # we first expect any of the IPs as no check has been performed yet
@@ -430,12 +456,13 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic ifportup() test with all ports DOWN
         """
-        query = dns.message.make_query('none.ifportup.example.org', 'A')
+        query = dns.message.make_query("none.ifportup.example.org", "A")
         expected = [
-            dns.rrset.from_text('none.ifportup.example.org.', 0, dns.rdataclass.IN, 'A',
-                                '192.168.42.21'),
-            dns.rrset.from_text('none.ifportup.example.org.', 0, dns.rdataclass.IN, 'A',
-                                '192.168.21.42'.format(prefix=self._PREFIX))]
+            dns.rrset.from_text("none.ifportup.example.org.", 0, dns.rdataclass.IN, "A", "192.168.42.21"),
+            dns.rrset.from_text(
+                "none.ifportup.example.org.", 0, dns.rdataclass.IN, "A", "192.168.21.42".format(prefix=self._PREFIX)
+            ),
+        ]
 
         # we first expect any of the IPs as no check has been performed yet
         res = self.sendUDPQuery(query)
@@ -451,9 +478,9 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic ifportup() test with all ports DOWN, fallback to 'all' backup selector
         """
-        name = 'all.noneup.ifportup.example.org.'
+        name = "all.noneup.ifportup.example.org."
         query = dns.message.make_query(name, dns.rdatatype.A)
-        expected = [dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, '192.168.42.21', '192.168.21.42')]
+        expected = [dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, "192.168.42.21", "192.168.21.42")]
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -467,7 +494,7 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic ifportup() test with all ports DOWN, fallback to 'empty' backup selector
         """
-        name = 'empty.noneup.ifportup.example.org.'
+        name = "empty.noneup.ifportup.example.org."
         query = dns.message.make_query(name, dns.rdatatype.A)
 
         # With backupSelector='empty', we always return NODATA when there are no healthy targets,
@@ -480,20 +507,18 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic ifurlup() test
         """
-        reachable = [
-            '{prefix}.103'.format(prefix=self._PREFIX)
-        ]
-        unreachable = ['192.168.42.105']
+        reachable = ["{prefix}.103".format(prefix=self._PREFIX)]
+        unreachable = ["192.168.42.105"]
         ips = reachable + unreachable
         all_rrs = []
         reachable_rrs = []
         for ip in ips:
-            rr = dns.rrset.from_text('usa.example.org.', 0, dns.rdataclass.IN, 'A', ip)
+            rr = dns.rrset.from_text("usa.example.org.", 0, dns.rdataclass.IN, "A", ip)
             all_rrs.append(rr)
             if ip in reachable:
                 reachable_rrs.append(rr)
 
-        query = dns.message.make_query('usa.example.org', 'A')
+        query = dns.message.make_query("usa.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, all_rrs)
@@ -508,20 +533,18 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic ifurlup() test, with non-default HTTP code
         """
-        reachable = [
-            '{prefix}.103'.format(prefix=self._PREFIX)
-        ]
-        unreachable = ['192.168.42.105']
+        reachable = ["{prefix}.103".format(prefix=self._PREFIX)]
+        unreachable = ["192.168.42.105"]
         ips = reachable + unreachable
         all_rrs = []
         reachable_rrs = []
         for ip in ips:
-            rr = dns.rrset.from_text('usa-404.example.org.', 0, dns.rdataclass.IN, 'A', ip)
+            rr = dns.rrset.from_text("usa-404.example.org.", 0, dns.rdataclass.IN, "A", ip)
             all_rrs.append(rr)
             if ip in reachable:
                 reachable_rrs.append(rr)
 
-        query = dns.message.make_query('usa-404.example.org', 'A')
+        query = dns.message.make_query("usa-404.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, all_rrs)
@@ -536,20 +559,18 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic ifurlup() test with mutiple sets
         """
-        reachable = [
-            '{prefix}.103'.format(prefix=self._PREFIX)
-        ]
-        unreachable = ['192.168.42.101', '192.168.42.102', '192.168.42.105']
+        reachable = ["{prefix}.103".format(prefix=self._PREFIX)]
+        unreachable = ["192.168.42.101", "192.168.42.102", "192.168.42.105"]
         ips = reachable + unreachable
         all_rrs = []
         reachable_rrs = []
         for ip in ips:
-            rr = dns.rrset.from_text('usa-ext.example.org.', 0, dns.rdataclass.IN, 'A', ip)
+            rr = dns.rrset.from_text("usa-ext.example.org.", 0, dns.rdataclass.IN, "A", ip)
             all_rrs.append(rr)
             if ip in reachable:
                 reachable_rrs.append(rr)
 
-        query = dns.message.make_query('usa-ext.example.org', 'A')
+        query = dns.message.make_query("usa-ext.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, all_rrs)
@@ -561,9 +582,11 @@ class TestLuaRecords(BaseLuaTest):
         self.assertAnyRRsetInAnswer(res, reachable_rrs)
 
     def testIfurlextup(self):
-        expected = [dns.rrset.from_text('ifurlextup.example.org.', 0, dns.rdataclass.IN, dns.rdatatype.A, '192.168.0.3')]
+        expected = [
+            dns.rrset.from_text("ifurlextup.example.org.", 0, dns.rdataclass.IN, dns.rdatatype.A, "192.168.0.3")
+        ]
 
-        query = dns.message.make_query('ifurlextup.example.org', 'A')
+        query = dns.message.make_query("ifurlextup.example.org", "A")
         self.sendUDPQuery(query)
 
         # wait for health checks to happen
@@ -579,20 +602,18 @@ class TestLuaRecords(BaseLuaTest):
         Basic ifurlup() test with the simplified list of ips
         Also ensures the correct path is queried
         """
-        reachable = [
-            '{prefix}.101'.format(prefix=self._PREFIX)
-        ]
-        unreachable = ['192.168.42.101']
+        reachable = ["{prefix}.101".format(prefix=self._PREFIX)]
+        unreachable = ["192.168.42.101"]
         ips = reachable + unreachable
         all_rrs = []
         reachable_rrs = []
         for ip in ips:
-            rr = dns.rrset.from_text('mix.ifurlup.example.org.', 0, dns.rdataclass.IN, 'A', ip)
+            rr = dns.rrset.from_text("mix.ifurlup.example.org.", 0, dns.rdataclass.IN, "A", ip)
             all_rrs.append(rr)
             if ip in reachable:
                 reachable_rrs.append(rr)
 
-        query = dns.message.make_query('mix.ifurlup.example.org', 'A')
+        query = dns.message.make_query("mix.ifurlup.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, all_rrs)
@@ -606,20 +627,18 @@ class TestLuaRecords(BaseLuaTest):
         """
         ifurlup() test where send headers.
         """
-        reachable = [
-            '{prefix}.102'.format(prefix=self._PREFIX)
-        ]
-        unreachable = ['192.168.42.105']
+        reachable = ["{prefix}.102".format(prefix=self._PREFIX)]
+        unreachable = ["192.168.42.105"]
         ips = reachable + unreachable
         all_rrs = []
         reachable_rrs = []
         for ip in ips:
-            rr = dns.rrset.from_text('goodheaders.ifurlup.example.org.', 0, dns.rdataclass.IN, 'A', ip)
+            rr = dns.rrset.from_text("goodheaders.ifurlup.example.org.", 0, dns.rdataclass.IN, "A", ip)
             all_rrs.append(rr)
             if ip in reachable:
                 reachable_rrs.append(rr)
 
-        query = dns.message.make_query('goodheaders.ifurlup.example.org', 'A')
+        query = dns.message.make_query("goodheaders.ifurlup.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, all_rrs)
@@ -633,20 +652,18 @@ class TestLuaRecords(BaseLuaTest):
         """
         ifurlup() test where send headers, but the value is wrong
         """
-        reachable = [
-            '{prefix}.102'.format(prefix=self._PREFIX)
-        ]
-        unreachable = ['192.168.42.105']
+        reachable = ["{prefix}.102".format(prefix=self._PREFIX)]
+        unreachable = ["192.168.42.105"]
         ips = reachable + unreachable
         all_rrs = []
         reachable_rrs = []
         for ip in ips:
-            rr = dns.rrset.from_text('badheaders.ifurlup.example.org.', 0, dns.rdataclass.IN, 'A', ip)
+            rr = dns.rrset.from_text("badheaders.ifurlup.example.org.", 0, dns.rdataclass.IN, "A", ip)
             all_rrs.append(rr)
             if ip in reachable:
                 reachable_rrs.append(rr)
 
-        query = dns.message.make_query('badheaders.ifurlup.example.org', 'A')
+        query = dns.message.make_query("badheaders.ifurlup.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, all_rrs)
@@ -660,12 +677,10 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic latlon() test
         """
-        name = 'latlon.geo.example.org.'
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.0', 24)
-        query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096, options=[ecso])
-        expected = dns.rrset.from_text(name, 0,
-                                       dns.rdataclass.IN, 'TXT',
-                                       '"47.913000 -122.304200"')
+        name = "latlon.geo.example.org."
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.0", 24)
+        query = dns.message.make_query(name, "TXT", "IN", use_edns=True, payload=4096, options=[ecso])
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", '"47.913000 -122.304200"')
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -675,11 +690,12 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic latlonloc() test
         """
-        name = 'latlonloc.geo.example.org.'
-        expected = dns.rrset.from_text(name, 0,dns.rdataclass.IN, 'TXT',
-                                       '"47 54 46.8 N 122 18 15.12 W 0.00m 1.00m 10000.00m 10.00m"')
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.0', 24)
-        query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "latlonloc.geo.example.org."
+        expected = dns.rrset.from_text(
+            name, 0, dns.rdataclass.IN, "TXT", '"47 54 46.8 N 122 18 15.12 W 0.00m 1.00m 10000.00m 10.00m"'
+        )
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.0", 24)
+        query = dns.message.make_query(name, "TXT", "IN", use_edns=True, payload=4096, options=[ecso])
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -689,7 +705,7 @@ class TestLuaRecords(BaseLuaTest):
         """
         Ensure errors coming from LUA wildcards are reported
         """
-        query = dns.message.make_query('failure.magic.example.org', 'A')
+        query = dns.message.make_query("failure.magic.example.org", "A")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
@@ -699,22 +715,18 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic closestMagic() test
         """
-        name = 'www-balanced.example.org.'
-        cname = '1-1-1-3.17-1-2-4.1-2-3-5.magic.example.org.'
-        queries = [
-            ('1.1.1.0', 24,  '1.1.1.3'),
-            ('1.2.3.0', 24,  '1.2.3.5'),
-            ('17.1.0.0', 16, '17.1.2.4')
-        ]
+        name = "www-balanced.example.org."
+        cname = "1-1-1-3.17-1-2-4.1-2-3-5.magic.example.org."
+        queries = [("1.1.1.0", 24, "1.1.1.3"), ("1.2.3.0", 24, "1.2.3.5"), ("17.1.0.0", 16, "17.1.2.4")]
 
-        for (subnet, mask, ip) in queries:
+        for subnet, mask, ip in queries:
             ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
-            query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+            query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
 
             response = dns.message.make_response(query)
 
             response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.CNAME, cname))
-            response.answer.append(dns.rrset.from_text(cname, 0, dns.rdataclass.IN, 'A', ip))
+            response.answer.append(dns.rrset.from_text(cname, 0, dns.rdataclass.IN, "A", ip))
 
             res = self.sendUDPQuery(query)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -724,16 +736,12 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic asnum() test
         """
-        queries = [
-            ('1.1.1.0', 24,  '"true"'),
-            ('1.2.3.0', 24,  '"false"'),
-            ('17.1.0.0', 16, '"false"')
-        ]
-        name = 'asnum.geo.example.org.'
-        for (subnet, mask, txt) in queries:
+        queries = [("1.1.1.0", 24, '"true"'), ("1.2.3.0", 24, '"false"'), ("17.1.0.0", 16, '"false"')]
+        name = "asnum.geo.example.org."
+        for subnet, mask, txt in queries:
             ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
-            query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096, options=[ecso])
-            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', txt)
+            query = dns.message.make_query(name, "TXT", "IN", use_edns=True, payload=4096, options=[ecso])
+            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", txt)
 
             res = self.sendUDPQuery(query)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -743,16 +751,12 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic country() test
         """
-        queries = [
-            ('1.1.1.0', 24,  '"false"'),
-            ('1.2.3.0', 24,  '"true"'),
-            ('17.1.0.0', 16, '"false"')
-        ]
-        name = 'country.geo.example.org.'
-        for (subnet, mask, txt) in queries:
+        queries = [("1.1.1.0", 24, '"false"'), ("1.2.3.0", 24, '"true"'), ("17.1.0.0", 16, '"false"')]
+        name = "country.geo.example.org."
+        for subnet, mask, txt in queries:
             ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
-            query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096, options=[ecso])
-            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', txt)
+            query = dns.message.make_query(name, "TXT", "IN", use_edns=True, payload=4096, options=[ecso])
+            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", txt)
 
             res = self.sendUDPQuery(query)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -762,16 +766,12 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic countryCode() test
         """
-        queries = [
-            ('1.1.1.0', 24,  '"au"'),
-            ('1.2.3.0', 24,  '"us"'),
-            ('17.1.0.0', 16, '"--"')
-        ]
-        name = 'country-code.geo.example.org.'
-        for (subnet, mask, txt) in queries:
+        queries = [("1.1.1.0", 24, '"au"'), ("1.2.3.0", 24, '"us"'), ("17.1.0.0", 16, '"--"')]
+        name = "country-code.geo.example.org."
+        for subnet, mask, txt in queries:
             ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
-            query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096, options=[ecso])
-            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', txt)
+            query = dns.message.make_query(name, "TXT", "IN", use_edns=True, payload=4096, options=[ecso])
+            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", txt)
 
             res = self.sendUDPQuery(query)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -781,16 +781,12 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic region() test
         """
-        queries = [
-            ('1.1.1.0', 24,  '"false"'),
-            ('1.2.3.0', 24,  '"true"'),
-            ('17.1.0.0', 16, '"false"')
-        ]
-        name = 'region.geo.example.org.'
-        for (subnet, mask, txt) in queries:
+        queries = [("1.1.1.0", 24, '"false"'), ("1.2.3.0", 24, '"true"'), ("17.1.0.0", 16, '"false"')]
+        name = "region.geo.example.org."
+        for subnet, mask, txt in queries:
             ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
-            query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096, options=[ecso])
-            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', txt)
+            query = dns.message.make_query(name, "TXT", "IN", use_edns=True, payload=4096, options=[ecso])
+            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", txt)
 
             res = self.sendUDPQuery(query)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -800,16 +796,12 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic regionCode() test
         """
-        queries = [
-            ('1.1.1.0', 24,  '"--"'),
-            ('1.2.3.0', 24,  '"ca"'),
-            ('17.1.0.0', 16, '"--"')
-        ]
-        name = 'region-code.geo.example.org.'
-        for (subnet, mask, txt) in queries:
+        queries = [("1.1.1.0", 24, '"--"'), ("1.2.3.0", 24, '"ca"'), ("17.1.0.0", 16, '"--"')]
+        name = "region-code.geo.example.org."
+        for subnet, mask, txt in queries:
             ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
-            query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096, options=[ecso])
-            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', txt)
+            query = dns.message.make_query(name, "TXT", "IN", use_edns=True, payload=4096, options=[ecso])
+            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", txt)
 
             res = self.sendUDPQuery(query)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -819,16 +811,12 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic continent() test
         """
-        queries = [
-            ('1.1.1.0', 24,  '"false"'),
-            ('1.2.3.0', 24,  '"true"'),
-            ('17.1.0.0', 16, '"false"')
-        ]
-        name = 'continent.geo.example.org.'
-        for (subnet, mask, txt) in queries:
+        queries = [("1.1.1.0", 24, '"false"'), ("1.2.3.0", 24, '"true"'), ("17.1.0.0", 16, '"false"')]
+        name = "continent.geo.example.org."
+        for subnet, mask, txt in queries:
             ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
-            query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096, options=[ecso])
-            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', txt)
+            query = dns.message.make_query(name, "TXT", "IN", use_edns=True, payload=4096, options=[ecso])
+            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", txt)
 
             res = self.sendUDPQuery(query)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -838,16 +826,12 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic continentCode() test
         """
-        queries = [
-            ('1.1.1.0', 24,  '"oc"'),
-            ('1.2.3.0', 24,  '"na"'),
-            ('17.1.0.0', 16, '"--"')
-        ]
-        name = 'continent-code.geo.example.org.'
-        for (subnet, mask, txt) in queries:
+        queries = [("1.1.1.0", 24, '"oc"'), ("1.2.3.0", 24, '"na"'), ("17.1.0.0", 16, '"--"')]
+        name = "continent-code.geo.example.org."
+        for subnet, mask, txt in queries:
             ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
-            query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096, options=[ecso])
-            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', txt)
+            query = dns.message.make_query(name, "TXT", "IN", use_edns=True, payload=4096, options=[ecso])
+            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", txt)
 
             res = self.sendUDPQuery(query)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -857,16 +841,12 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic pickclosest() test
         """
-        queries = [
-            ('1.1.1.0', 24,  '1.1.1.2'),
-            ('1.2.3.0', 24,  '1.2.3.4'),
-            ('17.1.0.0', 16, '1.1.1.2')
-        ]
-        name = 'closest.geo.example.org.'
-        for (subnet, mask, ip) in queries:
+        queries = [("1.1.1.0", 24, "1.1.1.2"), ("1.2.3.0", 24, "1.2.3.4"), ("17.1.0.0", 16, "1.1.1.2")]
+        name = "closest.geo.example.org."
+        for subnet, mask, ip in queries:
             ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
-            query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
-            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', ip)
+            query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
+            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", ip)
 
             res = self.sendUDPQuery(query)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -876,8 +856,10 @@ class TestLuaRecords(BaseLuaTest):
         """
         Basic all() test
         """
-        expected = [dns.rrset.from_text('all.example.org.', 0, dns.rdataclass.IN, dns.rdatatype.A, '1.2.3.4', '4.3.2.1')]
-        query = dns.message.make_query('all.example.org.', 'A')
+        expected = [
+            dns.rrset.from_text("all.example.org.", 0, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4", "4.3.2.1")
+        ]
+        query = dns.message.make_query("all.example.org.", "A")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -889,22 +871,18 @@ class TestLuaRecords(BaseLuaTest):
         """
         queries = [
             {
-                'expected': dns.rrset.from_text('true.netmask.example.org.', 0,
-                                       dns.rdataclass.IN, 'TXT',
-                                       '"true"'),
-                'query': dns.message.make_query('true.netmask.example.org', 'TXT')
+                "expected": dns.rrset.from_text("true.netmask.example.org.", 0, dns.rdataclass.IN, "TXT", '"true"'),
+                "query": dns.message.make_query("true.netmask.example.org", "TXT"),
             },
             {
-                'expected': dns.rrset.from_text('false.netmask.example.org.', 0,
-                                       dns.rdataclass.IN, 'TXT',
-                                       '"false"'),
-                'query': dns.message.make_query('false.netmask.example.org', 'TXT')
-            }
+                "expected": dns.rrset.from_text("false.netmask.example.org.", 0, dns.rdataclass.IN, "TXT", '"false"'),
+                "query": dns.message.make_query("false.netmask.example.org", "TXT"),
+            },
         ]
-        for query in queries :
-            res = self.sendUDPQuery(query['query'])
+        for query in queries:
+            res = self.sendUDPQuery(query["query"])
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
-            self.assertRRsetInAnswer(res, query['expected'])
+            self.assertRRsetInAnswer(res, query["expected"])
 
     def testView(self):
         """
@@ -912,28 +890,26 @@ class TestLuaRecords(BaseLuaTest):
         """
         queries = [
             {
-                'expected': dns.rrset.from_text('view.example.org.', 0,
-                                       dns.rdataclass.IN, 'A',
-                                       '{prefix}.54'.format(prefix=self._PREFIX)),
-                'query': dns.message.make_query('view.example.org', 'A')
+                "expected": dns.rrset.from_text(
+                    "view.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.54".format(prefix=self._PREFIX)
+                ),
+                "query": dns.message.make_query("view.example.org", "A"),
             },
             {
-                'expected': dns.rrset.from_text('txt.view.example.org.', 0,
-                                       dns.rdataclass.IN, 'TXT',
-                                       '"else"'),
-                'query': dns.message.make_query('txt.view.example.org', 'TXT')
-            }
+                "expected": dns.rrset.from_text("txt.view.example.org.", 0, dns.rdataclass.IN, "TXT", '"else"'),
+                "query": dns.message.make_query("txt.view.example.org", "TXT"),
+            },
         ]
-        for query in queries :
-            res = self.sendUDPQuery(query['query'])
+        for query in queries:
+            res = self.sendUDPQuery(query["query"])
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
-            self.assertRRsetInAnswer(res, query['expected'])
+            self.assertRRsetInAnswer(res, query["expected"])
 
     def testViewNoMatch(self):
         """
         view() test where no netmask match
         """
-        query = dns.message.make_query('none.view.example.org', 'A')
+        query = dns.message.make_query("none.view.example.org", "A")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
@@ -944,10 +920,12 @@ class TestLuaRecords(BaseLuaTest):
         Basic pickwhashed() and pickchashed() test with a set of A records
         As the `bestwho` is hashed, we should always get the same answer
         """
-        for qname in ['whashed.example.org.', 'chashed.example.org.']:
-            expected = [dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '1.2.3.4'),
-                        dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '4.3.2.1')]
-            query = dns.message.make_query(qname, 'A')
+        for qname in ["whashed.example.org.", "chashed.example.org."]:
+            expected = [
+                dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "1.2.3.4"),
+                dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "4.3.2.1"),
+            ]
+            query = dns.message.make_query(qname, "A")
 
             first = self.sendUDPQuery(query)
             self.assertRcodeEqual(first, dns.rcode.NOERROR)
@@ -965,32 +943,30 @@ class TestLuaRecords(BaseLuaTest):
 
         queries = [
             {
-                'query': dns.message.make_query('test.namehashed.example.org', 'A'),
-                'expected': dns.rrset.from_text('test.namehashed.example.org.', 0,
-                                       dns.rdataclass.IN, 'A',
-                                       '1.2.3.4'),
+                "query": dns.message.make_query("test.namehashed.example.org", "A"),
+                "expected": dns.rrset.from_text("test.namehashed.example.org.", 0, dns.rdataclass.IN, "A", "1.2.3.4"),
             },
             {
-                'query': dns.message.make_query('test2.namehashed.example.org', 'A'),
-                'expected': dns.rrset.from_text('test2.namehashed.example.org.', 0,
-                                       dns.rdataclass.IN, 'A',
-                                       '4.3.2.1'),
-            }
+                "query": dns.message.make_query("test2.namehashed.example.org", "A"),
+                "expected": dns.rrset.from_text("test2.namehashed.example.org.", 0, dns.rdataclass.IN, "A", "4.3.2.1"),
+            },
         ]
-        for query in queries :
-            res = self.sendUDPQuery(query['query'])
+        for query in queries:
+            res = self.sendUDPQuery(query["query"])
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
-            self.assertRRsetInAnswer(res, query['expected'])
+            self.assertRRsetInAnswer(res, query["expected"])
 
     def testCWHashedTxt(self):
         """
         Basic pickwhashed() test with a set of TXT records
         As the `bestwho` is hashed, we should always get the same answer
         """
-        for qname in ['whashed-txt.example.org.', 'chashed-txt.example.org.']:
-            expected = [dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'TXT', 'bob'),
-                        dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'TXT', 'alice')]
-            query = dns.message.make_query(qname,'TXT')
+        for qname in ["whashed-txt.example.org.", "chashed-txt.example.org."]:
+            expected = [
+                dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "TXT", "bob"),
+                dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "TXT", "alice"),
+            ]
+            query = dns.message.make_query(qname, "TXT")
 
             first = self.sendUDPQuery(query)
             self.assertRcodeEqual(first, dns.rcode.NOERROR)
@@ -1005,9 +981,11 @@ class TestLuaRecords(BaseLuaTest):
         Basic pickhashed() test with a set of A records
         As the `bestwho` is hashed, we should always get the same answer
         """
-        expected = [dns.rrset.from_text('hashed.example.org.', 0, dns.rdataclass.IN, 'A', '1.2.3.4'),
-                    dns.rrset.from_text('hashed.example.org.', 0, dns.rdataclass.IN, 'A', '4.3.2.1')]
-        query = dns.message.make_query('hashed.example.org', 'A')
+        expected = [
+            dns.rrset.from_text("hashed.example.org.", 0, dns.rdataclass.IN, "A", "1.2.3.4"),
+            dns.rrset.from_text("hashed.example.org.", 0, dns.rdataclass.IN, "A", "4.3.2.1"),
+        ]
+        query = dns.message.make_query("hashed.example.org", "A")
 
         first = self.sendUDPQuery(query)
         self.assertRcodeEqual(first, dns.rcode.NOERROR)
@@ -1022,9 +1000,11 @@ class TestLuaRecords(BaseLuaTest):
         Basic pickhashed() test with a set of AAAA records
         As the `bestwho` is hashed, we should always get the same answer
         """
-        expected = [dns.rrset.from_text('hashed-v6.example.org.', 0, dns.rdataclass.IN, 'AAAA', '2001:db8:a0b:12f0::1'),
-                    dns.rrset.from_text('hashed-v6.example.org.', 0, dns.rdataclass.IN, 'AAAA', 'fe80::2a1:9bff:fe9b:f268')]
-        query = dns.message.make_query('hashed-v6.example.org', 'AAAA')
+        expected = [
+            dns.rrset.from_text("hashed-v6.example.org.", 0, dns.rdataclass.IN, "AAAA", "2001:db8:a0b:12f0::1"),
+            dns.rrset.from_text("hashed-v6.example.org.", 0, dns.rdataclass.IN, "AAAA", "fe80::2a1:9bff:fe9b:f268"),
+        ]
+        query = dns.message.make_query("hashed-v6.example.org", "AAAA")
 
         first = self.sendUDPQuery(query)
         self.assertRcodeEqual(first, dns.rcode.NOERROR)
@@ -1039,9 +1019,11 @@ class TestLuaRecords(BaseLuaTest):
         Basic pickhashed() test with a set of TXT records
         As the `bestwho` is hashed, we should always get the same answer
         """
-        expected = [dns.rrset.from_text('hashed-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'bob'),
-                    dns.rrset.from_text('hashed-txt.example.org.', 0, dns.rdataclass.IN, 'TXT', 'alice')]
-        query = dns.message.make_query('hashed-txt.example.org', 'TXT')
+        expected = [
+            dns.rrset.from_text("hashed-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "bob"),
+            dns.rrset.from_text("hashed-txt.example.org.", 0, dns.rdataclass.IN, "TXT", "alice"),
+        ]
+        query = dns.message.make_query("hashed-txt.example.org", "TXT")
 
         first = self.sendUDPQuery(query)
         self.assertRcodeEqual(first, dns.rcode.NOERROR)
@@ -1056,7 +1038,7 @@ class TestLuaRecords(BaseLuaTest):
         Test that pickwhashed() does not accept zero weights
         """
 
-        query = dns.message.make_query('whashedzero.example.org', 'A')
+        query = dns.message.make_query("whashedzero.example.org", "A")
 
         response = self.sendUDPQuery(query)
         self.assertRcodeEqual(response, dns.rcode.SERVFAIL)
@@ -1066,7 +1048,7 @@ class TestLuaRecords(BaseLuaTest):
         Test that pickwhashed() does not accept negative weights
         """
 
-        query = dns.message.make_query('whashednegative.example.org', 'A')
+        query = dns.message.make_query("whashednegative.example.org", "A")
 
         response = self.sendUDPQuery(query)
         self.assertRcodeEqual(response, dns.rcode.SERVFAIL)
@@ -1075,23 +1057,22 @@ class TestLuaRecords(BaseLuaTest):
         """
         Test if LUA scripts are aborted if script execution takes too long
         """
-        query = dns.message.make_query('timeout.example.org', 'A')
+        query = dns.message.make_query("timeout.example.org", "A")
 
         first = self.sendUDPQuery(query)
         self.assertRcodeEqual(first, dns.rcode.SERVFAIL)
 
-
     def testA(self):
         """
         Test A query against `any`
         """
-        name = 'any.example.org.'
+        name = "any.example.org."
 
-        query = dns.message.make_query(name, 'A')
+        query = dns.message.make_query(name, "A")
 
         response = dns.message.make_response(query)
 
-        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'))
+        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -1102,14 +1083,14 @@ class TestLuaRecords(BaseLuaTest):
         Test ANY query against `any`
         """
 
-        name = 'any.example.org.'
+        name = "any.example.org."
 
-        query = dns.message.make_query(name, 'ANY')
+        query = dns.message.make_query(name, "ANY")
 
         response = dns.message.make_response(query)
 
-        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'))
-        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', '"hello there"'))
+        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
+        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", '"hello there"'))
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -1119,23 +1100,27 @@ class TestLuaRecords(BaseLuaTest):
         """
         Test newCAFromRaw() function
         """
-        name = 'newcafromraw.example.org.'
+        name = "newcafromraw.example.org."
 
-        query = dns.message.make_query(name, 'A')
+        query = dns.message.make_query(name, "A")
 
         response = dns.message.make_response(query)
 
-        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, '65.66.67.68'))
+        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, "65.66.67.68"))
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(res.answer, response.answer)
 
-        query = dns.message.make_query(name, 'AAAA')
+        query = dns.message.make_query(name, "AAAA")
 
         response = dns.message.make_response(query)
 
-        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.AAAA, '4142:4344:3032:3033:3430:3530:3630:3730'))
+        response.answer.append(
+            dns.rrset.from_text(
+                name, 0, dns.rdataclass.IN, dns.rdatatype.AAAA, "4142:4344:3032:3033:3430:3530:3630:3730"
+            )
+        )
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -1145,13 +1130,13 @@ class TestLuaRecords(BaseLuaTest):
         """
         Test resolve() function
         """
-        name = 'resolve.example.org.'
+        name = "resolve.example.org."
 
-        query = dns.message.make_query(name, 'A')
+        query = dns.message.make_query(name, "A")
 
         response = dns.message.make_response(query)
 
-        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.1'))
+        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1"))
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -1161,9 +1146,9 @@ class TestLuaRecords(BaseLuaTest):
         """
         Test filterForward() function with empty fallback
         """
-        name = 'filterforwardempty.example.org.'
+        name = "filterforwardempty.example.org."
 
-        query = dns.message.make_query(name, 'A')
+        query = dns.message.make_query(name, "A")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -1171,51 +1156,63 @@ class TestLuaRecords(BaseLuaTest):
 
     def testCreateForwardAndReverse(self):
         expected = {
-            ".createforward.example.org." : (dns.rdatatype.A, {
-                "1.2.3.4": "1.2.3.4",
-                "1.2.3.4.static": "1.2.3.4",
-                "1.2.3.4.5.6": "1.2.3.4",
-                "invalid.1.2.3.4": "0.0.0.0",
-                "invalid": "0.0.0.0",
-                "1-2-3-4": "1.2.3.4",
-                "1-2-3-4.foo": "1.2.3.4",
-                "1-2-3-4.foo.bar": "1.2.3.4",
-                "1-2-3-4.foo.bar.baz": "0.0.0.0",
-                "1-2-3-4.foo.bar.baz.quux": "0.0.0.0",
-                "ip-1-2-3-4": "1.2.3.4",
-                "ip-is-here-for-you-1-2-3-4": "1.2.3.4",
-                "40414243": "64.65.66.67",
-                "p40414243": "64.65.66.67",
-                "ip40414243": "64.65.66.67",
-                "ipp40414243": "64.65.66.67",
-                "ip4041424": "0.0.0.0",
-                "ip-441424": "0.0.0.0",
-                "ip-5abcdef": "0.0.0.0",
-                "some-text-with-more-than-five-dashes": "0.0.0.0",
-                "host64-22-33-44": "64.22.33.44",
-                "2.2.2.2": "0.0.0.0"   # filtered
-            }),
-            ".createreverse.example.org." : (dns.rdatatype.PTR, {
-                "4.3.2.1": "1-2-3-4.example.com.",
-                "10.10.10.10": "quad10.example.com.",  # exception
-                # error: values not in the 0..255 range
-                "256.384.512.640": "error."
-            }),
-            ".createforward6.example.org." : (dns.rdatatype.AAAA, {
-                "2001--db8" : "2001::db8",
-                "20010002000300040005000600070db8" : "2001:2:3:4:5:6:7:db8",
-                "blabla20010002000300040005000600070db8" : "2001:2:3:4:5:6:7:db8",
-                "4000-db8--1" : "fe80::1",   # filtered, with fallback address override
-                "l1.l2.l3.l4.l5.l6.l7.l8" : "fe80::1"
-            }),
-            ".createreverse6.example.org." : (dns.rdatatype.PTR, {
-                "8.b.d.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2" : "2001--db8.example.com.",
-                "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2" : "example.example.com.",   # exception
-                # error: fewer than 32 labels (including ".createreverse6.example.org.")
-                "8.b.d.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2" : "unknown.",
-                # error: I and O instead of 1 and 0 in the would-be address
-                "O.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.b.c.A.2.F.E.9.C.0.0.3.0.0.2.I" : "error."
-            })
+            ".createforward.example.org.": (
+                dns.rdatatype.A,
+                {
+                    "1.2.3.4": "1.2.3.4",
+                    "1.2.3.4.static": "1.2.3.4",
+                    "1.2.3.4.5.6": "1.2.3.4",
+                    "invalid.1.2.3.4": "0.0.0.0",
+                    "invalid": "0.0.0.0",
+                    "1-2-3-4": "1.2.3.4",
+                    "1-2-3-4.foo": "1.2.3.4",
+                    "1-2-3-4.foo.bar": "1.2.3.4",
+                    "1-2-3-4.foo.bar.baz": "0.0.0.0",
+                    "1-2-3-4.foo.bar.baz.quux": "0.0.0.0",
+                    "ip-1-2-3-4": "1.2.3.4",
+                    "ip-is-here-for-you-1-2-3-4": "1.2.3.4",
+                    "40414243": "64.65.66.67",
+                    "p40414243": "64.65.66.67",
+                    "ip40414243": "64.65.66.67",
+                    "ipp40414243": "64.65.66.67",
+                    "ip4041424": "0.0.0.0",
+                    "ip-441424": "0.0.0.0",
+                    "ip-5abcdef": "0.0.0.0",
+                    "some-text-with-more-than-five-dashes": "0.0.0.0",
+                    "host64-22-33-44": "64.22.33.44",
+                    "2.2.2.2": "0.0.0.0",  # filtered
+                },
+            ),
+            ".createreverse.example.org.": (
+                dns.rdatatype.PTR,
+                {
+                    "4.3.2.1": "1-2-3-4.example.com.",
+                    "10.10.10.10": "quad10.example.com.",  # exception
+                    # error: values not in the 0..255 range
+                    "256.384.512.640": "error.",
+                },
+            ),
+            ".createforward6.example.org.": (
+                dns.rdatatype.AAAA,
+                {
+                    "2001--db8": "2001::db8",
+                    "20010002000300040005000600070db8": "2001:2:3:4:5:6:7:db8",
+                    "blabla20010002000300040005000600070db8": "2001:2:3:4:5:6:7:db8",
+                    "4000-db8--1": "fe80::1",  # filtered, with fallback address override
+                    "l1.l2.l3.l4.l5.l6.l7.l8": "fe80::1",
+                },
+            ),
+            ".createreverse6.example.org.": (
+                dns.rdatatype.PTR,
+                {
+                    "8.b.d.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2": "2001--db8.example.com.",
+                    "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2": "example.example.com.",  # exception
+                    # error: fewer than 32 labels (including ".createreverse6.example.org.")
+                    "8.b.d.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2": "unknown.",
+                    # error: I and O instead of 1 and 0 in the would-be address
+                    "O.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.b.c.A.2.F.E.9.C.0.0.3.0.0.2.I": "error.",
+                },
+            ),
         }
 
         for suffix, v in expected.items():
@@ -1225,8 +1222,7 @@ class TestLuaRecords(BaseLuaTest):
 
                 query = dns.message.make_query(name, qtype)
                 response = dns.message.make_response(query)
-                response.answer.append(dns.rrset.from_text(
-                    name, 0, dns.rdataclass.IN, qtype, target))
+                response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, qtype, target))
 
                 res = self.sendUDPQuery(query)
                 print(res)
@@ -1238,24 +1234,30 @@ class TestLuaRecords(BaseLuaTest):
         Fix #7524
         """
         expected = {
-            ".no-filter.createforward6.example.org." : (dns.rdatatype.AAAA, {
-                "0--0" : "::",
-                "0--1" : "::1",
-                "0aa--0" : "aa::",
-                "0aa--1" : "aa::1",
-                "2001--0" : "2001::",
-                "a-b--c" : "a:b::c",
-                "a--b-c" : "a::b:c"
-            }),
-            ".createreverse6.example.org." : (dns.rdatatype.PTR, {
-                "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0" : "0--0.example.com.",
-                "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0" : "0--1.example.com.",
-                "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.a.a.0.0" : "0aa--0.example.com.",
-                "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.a.a.0.0" : "0aa--1.example.com.",
-                "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2" : "2001--0.example.com.",
-                "c.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.0.0.0.a.0.0.0" : "a-b--c.example.com.",
-                "c.0.0.0.b.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.a.0.0.0" : "a--b-c.example.com."
-            })
+            ".no-filter.createforward6.example.org.": (
+                dns.rdatatype.AAAA,
+                {
+                    "0--0": "::",
+                    "0--1": "::1",
+                    "0aa--0": "aa::",
+                    "0aa--1": "aa::1",
+                    "2001--0": "2001::",
+                    "a-b--c": "a:b::c",
+                    "a--b-c": "a::b:c",
+                },
+            ),
+            ".createreverse6.example.org.": (
+                dns.rdatatype.PTR,
+                {
+                    "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0": "0--0.example.com.",
+                    "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0": "0--1.example.com.",
+                    "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.a.a.0.0": "0aa--0.example.com.",
+                    "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.a.a.0.0": "0aa--1.example.com.",
+                    "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2": "2001--0.example.com.",
+                    "c.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.0.0.0.a.0.0.0": "a-b--c.example.com.",
+                    "c.0.0.0.b.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.a.0.0.0": "a--b-c.example.com.",
+                },
+            ),
         }
 
         for suffix, v in expected.items():
@@ -1265,8 +1267,7 @@ class TestLuaRecords(BaseLuaTest):
 
                 query = dns.message.make_query(name, qtype)
                 response = dns.message.make_response(query)
-                response.answer.append(dns.rrset.from_text(
-                    name, 0, dns.rdataclass.IN, qtype, target))
+                response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, qtype, target))
 
                 res = self.sendUDPQuery(query)
                 print(res)
@@ -1277,9 +1278,9 @@ class TestLuaRecords(BaseLuaTest):
         """
         Helper function for shared/non-shared testing
         """
-        name = 'counter.example.org.'
+        name = "counter.example.org."
 
-        query = dns.message.make_query(name, 'TXT')
+        query = dns.message.make_query(name, "TXT")
         responses = []
 
         sender = self.sendTCPQuery if tcp else self.sendUDPQuery
@@ -1288,7 +1289,7 @@ class TestLuaRecords(BaseLuaTest):
             res = sender(query)
             responses.append(res.answer[0][0])
 
-        return(responses)
+        return responses
 
     def testCounter(self):
         """
@@ -1306,13 +1307,13 @@ class TestLuaRecords(BaseLuaTest):
         Test dblookup() function
         """
 
-        name = 'dblookup.example.org.'
+        name = "dblookup.example.org."
 
-        query = dns.message.make_query(name, 'A')
+        query = dns.message.make_query(name, "A")
 
         response = dns.message.make_response(query)
 
-        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.5'))
+        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.5"))
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -1322,13 +1323,17 @@ class TestLuaRecords(BaseLuaTest):
         """
         Test TXT query for whitespace
         """
-        name = 'whitespace.example.org.'
+        name = "whitespace.example.org."
 
-        query = dns.message.make_query(name, 'TXT')
+        query = dns.message.make_query(name, "TXT")
 
         response = dns.message.make_response(query)
 
-        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.TXT, '"foo   bar"' if expectws else '"foobar"'))
+        response.answer.append(
+            dns.rrset.from_text(
+                name, 0, dns.rdataclass.IN, dns.rdatatype.TXT, '"foo   bar"' if expectws else '"foobar"'
+            )
+        )
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -1338,9 +1343,9 @@ class TestLuaRecords(BaseLuaTest):
         """
         Test GeoIPQueryAttribute enum
         """
-        name = 'geoipqueryattribute.example.org.'
+        name = "geoipqueryattribute.example.org."
 
-        query = dns.message.make_query(name, 'TXT')
+        query = dns.message.make_query(name, "TXT")
 
         response = dns.message.make_response(query)
 
@@ -1376,6 +1381,7 @@ lua-health-checks-interval=1
         self.assertEqual(len(resUDP), 50)
         self.assertEqual(len(resTCP), 50)
 
+
 class TestLuaRecordsNoWhiteSpace(TestLuaRecords):
     _config_template = """
 geoip-database-files=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb
@@ -1390,9 +1396,10 @@ lua-health-checks-interval=1
     def testWhitespace(self):
         return TestLuaRecords.testWhitespace(self, False)
 
+
 class TestLuaRecordsSlowTimeouts(BaseLuaTest):
-     # This configuration is similar to BaseLuaTest, but the health check
-     # interval is increased to 5 seconds.
+    # This configuration is similar to BaseLuaTest, but the health check
+    # interval is increased to 5 seconds.
     _config_template = """
 geoip-database-files=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb
 edns-subnet-processing=yes
@@ -1407,23 +1414,21 @@ lua-health-checks-interval=5
         """
         Simple ifurlup() test with minimumFailures option set.
         """
-        reachable = [
-            '{prefix}.103'.format(prefix=self._PREFIX)
-        ]
-        unreachable = ['192.168.42.105']
+        reachable = ["{prefix}.103".format(prefix=self._PREFIX)]
+        unreachable = ["192.168.42.105"]
         ips = reachable + unreachable
         all_rrs = []
         reachable_rrs = []
         unreachable_rrs = []
         for ip in ips:
-            rr = dns.rrset.from_text('usa-unreachable.example.org.', 0, dns.rdataclass.IN, 'A', ip)
+            rr = dns.rrset.from_text("usa-unreachable.example.org.", 0, dns.rdataclass.IN, "A", ip)
             all_rrs.append(rr)
             if ip in reachable:
                 reachable_rrs.append(rr)
             else:
                 unreachable_rrs.append(rr)
 
-        query = dns.message.make_query('usa-unreachable.example.org', 'A')
+        query = dns.message.make_query("usa-unreachable.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, all_rrs)
@@ -1456,23 +1461,21 @@ lua-health-checks-interval=5
         """
         Simple ifurlup() test with interval option set.
         """
-        reachable = [
-            '{prefix}.103'.format(prefix=self._PREFIX)
-        ]
-        unreachable = ['192.168.42.105']
+        reachable = ["{prefix}.103".format(prefix=self._PREFIX)]
+        unreachable = ["192.168.42.105"]
         ips = reachable + unreachable
         all_rrs = []
         reachable_rrs = []
         unreachable_rrs = []
         for ip in ips:
-            rr = dns.rrset.from_text('usa-slowcheck.example.org.', 0, dns.rdataclass.IN, 'A', ip)
+            rr = dns.rrset.from_text("usa-slowcheck.example.org.", 0, dns.rdataclass.IN, "A", ip)
             all_rrs.append(rr)
             if ip in reachable:
                 reachable_rrs.append(rr)
             else:
                 unreachable_rrs.append(rr)
 
-        query = dns.message.make_query('usa-slowcheck.example.org', 'A')
+        query = dns.message.make_query("usa-slowcheck.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, all_rrs)
@@ -1498,13 +1501,13 @@ lua-health-checks-interval=5
         """
         Simple ifurlup() test with failOnIncompleteCheck option set.
         """
-        ips = ['192.168.42.105']
+        ips = ["192.168.42.105"]
         all_rrs = []
         for ip in ips:
-            rr = dns.rrset.from_text('usa-failincomplete.example.org.', 0, dns.rdataclass.IN, 'A', ip)
+            rr = dns.rrset.from_text("usa-failincomplete.example.org.", 0, dns.rdataclass.IN, "A", ip)
             all_rrs.append(rr)
 
-        query = dns.message.make_query('usa-failincomplete.example.org', 'A')
+        query = dns.message.make_query("usa-failincomplete.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
@@ -1518,9 +1521,10 @@ lua-health-checks-interval=5
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, all_rrs)
 
+
 class TestLuaRecordsExecLimit(BaseLuaTest):
-     # This configuration is similar to BaseLuaTest, but the exec limit is
-     # set to a very low value.
+    # This configuration is similar to BaseLuaTest, but the exec limit is
+    # set to a very low value.
     _config_template = """
 geoip-database-files=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb
 edns-subnet-processing=yes
@@ -1535,13 +1539,14 @@ lua-records-exec-limit=1
         """
         Test A query against `any`, failing due to exec-limit
         """
-        name = 'any.example.org.'
+        name = "any.example.org."
 
-        query = dns.message.make_query(name, 'A')
+        query = dns.message.make_query(name, "A")
 
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     unittest.main()
     exit(0)
index beffea331b8870d5dcf7107d4a10f8229977178a..520b8003673d1d979c0342cfcd877cc0b73ca427 100644 (file)
@@ -4,8 +4,9 @@ import dns
 
 from authtests import AuthTest
 
+
 class TestLuaRecordsLMDB(AuthTest):
-    _backend = 'lmdb'
+    _backend = "lmdb"
 
     _config_template = """
 launch=lmdb
@@ -13,7 +14,7 @@ enable-lua-records
 """
 
     _zones = {
-        'example.org': """
+        "example.org": """
 example.org.                 3600 IN SOA  {soa}
 example.org.                 3600 IN NS   ns1.example.org.
 example.org.                 3600 IN NS   ns2.example.org.
@@ -37,16 +38,21 @@ nested-lua.example.org.      3600 IN LUA  A   ( ";include('config') "
         Basic pickrandom() test with a set of A records, with a bit of lua inclusion
         """
 
-        expected = [dns.rrset.from_text('nested-lua.example.org.', 0, dns.rdataclass.IN, 'A',
-                                        '{prefix}.101'.format(prefix=self._PREFIX)),
-                    dns.rrset.from_text('nested-lua.example.org.', 0, dns.rdataclass.IN, 'A',
-                                        '{prefix}.102'.format(prefix=self._PREFIX))]
+        expected = [
+            dns.rrset.from_text(
+                "nested-lua.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.101".format(prefix=self._PREFIX)
+            ),
+            dns.rrset.from_text(
+                "nested-lua.example.org.", 0, dns.rdataclass.IN, "A", "{prefix}.102".format(prefix=self._PREFIX)
+            ),
+        ]
 
-        query = dns.message.make_query('nested-lua.example.org', 'A')
+        query = dns.message.make_query("nested-lua.example.org", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnyRRsetInAnswer(res, expected)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     unittest.main()
     exit(0)
index 6cd5f1db7811f62c288efa9d0618d43bcc187f36..f438aec73025cfd4e762a1b350c8d1654d3b2cc0 100644 (file)
@@ -8,6 +8,7 @@ import subprocess
 from authtests import AuthTest
 from proxyprotocol import ProxyProtocol
 
+
 class TestProxyProtocolLuaRecords(AuthTest):
     _config_template = """
 launch={backend}
@@ -18,7 +19,7 @@ edns-subnet-processing=yes
 """
 
     _zones = {
-        'example.org': """
+        "example.org": """
 example.org.                 3600 IN SOA  {soa}
 example.org.                 3600 IN NS   ns1.example.org.
 example.org.                 3600 IN NS   ns2.example.org.
@@ -37,24 +38,25 @@ myip.example.org.            3600 IN LUA  TXT     "who:toString()..'/'..bestwho:
         """
         See if LUA who picks up the inner address from the PROXY protocol
         """
-        
+
         for testWithECS in True, False:
             # first test with an unproxied query - should get ignored
 
             options = []
-            expectedText = '192.0.2.1/192.0.2.1'
+            expectedText = "192.0.2.1/192.0.2.1"
 
             if testWithECS:
-                ecso = clientsubnetoption.ClientSubnetOption('192.0.2.5', 32)
+                ecso = clientsubnetoption.ClientSubnetOption("192.0.2.5", 32)
                 options.append(ecso)
-                expectedText = '192.0.2.1/192.0.2.5'
+                expectedText = "192.0.2.1/192.0.2.5"
 
-            query = dns.message.make_query('myip.example.org', 'TXT', 'IN', use_edns=testWithECS, options=options, payload=512)
+            query = dns.message.make_query(
+                "myip.example.org", "TXT", "IN", use_edns=testWithECS, options=options, payload=512
+            )
 
             res = self.sendUDPQuery(query)
 
-            self.assertEqual(res, None)     # query was ignored correctly
-
+            self.assertEqual(res, None)  # query was ignored correctly
 
             # now send a proxied query
             queryPayload = query.to_wire()
@@ -76,7 +78,7 @@ myip.example.org.            3600 IN LUA  TXT     "who:toString()..'/'..bestwho:
             if data:
                 res = dns.message.from_wire(data)
 
-            expected = [dns.rrset.from_text('myip.example.org.', 0, dns.rdataclass.IN, 'TXT', expectedText)]
+            expected = [dns.rrset.from_text("myip.example.org.", 0, dns.rdataclass.IN, "TXT", expectedText)]
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertEqual(res.answer, expected)
 
@@ -109,6 +111,7 @@ myip.example.org.            3600 IN LUA  TXT     "who:toString()..'/'..bestwho:
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertEqual(res.answer, expected)
 
+
 class TestProxyProtocolNOTIFY(AuthTest):
     _config_template = """
 launch={backend}
@@ -117,53 +120,58 @@ proxy-protocol-from=127.0.0.1
 secondary
 """
 
-    _secondary_zones = { 'example.org': '192.0.2.1',
-               'example.com': '192.0.2.2'
-    }
+    _secondary_zones = {"example.org": "192.0.2.1", "example.com": "192.0.2.2"}
 
     _zones = {}
 
     @classmethod
     def generateAuthZone(cls, confdir, zonename, zonecontent):
         try:
-            os.unlink(os.path.join(confdir, '%s.zone' % zonename))
+            os.unlink(os.path.join(confdir, "%s.zone" % zonename))
         except Exception:
             pass
 
     @classmethod
     def generateAuthConfig(cls, confdir):
         super(TestProxyProtocolNOTIFY, cls).generateAuthConfig(confdir)
-        if cls._backend == 'lmdb':
+        if cls._backend == "lmdb":
             for zonename in cls._secondary_zones:
-                pdnsutilCmd = [os.environ['PDNSUTIL'],
-                   '--config-dir=%s' % confdir,
-                   'create-secondary-zone',
-                   zonename,
-                   cls._secondary_zones[zonename]]
-
-                print(' '.join(pdnsutilCmd))
+                pdnsutilCmd = [
+                    os.environ["PDNSUTIL"],
+                    "--config-dir=%s" % confdir,
+                    "create-secondary-zone",
+                    zonename,
+                    cls._secondary_zones[zonename],
+                ]
+
+                print(" ".join(pdnsutilCmd))
                 try:
                     subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
                 except subprocess.CalledProcessError as e:
-                    raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+                    raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
     @classmethod
     def generateAuthNamedConf(cls, confdir, zones):
-        with open(os.path.join(confdir, 'named.conf'), 'w') as namedconf:
-            namedconf.write("""
+        with open(os.path.join(confdir, "named.conf"), "w") as namedconf:
+            namedconf.write(
+                """
 options {
     directory "%s";
-};""" % confdir)
+};"""
+                % confdir
+            )
             for zonename in cls._secondary_zones:
-                zone = '.' if zonename == 'ROOT' else zonename
+                zone = "." if zonename == "ROOT" else zonename
 
-                namedconf.write("""
+                namedconf.write(
+                    """
         zone "%s" {
             type secondary;
             file "%s.zone";
             masters { %s; };
-        };""" % (zone, zonename, cls._secondary_zones[zone]))
-
+        };"""
+                    % (zone, zonename, cls._secondary_zones[zone])
+                )
 
     @classmethod
     def setUpClass(cls):
@@ -174,12 +182,12 @@ options {
         Check that NOTIFY is properly accepted/rejected based on the PROXY header inner address
         """
 
-        query = dns.message.make_query('example.org', 'SOA')
+        query = dns.message.make_query("example.org", "SOA")
         query.set_opcode(dns.opcode.NOTIFY)
 
         queryPayload = query.to_wire()
 
-        for task in ('192.0.2.1', dns.rcode.NOERROR), ('192.0.2.2', dns.rcode.REFUSED):
+        for task in ("192.0.2.1", dns.rcode.NOERROR), ("192.0.2.2", dns.rcode.REFUSED):
             ip, expectedrcode = task
 
             ppPayload = ProxyProtocol.getPayload(False, False, False, ip, "10.1.2.3", 12345, 53, [])
@@ -219,11 +227,15 @@ allow-axfr-ips=192.0.2.53
         Check that AXFR is properly accepted/rejected based on the PROXY header inner address
         """
 
-        query = dns.message.make_query('example.org', 'AXFR')
+        query = dns.message.make_query("example.org", "AXFR")
 
         queryPayload = query.to_wire()
 
-        for task in ('192.0.2.1', dns.rcode.NOTAUTH), ('127.0.0.1', dns.rcode.NOTAUTH), ('192.0.2.53', dns.rcode.NOERROR):
+        for task in (
+            ("192.0.2.1", dns.rcode.NOTAUTH),
+            ("127.0.0.1", dns.rcode.NOTAUTH),
+            ("192.0.2.53", dns.rcode.NOERROR),
+        ):
             ip, expectedrcode = task
 
             ppPayload = ProxyProtocol.getPayload(False, True, False, ip, "10.1.2.3", 12345, 53, [])
index 7d753e3a119438c8677a41f4cd293ce5082ad2b1..c43105fdddd35f047b880b6c12ea58b992fc206d 100644 (file)
@@ -51,9 +51,7 @@ resolve-across-zones=no
     )
 
     def impl_cname_only_test(self, qname, target):
-        expected_cname = dns.rrset.from_text(
-            qname, 0, dns.rdataclass.IN, "CNAME", target
-        )
+        expected_cname = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "CNAME", target)
         query = dns.message.make_query(qname, "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -64,9 +62,7 @@ resolve-across-zones=no
         self.impl_cname_only_test("cname-otherzone.example.org.", "target.example.com.")
 
     def testCNAMESubZone(self):
-        self.impl_cname_only_test(
-            "cname-subzone.example.org.", "target.subzone.example.org."
-        )
+        self.impl_cname_only_test("cname-subzone.example.org.", "target.subzone.example.org.")
 
 
 class TestCrossZoneResolveOn(CrossZoneResolveBase):
@@ -78,12 +74,8 @@ resolve-across-zones=yes
     )
 
     def impl_cname_and_target_test(self, qname, target, target_ip):
-        expected_cname = dns.rrset.from_text(
-            qname, 0, dns.rdataclass.IN, "CNAME", target
-        )
-        expected_target = dns.rrset.from_text(
-            target, 0, dns.rdataclass.IN, "A", target_ip
-        )
+        expected_cname = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "CNAME", target)
+        expected_target = dns.rrset.from_text(target, 0, dns.rdataclass.IN, "A", target_ip)
         query = dns.message.make_query(qname, "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
index 613ee6c6429a424c24d38de95aaa6d94e4c9c2c1..4f41727e57c7f14fcf283115c70623ff72df1760 100644 (file)
@@ -3,13 +3,14 @@ import dns
 import os
 import subprocess
 
+
 class SVCBRecordsBase(AuthTest):
     _config_template = """
 svc-autohints
 """
 
     _zones = {
-        'example.org': """
+        "example.org": """
 example.org.                 3600 IN SOA  {soa}
 example.org.                 3600 IN NS   ns1.example.org.
 example.org.                 3600 IN NS   ns2.example.org.
@@ -40,11 +41,10 @@ auto-aaaa.example.org.       3600 IN AAAA 2001:db8::80
     }
 
     def impl_testWithoutAlias(self):
-        query = dns.message.make_query('www.example.org', 'HTTPS')
+        query = dns.message.make_query("www.example.org", "HTTPS")
         res = self.sendUDPQuery(query)
         expected_ans = dns.rrset.from_text(
-            'www.example.org.', 3600, dns.rdataclass.IN, 'HTTPS',
-            '1 . ipv4hint="192.0.2.80" ipv6hint="2001:db8::80"'
+            "www.example.org.", 3600, dns.rdataclass.IN, "HTTPS", '1 . ipv4hint="192.0.2.80" ipv6hint="2001:db8::80"'
         )
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected_ans)
@@ -54,16 +54,12 @@ auto-aaaa.example.org.       3600 IN AAAA 2001:db8::80
         """
         Ensure additional processing happens for HTTPS AliasMode
         """
-        query = dns.message.make_query('example.org', 'HTTPS')
+        query = dns.message.make_query("example.org", "HTTPS")
         res = self.sendUDPQuery(query)
         expected_addl = dns.rrset.from_text(
-            'www.example.org.', 3600, dns.rdataclass.IN, 'HTTPS',
-            '1 . ipv4hint="192.0.2.80" ipv6hint="2001:db8::80"'
-        )
-        expected_ans = dns.rrset.from_text(
-            'example.org.', 3600, dns.rdataclass.IN, 'HTTPS',
-            '0 www.example.org.'
+            "www.example.org.", 3600, dns.rdataclass.IN, "HTTPS", '1 . ipv4hint="192.0.2.80" ipv6hint="2001:db8::80"'
         )
+        expected_ans = dns.rrset.from_text("example.org.", 3600, dns.rdataclass.IN, "HTTPS", "0 www.example.org.")
         print(res.answer)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected_ans)
@@ -74,11 +70,10 @@ auto-aaaa.example.org.       3600 IN AAAA 2001:db8::80
         """
         Ensure PowerDNS removes the ipv4hint if there's no A record
         """
-        query = dns.message.make_query('no-a.example.org', 'HTTPS')
+        query = dns.message.make_query("no-a.example.org", "HTTPS")
         res = self.sendUDPQuery(query)
         expected_ans = dns.rrset.from_text(
-            'no-a.example.org.', 3600, dns.rdataclass.IN, 'HTTPS',
-            '1 . ipv6hint="2001:db8::81"'
+            "no-a.example.org.", 3600, dns.rdataclass.IN, "HTTPS", '1 . ipv6hint="2001:db8::81"'
         )
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected_ans)
@@ -88,11 +83,10 @@ auto-aaaa.example.org.       3600 IN AAAA 2001:db8::80
         """
         Ensure PowerDNS removes the ipv6hint if there's no AAAA record
         """
-        query = dns.message.make_query('no-aaaa.example.org', 'HTTPS')
+        query = dns.message.make_query("no-aaaa.example.org", "HTTPS")
         res = self.sendUDPQuery(query)
         expected_ans = dns.rrset.from_text(
-            'no-aaaa.example.org.', 3600, dns.rdataclass.IN, 'HTTPS',
-            '1 . ipv4hint="192.0.2.81"'
+            "no-aaaa.example.org.", 3600, dns.rdataclass.IN, "HTTPS", '1 . ipv4hint="192.0.2.81"'
         )
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected_ans)
@@ -102,11 +96,14 @@ auto-aaaa.example.org.       3600 IN AAAA 2001:db8::80
         """
         Ensure we send the actual hints, not generated ones
         """
-        query = dns.message.make_query('no-auto.example.org', 'HTTPS')
+        query = dns.message.make_query("no-auto.example.org", "HTTPS")
         res = self.sendUDPQuery(query)
         expected_ans = dns.rrset.from_text(
-            'no-auto.example.org.', 3600, dns.rdataclass.IN, 'HTTPS',
-            '1 . ipv4hint="192.0.2.81" ipv6hint="2001:db8::81"'
+            "no-auto.example.org.",
+            3600,
+            dns.rdataclass.IN,
+            "HTTPS",
+            '1 . ipv4hint="192.0.2.81" ipv6hint="2001:db8::81"',
         )
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         print(res)
@@ -117,11 +114,10 @@ auto-aaaa.example.org.       3600 IN AAAA 2001:db8::80
         """
         Ensure we send a generated A hint, but keep the existing AAAA hint
         """
-        query = dns.message.make_query('auto-a.example.org', 'HTTPS')
+        query = dns.message.make_query("auto-a.example.org", "HTTPS")
         res = self.sendUDPQuery(query)
         expected_ans = dns.rrset.from_text(
-            'auto-a.example.org.', 3600, dns.rdataclass.IN, 'HTTPS',
-            '1 . ipv4hint="192.0.2.80" ipv6hint="2001:db8::81"'
+            "auto-a.example.org.", 3600, dns.rdataclass.IN, "HTTPS", '1 . ipv4hint="192.0.2.80" ipv6hint="2001:db8::81"'
         )
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         print(res)
@@ -132,17 +128,21 @@ auto-aaaa.example.org.       3600 IN AAAA 2001:db8::80
         """
         Ensure we send a generated AAAA hint, but keep the existing A hint
         """
-        query = dns.message.make_query('auto-aaaa.example.org', 'HTTPS')
+        query = dns.message.make_query("auto-aaaa.example.org", "HTTPS")
         res = self.sendUDPQuery(query)
         expected_ans = dns.rrset.from_text(
-            'auto-aaaa.example.org.', 3600, dns.rdataclass.IN, 'HTTPS',
-            '1 . ipv4hint="192.0.2.81" ipv6hint="2001:db8::80"'
+            "auto-aaaa.example.org.",
+            3600,
+            dns.rdataclass.IN,
+            "HTTPS",
+            '1 . ipv4hint="192.0.2.81" ipv6hint="2001:db8::80"',
         )
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         print(res)
         self.assertRRsetInAnswer(res, expected_ans)
         self.assertEqual(len(res.additional), 2)
 
+
 class TestSVCBRecordsBind(SVCBRecordsBase):
     _backend = "bind"
 
@@ -200,8 +200,9 @@ launch={backend}
         """
         self.impl_testAutoAAAA()
 
+
 class TestSVCBRecordsLMDB(SVCBRecordsBase):
-    _backend='lmdb'
+    _backend = "lmdb"
 
     _config_template = (
         SVCBRecordsBase._config_template
@@ -218,20 +219,20 @@ launch=lmdb
         cls.generateAuthConfig(confdir)
 
         for zonename, zonecontent in cls._zones.items():
-            cls.generateAuthZone(confdir,
-                                 zonename,
-                                 zonecontent)
-            pdnsutilCmd = [os.environ['PDNSUTIL'],
-                           '--config-dir=%s' % confdir,
-                           'load-zone',
-                           zonename,
-                           os.path.join(confdir, '%s.zone' % zonename)]
-
-            print(' '.join(pdnsutilCmd))
+            cls.generateAuthZone(confdir, zonename, zonecontent)
+            pdnsutilCmd = [
+                os.environ["PDNSUTIL"],
+                "--config-dir=%s" % confdir,
+                "load-zone",
+                zonename,
+                os.path.join(confdir, "%s.zone" % zonename),
+            ]
+
+            print(" ".join(pdnsutilCmd))
             try:
                 subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
             except subprocess.CalledProcessError as e:
-                raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+                raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
     def testWithoutAlias(self):
         self.impl_testWithoutAlias()
index ac06abeba787a5f07e203a93dc8db70e6b30c757..c3476cfebc889d50ea8f1ef66a275e60ab70907d 100644 (file)
@@ -8,13 +8,13 @@ import time
 
 from authtests import AuthTest
 
-class BadXFRServer(object):
 
+class BadXFRServer(object):
     def __init__(self, port):
         self._currentSerial = 0
         self._targetSerial = 1
         self._serverPort = port
-        listener = threading.Thread(name='XFR Listener', target=self._listener, args=[])
+        listener = threading.Thread(name="XFR Listener", target=self._listener, args=[])
         listener.setDaemon(True)
         listener.start()
 
@@ -25,7 +25,7 @@ class BadXFRServer(object):
         if newSerial == self._currentSerial or newSerial == self._targetSerial:
             return False
 
-        #if newSerial != self._currentSerial + 1:
+        # if newSerial != self._currentSerial + 1:
         #    raise AssertionError("Asking the XFR server to serve serial %d, already serving %d" % (newSerial, self._currentSerial))
         self._targetSerial = newSerial
         print("moveToSerial %d" % newSerial, file=sys.stderr)
@@ -38,15 +38,29 @@ class BadXFRServer(object):
 
         if message.question[0].rdtype == dns.rdatatype.AXFR:
             if self._currentSerial != 0:
-                print('Received an AXFR query but IXFR expected because the current serial is %d' % (self._currentSerial))
+                print(
+                    "Received an AXFR query but IXFR expected because the current serial is %d" % (self._currentSerial)
+                )
                 return (None, self._currentSerial)
 
             newSerial = self._targetSerial
             records = [
-                dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                dns.rrset.from_text('a.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                ]
+                dns.rrset.from_text(
+                    "zone.rpz.",
+                    60,
+                    dns.rdataclass.IN,
+                    dns.rdatatype.SOA,
+                    "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                ),
+                dns.rrset.from_text("a.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                dns.rrset.from_text(
+                    "zone.rpz.",
+                    60,
+                    dns.rdataclass.IN,
+                    dns.rdatatype.SOA,
+                    "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                ),
+            ]
 
         elif message.question[0].rdtype == dns.rdatatype.IXFR:
             oldSerial = message.authority[0][0].serial
@@ -54,17 +68,41 @@ class BadXFRServer(object):
             newSerial = self._targetSerial
             if newSerial == 2:
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
                     # no deletion
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('b.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("b.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                ]
             elif newSerial == 3:
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('a.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("a.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                ]
 
         response.answer = records
         return (newSerial, response)
@@ -84,15 +122,18 @@ class BadXFRServer(object):
 
             message = dns.message.from_wire(data)
             if len(message.question) != 1:
-                print('Invalid query, qdcount is %d' % (len(message.question)), file=sys.stderr)
+                print("Invalid query, qdcount is %d" % (len(message.question)), file=sys.stderr)
                 break
             if not message.question[0].rdtype in [dns.rdatatype.AXFR, dns.rdatatype.IXFR]:
-                print('Invalid query, qtype is %d' % (message.question.rdtype), file=sys.stderr)
+                print("Invalid query, qtype is %d" % (message.question.rdtype), file=sys.stderr)
                 break
             print(message, file=sys.stderr)
             (serial, answer) = self._getAnswer(message)
             if not answer:
-                print('Unable to get a response for %s %d' % (message.question[0].name, message.question[0].rdtype), file=sys.stderr)
+                print(
+                    "Unable to get a response for %s %d" % (message.question[0].name, message.question[0].rdtype),
+                    file=sys.stderr,
+                )
                 break
 
             wire = answer.to_wire()
@@ -119,19 +160,19 @@ class BadXFRServer(object):
             try:
                 (conn, _) = sock.accept()
                 print("New connection", file=sys.stderr)
-                thread = threading.Thread(name='IXFR Connection Handler',
-                                      target=self._connectionHandler,
-                                      args=[conn])
+                thread = threading.Thread(name="IXFR Connection Handler", target=self._connectionHandler, args=[conn])
                 thread.setDaemon(True)
                 thread.start()
 
             except socket.error as e:
-                print('Error in IXFR socket: %s' % str(e))
+                print("Error in IXFR socket: %s" % str(e))
                 sock.close()
 
+
 badxfrServerPort = 4251
 badxfrServer = BadXFRServer(badxfrServerPort)
 
+
 class XFRIncompleteAuthTest(AuthTest):
     """
     This test makes sure that we correctly detect incomplete RPZ zones via AXFR then IXFR
@@ -139,7 +180,7 @@ class XFRIncompleteAuthTest(AuthTest):
 
     global badxfrServerPort
 
-    _backend = 'gsqlite3'
+    _backend = "gsqlite3"
 
     _config_template = """
 launch=gsqlite3
@@ -158,9 +199,11 @@ xfr-cycle-interval=1
     @classmethod
     def setUpClass(cls):
         super(XFRIncompleteAuthTest, cls).setUpClass()
-        os.system("$PDNSUTIL --config-dir=configs/auth create-secondary-zone zone.rpz. 127.0.0.1:%s" % (badxfrServerPort,))
+        os.system(
+            "$PDNSUTIL --config-dir=configs/auth create-secondary-zone zone.rpz. 127.0.0.1:%s" % (badxfrServerPort,)
+        )
         os.system("$PDNSUTIL --config-dir=configs/auth set-meta zone.rpz. IXFR 1")
-    
+
     def waitUntilCorrectSerialIsLoaded(self, serial, timeout=20):
         global badxfrServer
 
@@ -172,19 +215,30 @@ xfr-cycle-interval=1
             if currentSerial > serial:
                 raise AssertionError("Expected serial %d, got %d" % (serial, currentSerial))
             if currentSerial == serial:
-                badxfrServer.moveToSerial(serial+1)
+                badxfrServer.moveToSerial(serial + 1)
                 return
 
             attempts = attempts + 1
             time.sleep(1)
 
-        raise AssertionError("Waited %d seconds for the serial to be updated to %d but the serial is still %d" % (timeout, serial, currentSerial))
+        raise AssertionError(
+            "Waited %d seconds for the serial to be updated to %d but the serial is still %d"
+            % (timeout, serial, currentSerial)
+        )
 
     def checkZone(self):
-        query = dns.message.make_query('zone.rpz.', 'SOA')
-        res = self.sendUDPQuery(query) # , count=len(expected))
-
-        expected = [dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. 1 3600 3600 3600 1')]
+        query = dns.message.make_query("zone.rpz.", "SOA")
+        res = self.sendUDPQuery(query)  # , count=len(expected))
+
+        expected = [
+            dns.rrset.from_text(
+                "zone.rpz.",
+                60,
+                dns.rdataclass.IN,
+                dns.rdatatype.SOA,
+                "ns.zone.rpz. hostmaster.zone.rpz. 1 3600 3600 3600 1",
+            )
+        ]
         self.assertEqual(res.answer, expected)
 
     def doRetrieve(self):
index 812bdea67228b2d0f19cfc68e8d53ae3ba1c716c..b961e4dccec8243801b6ca8fdacb93040d9823bd 100644 (file)
@@ -1,6 +1,7 @@
 import requests
 from authtests import AuthTest
 
+
 class TestBasic(AuthTest):
     _config_template = """
     launch = {backend}
@@ -15,9 +16,10 @@ class TestBasic(AuthTest):
         super(TestBasic, cls).setUpClass()
 
     def test_basic(self):
-        r = requests.get('http://127.0.0.1:8053')
+        r = requests.get("http://127.0.0.1:8053")
         self.assertEqual(r.status_code, 200)
 
+
 class TestDualStack(AuthTest):
     _config_template = """
     launch = {backend}
@@ -32,9 +34,10 @@ class TestDualStack(AuthTest):
         super(TestDualStack, cls).setUpClass()
 
     def test_ds(self):
-        r = requests.get('http://127.0.0.1:8053')
+        r = requests.get("http://127.0.0.1:8053")
         self.assertEqual(r.status_code, 200)
 
+
 class TestDualStackBackwardsCompat(AuthTest):
     _config_template = """
     launch = {backend}
@@ -45,9 +48,10 @@ class TestDualStackBackwardsCompat(AuthTest):
     """
 
     def test_ds_compat(self):
-        r = requests.get('http://127.0.0.1:8053')
+        r = requests.get("http://127.0.0.1:8053")
         self.assertEqual(r.status_code, 200)
 
+
 class TestUnauthorized(AuthTest):
     _config_template = """
     launch = {backend}
@@ -59,11 +63,12 @@ class TestUnauthorized(AuthTest):
 
     def test_unauthorized(self):
         try:
-            requests.get('http://127.0.0.1:8053')
+            requests.get("http://127.0.0.1:8053")
             self.fail()
         except requests.exceptions.ConnectionError:
             pass
 
+
 class TestUnauthorizedDualStack(AuthTest):
     _config_template = """
     launch = {backend}
@@ -75,8 +80,7 @@ class TestUnauthorizedDualStack(AuthTest):
 
     def test_unauthorized(self):
         try:
-            requests.get('http://127.0.0.1:8053')
+            requests.get("http://127.0.0.1:8053")
             self.fail()
         except requests.exceptions.ConnectionError:
             pass
-
index 0677b0dbbd7d411f9c2fb7cc81a4b387a92a5eee..50b8b70fd8c557d9a76f045bd0248aad243f92f7 100644 (file)
@@ -4,8 +4,9 @@ import copy
 import socket
 import struct
 
+
 class ProxyProtocol(object):
-    MAGIC = b'\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A'
+    MAGIC = b"\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a"
     # Header is magic + versioncommand (1) + family (1) + content length (2)
     HEADER_SIZE = len(MAGIC) + 1 + 1 + 2
     PORT_SIZE = 2
@@ -17,10 +18,10 @@ class ProxyProtocol(object):
         if len(data) < self.HEADER_SIZE:
             return False
 
-        if data[:len(self.MAGIC)] != self.MAGIC:
+        if data[: len(self.MAGIC)] != self.MAGIC:
             return False
 
-        value = struct.unpack('!B', bytes(bytearray([data[12]])))[0]
+        value = struct.unpack("!B", bytes(bytearray([data[12]])))[0]
         self.version = value >> 4
         if self.version != 0x02:
             return False
@@ -32,7 +33,7 @@ class ProxyProtocol(object):
         if self.command == 0x00:
             self.local = True
         elif self.command == 0x01:
-            value = struct.unpack('!B', bytes(bytearray([data[13]])))[0]
+            value = struct.unpack("!B", bytes(bytearray([data[13]])))[0]
             self.family = value >> 4
             if self.family == 0x01:
                 self.addrSize = 4
@@ -65,9 +66,9 @@ class ProxyProtocol(object):
 
         value = None
         if self.family == 0x01:
-            value = socket.inet_ntop(socket.AF_INET, data[self.offset:self.offset + self.addrSize])
+            value = socket.inet_ntop(socket.AF_INET, data[self.offset : self.offset + self.addrSize])
         else:
-            value = socket.inet_ntop(socket.AF_INET6, data[self.offset:self.offset + self.addrSize])
+            value = socket.inet_ntop(socket.AF_INET6, data[self.offset : self.offset + self.addrSize])
 
         self.offset = self.offset + self.addrSize
         return value
@@ -76,7 +77,7 @@ class ProxyProtocol(object):
         if len(data) < (self.consumed() + self.PORT_SIZE):
             return False
 
-        value = struct.unpack('!H', data[self.offset:self.offset + self.PORT_SIZE])[0]
+        value = struct.unpack("!H", data[self.offset : self.offset + self.PORT_SIZE])[0]
         self.offset = self.offset + self.PORT_SIZE
         return value
 
@@ -108,14 +109,14 @@ class ProxyProtocol(object):
         while remaining >= 3:
             valueType = struct.unpack("!B", bytes(bytearray([data[self.offset]])))[0]
             self.offset = self.offset + 1
-            valueLen = struct.unpack("!H", data[self.offset:self.offset+2])[0]
+            valueLen = struct.unpack("!H", data[self.offset : self.offset + 2])[0]
             self.offset = self.offset + 2
 
             remaining = remaining - 3
             if valueLen > 0:
                 if valueLen > remaining:
                     return False
-                self.values.append([valueType, data[self.offset:self.offset+valueLen]])
+                self.values.append([valueType, data[self.offset : self.offset + valueLen]])
                 self.offset = self.offset + valueLen
                 remaining = remaining - valueLen
 
@@ -134,7 +135,7 @@ class ProxyProtocol(object):
         else:
             command = 0x01
 
-        value = struct.pack('!B', (version << 4) + command)
+        value = struct.pack("!B", (version << 4) + command)
         payload = payload + value
 
         addrSize = 0
@@ -154,12 +155,12 @@ class ProxyProtocol(object):
                 family = 0x02
                 addrSize = 16
 
-        value = struct.pack('!B', (family << 4)  + protocol)
+        value = struct.pack("!B", (family << 4) + protocol)
         payload = payload + value
 
         contentSize = 0
         if not local:
-            contentSize = contentSize + addrSize * 2 + cls.PORT_SIZE *2
+            contentSize = contentSize + addrSize * 2 + cls.PORT_SIZE * 2
 
         valuesSize = 0
         for value in values:
@@ -167,8 +168,8 @@ class ProxyProtocol(object):
 
         contentSize = contentSize + valuesSize
 
-        value = struct.pack('!H', contentSize)
-        payload = payload +  value
+        value = struct.pack("!H", contentSize)
+        payload = payload + value
 
         if not local:
             if family == 0x01:
@@ -180,14 +181,14 @@ class ProxyProtocol(object):
             payload = payload + value
             value = socket.inet_pton(af, destination)
             payload = payload + value
-            value = struct.pack('!H', sourcePort)
+            value = struct.pack("!H", sourcePort)
             payload = payload + value
-            value = struct.pack('!H', destinationPort)
+            value = struct.pack("!H", destinationPort)
             payload = payload + value
 
         for value in values:
-            valueType = struct.pack('!B', value[0])
-            valueLen = struct.pack('!H', len(value[1]))
+            valueType = struct.pack("!B", value[0])
+            valueLen = struct.pack("!H", len(value[1]))
             payload = payload + valueType + valueLen + value[1]
 
         return payload
index 83ab109d53951cdef2ddbaa8d86e004caf501619..43fd270d4d28161cc0c8b4cb68b29c07fdae36bd 100644 (file)
 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-""" Class to implement draft-ietf-dnsop-edns-client-subnet (previously known as
+"""Class to implement draft-ietf-dnsop-edns-client-subnet (previously known as
 draft-vandergaast-edns-client-subnet.
 
 The contained class supports both IPv4 and IPv6 addresses.
 Requirements:
   dnspython (http://www.dnspython.org/)
 """
+
 from __future__ import print_function
 from __future__ import division
 
@@ -77,11 +78,11 @@ class ClientSubnetOption(dns.edns.Option):
                 n = socket.inet_pton(family, ip)
                 if family == socket.AF_INET6:
                     f = FAMILY_IPV6
-                    hi, lo = struct.unpack('!QQ', n)
+                    hi, lo = struct.unpack("!QQ", n)
                     ip = hi << 64 | lo
                 elif family == socket.AF_INET:
                     f = FAMILY_IPV4
-                    ip = struct.unpack('!L', n)[0]
+                    ip = struct.unpack("!L", n)[0]
             except Exception:
                 pass
 
@@ -117,13 +118,13 @@ class ClientSubnetOption(dns.edns.Option):
 
         ip = self.ip >> bits - self.mask
 
-        if (self.mask % 8 != 0):
+        if self.mask % 8 != 0:
             ip = ip << 8 - (self.mask % 8)
 
         return ip
 
     def is_draft(self):
-        """" Determines whether this instance is using the draft option code """
+        """ " Determines whether this instance is using the draft option code"""
         return self.option == DRAFT_OPTION_CODE
 
     def to_wire(self, file=None):
@@ -133,13 +134,13 @@ class ClientSubnetOption(dns.edns.Option):
 
         mask_bits = self.mask
         if mask_bits % 8 != 0:
-                mask_bits += 8 - (self.mask % 8)
+            mask_bits += 8 - (self.mask % 8)
 
         if self.family == FAMILY_IPV4:
             test = struct.pack("!L", ip)
         elif self.family == FAMILY_IPV6:
-            test = struct.pack("!QQ", ip >> 64, ip & (2 ** 64 - 1))
-        test = test[-(mask_bits // 8):]
+            test = struct.pack("!QQ", ip >> 64, ip & (2**64 - 1))
+        test = test[-(mask_bits // 8) :]
 
         format = "!HBB%ds" % (mask_bits // 8)
         data = struct.pack(format, self.family, self.mask, self.scope, test)
@@ -155,7 +156,7 @@ class ClientSubnetOption(dns.edns.Option):
             An instance of ClientSubnetOption based on the ENDS packet
         """
 
-        data = wire[current:current + olen]
+        data = wire[current : current + olen]
         (family, mask, scope) = struct.unpack("!HBB", data[:4])
 
         c_mask = mask
@@ -164,11 +165,11 @@ class ClientSubnetOption(dns.edns.Option):
 
         ip = struct.unpack_from("!%ds" % (c_mask // 8), data, 4)[0]
 
-        if (family == FAMILY_IPV4):
-            ip = ip + b'\0' * ((32 - c_mask) // 8)
+        if family == FAMILY_IPV4:
+            ip = ip + b"\0" * ((32 - c_mask) // 8)
             ip = socket.inet_ntop(socket.AF_INET, ip)
-        elif (family == FAMILY_IPV6):
-            ip = ip + b'\0' * ((128 - c_mask) // 8)
+        elif family == FAMILY_IPV6:
+            ip = ip + b"\0" * ((128 - c_mask) // 8)
             ip = socket.inet_ntop(socket.AF_INET6, ip)
         else:
             raise Exception("Returned a family other then IPv4 or IPv6")
@@ -180,35 +181,27 @@ class ClientSubnetOption(dns.edns.Option):
     # needed in 2.0.0..
     @classmethod
     def from_wire_parser(cls, otype, parser):
-        family, src, scope = parser.get_struct('!HBB')
+        family, src, scope = parser.get_struct("!HBB")
         addrlen = int(math.ceil(src / 8.0))
         prefix = parser.get_bytes(addrlen)
         if family == 1:
             pad = 4 - addrlen
-            addr = dns.ipv4.inet_ntoa(prefix + b'\x00' * pad)
+            addr = dns.ipv4.inet_ntoa(prefix + b"\x00" * pad)
         elif family == 2:
             pad = 16 - addrlen
-            addr = dns.ipv6.inet_ntoa(prefix + b'\x00' * pad)
+            addr = dns.ipv6.inet_ntoa(prefix + b"\x00" * pad)
         else:
-            raise ValueError('unsupported family')
+            raise ValueError("unsupported family")
 
         return cls(addr, src, scope, otype)
 
     def __repr__(self):
         if self.family == FAMILY_IPV4:
-            ip = socket.inet_ntop(socket.AF_INET, struct.pack('!L', self.ip))
+            ip = socket.inet_ntop(socket.AF_INET, struct.pack("!L", self.ip))
         elif self.family == FAMILY_IPV6:
-            ip = socket.inet_ntop(socket.AF_INET6,
-                                  struct.pack('!QQ',
-                                              self.ip >> 64,
-                                              self.ip & (2 ** 64 - 1)))
-
-        return "%s(%s, %s, %s)" % (
-            self.__class__.__name__,
-            ip,
-            self.mask,
-            self.scope
-        )
+            ip = socket.inet_ntop(socket.AF_INET6, struct.pack("!QQ", self.ip >> 64, self.ip & (2**64 - 1)))
+
+        return "%s(%s, %s, %s)" % (self.__class__.__name__, ip, self.mask, self.scope)
 
     def to_text(self):
         return self.__repr__()
@@ -280,13 +273,25 @@ if __name__ == "__main__":
                 print("Found ClientSubnetOption...", end=None, file=sys.stderr)
                 if not cso.family == options.family:
                     error = True
-                    print("\nFailed: returned family (%d) is different from the passed family (%d)" % (options.family, cso.family), file=sys.stderr)
+                    print(
+                        "\nFailed: returned family (%d) is different from the passed family (%d)"
+                        % (options.family, cso.family),
+                        file=sys.stderr,
+                    )
                 if not cso.calculate_ip() == options.calculate_ip():
                     error = True
-                    print("\nFailed: returned ip (%s) is different from the passed ip (%s)." % (options.calculate_ip(), cso.calculate_ip()), file=sys.stderr)
+                    print(
+                        "\nFailed: returned ip (%s) is different from the passed ip (%s)."
+                        % (options.calculate_ip(), cso.calculate_ip()),
+                        file=sys.stderr,
+                    )
                 if not options.mask == cso.mask:
                     error = True
-                    print("\nFailed: returned mask bits (%d) is different from the passed mask bits (%d)" % (options.mask, cso.mask), file=sys.stderr)
+                    print(
+                        "\nFailed: returned mask bits (%d) is different from the passed mask bits (%d)"
+                        % (options.mask, cso.mask),
+                        file=sys.stderr,
+                    )
                 if not options.scope != 0:
                     print("\nWarning: scope indicates edns-clientsubnet data is not used", file=sys.stderr)
                 if options.is_draft():
@@ -299,17 +304,19 @@ if __name__ == "__main__":
         else:
             print("Failed: No ClientSubnetOption returned", file=sys.stderr)
 
-    parser = argparse.ArgumentParser(description='draft-vandergaast-edns-client-subnet-01 tester')
-    parser.add_argument('nameserver', help='The nameserver to test')
-    parser.add_argument('rr', help='DNS record that should return an EDNS enabled response')
-    parser.add_argument('-s', '--subnet', help='Specifies an IP to pass as the client subnet.', default='192.0.2.0')
-    parser.add_argument('-m', '--mask', type=int, help='CIDR mask to use for subnet')
-    parser.add_argument('--timeout', type=int, help='Set the timeout for query to TIMEOUT seconds, default=10', default=10)
-    parser.add_argument('-t', '--type', help='DNS query type, default=A', default='A')
+    parser = argparse.ArgumentParser(description="draft-vandergaast-edns-client-subnet-01 tester")
+    parser.add_argument("nameserver", help="The nameserver to test")
+    parser.add_argument("rr", help="DNS record that should return an EDNS enabled response")
+    parser.add_argument("-s", "--subnet", help="Specifies an IP to pass as the client subnet.", default="192.0.2.0")
+    parser.add_argument("-m", "--mask", type=int, help="CIDR mask to use for subnet")
+    parser.add_argument(
+        "--timeout", type=int, help="Set the timeout for query to TIMEOUT seconds, default=10", default=10
+    )
+    parser.add_argument("-t", "--type", help="DNS query type, default=A", default="A")
     args = parser.parse_args()
 
     if not args.mask:
-        if ':' in args.subnet:
+        if ":" in args.subnet:
             args.mask = 48
         else:
             args.mask = 24
index 0cc42a9ebbb1d4c14ed0acd8c4512712f2e66ece..1a3cea919a2152d46dbb5f513486f1a44839dfe5 100644 (file)
@@ -6,18 +6,18 @@ import dns.flags
 import dns.message
 import dns.query
 
+
 class CookiesOption(dns.edns.Option):
-    """Implementation of draft-ietf-dnsop-cookies-09.
-    """
+    """Implementation of draft-ietf-dnsop-cookies-09."""
 
     def __init__(self, client, server):
         super(CookiesOption, self).__init__(10)
 
         if len(client) != 8:
-            raise Exception('invalid client cookie length')
+            raise Exception("invalid client cookie length")
 
         if server is not None and len(server) != 0 and (len(server) < 8 or len(server) > 32):
-            raise Exception('invalid server cookie length')
+            raise Exception("invalid server cookie length")
 
         self.client = client
         self.server = server
@@ -42,9 +42,9 @@ class CookiesOption(dns.edns.Option):
             An instance of CookiesOption based on the EDNS packet
         """
 
-        data = wire[current:current + olen]
+        data = wire[current : current + olen]
         if len(data) != 8 and (len(data) < 16 or len(data) > 40):
-            raise Exception('Invalid EDNS Cookies option')
+            raise Exception("Invalid EDNS Cookies option")
 
         client = data[:8]
         if len(data) > 8:
@@ -62,7 +62,7 @@ class CookiesOption(dns.edns.Option):
         data = parser.get_remaining()
 
         if len(data) != 8 and (len(data) < 16 or len(data) > 40):
-            raise Exception('Invalid EDNS Cookies option')
+            raise Exception("Invalid EDNS Cookies option")
 
         client = data[:8]
         if len(data) > 8:
@@ -73,11 +73,7 @@ class CookiesOption(dns.edns.Option):
         return cls(client, server)
 
     def __repr__(self):
-        return '%s(%s, %s)' % (
-            self.__class__.__name__,
-            self.client,
-            self.server
-        )
+        return "%s(%s, %s)" % (self.__class__.__name__, self.client, self.server)
 
     def to_text(self):
         return self.__repr__()
index 0153677b203315041ec82836bde6ffbd84328bd1..dcd829e56fdcf5bbf47472dcfaab06035819c8d4 100644 (file)
@@ -9,10 +9,11 @@ import libnacl.utils
 import binascii
 from builtins import bytes
 
+
 class DNSCryptResolverCertificate(object):
-    DNSCRYPT_CERT_MAGIC = b'\x44\x4e\x53\x43'
-    DNSCRYPT_ES_VERSION = b'\x00\x01'
-    DNSCRYPT_PROTOCOL_MIN_VERSION = b'\x00\x00'
+    DNSCRYPT_CERT_MAGIC = b"\x44\x4e\x53\x43"
+    DNSCRYPT_ES_VERSION = b"\x00\x01"
+    DNSCRYPT_PROTOCOL_MIN_VERSION = b"\x00\x00"
 
     def __init__(self, serial, validFrom, validUntil, publicKey, clientMagic):
         self.serial = serial
@@ -34,7 +35,11 @@ class DNSCryptResolverCertificate(object):
         esVersion = binary[4:6]
         protocolMinVersion = binary[6:8]
 
-        if certMagic != DNSCryptResolverCertificate.DNSCRYPT_CERT_MAGIC or esVersion != DNSCryptResolverCertificate.DNSCRYPT_ES_VERSION or protocolMinVersion != DNSCryptResolverCertificate.DNSCRYPT_PROTOCOL_MIN_VERSION:
+        if (
+            certMagic != DNSCryptResolverCertificate.DNSCRYPT_CERT_MAGIC
+            or esVersion != DNSCryptResolverCertificate.DNSCRYPT_ES_VERSION
+            or protocolMinVersion != DNSCryptResolverCertificate.DNSCRYPT_PROTOCOL_MIN_VERSION
+        ):
             raise Exception("Invalid binary certificate")
 
         orig = libnacl.crypto_sign_open(binary[8:124], providerFP)
@@ -46,12 +51,13 @@ class DNSCryptResolverCertificate(object):
         validUntil = struct.unpack_from("!I", orig[48:52])[0]
         return DNSCryptResolverCertificate(serial, validFrom, validUntil, resolverPK, clientMagic)
 
+
 class DNSCryptClient(object):
     DNSCRYPT_NONCE_SIZE = 24
     DNSCRYPT_MAC_SIZE = 16
     DNSCRYPT_PADDED_BLOCK_SIZE = 64
     DNSCRYPT_MIN_UDP_LENGTH = 256
-    DNSCRYPT_RESOLVER_MAGIC = b'\x72\x36\x66\x6e\x76\x57\x6a\x38'
+    DNSCRYPT_RESOLVER_MAGIC = b"\x72\x36\x66\x6e\x76\x57\x6a\x38"
 
     @staticmethod
     def _addrToSocketType(addr):
@@ -67,7 +73,7 @@ class DNSCryptClient(object):
 
     def __init__(self, providerName, providerFingerprint, resolverAddress, resolverPort=443, timeout=2):
         self._providerName = providerName
-        self._providerFingerprint = binascii.unhexlify(providerFingerprint.lower().replace(':', ''))
+        self._providerFingerprint = binascii.unhexlify(providerFingerprint.lower().replace(":", ""))
         self._resolverAddress = resolverAddress
         self._resolverPort = resolverPort
         self._resolverCertificates = []
@@ -165,7 +171,7 @@ class DNSCryptClient(object):
     @staticmethod
     def _generateNonce():
         nonce = libnacl.utils.rand_nonce()
-        return nonce[:int(DNSCryptClient.DNSCRYPT_NONCE_SIZE / 2)]
+        return nonce[: int(DNSCryptClient.DNSCRYPT_NONCE_SIZE / 2)]
 
     def _encryptQuery(self, queryContent, resolverCert, nonce, tcp=False):
         header = resolverCert.clientMagic + self._publicKey + nonce
@@ -176,14 +182,14 @@ class DNSCryptClient(object):
             paddingSize += self.DNSCRYPT_MIN_UDP_LENGTH - requiredSize
             requiredSize = self.DNSCRYPT_MIN_UDP_LENGTH
 
-        padding = b'\x80'
+        padding = b"\x80"
         idx = 0
         while idx < (paddingSize - 1):
-            padding = padding + b'\x00'
+            padding = padding + b"\x00"
             idx += 1
 
         data = queryContent + padding
-        nonce = nonce + (b'\x00'*int(self.DNSCRYPT_NONCE_SIZE / 2))
+        nonce = nonce + (b"\x00" * int(self.DNSCRYPT_NONCE_SIZE / 2))
         box = libnacl.crypto_box(data, nonce, resolverCert.publicKey, self._privateKey)
         return header + box
 
@@ -193,7 +199,7 @@ class DNSCryptClient(object):
             raise Exception("Invalid encrypted response: bad resolver magic")
 
         nonce = encryptedResponse[8:32]
-        if nonce[0:int(self.DNSCRYPT_NONCE_SIZE / 2)] != clientNonce:
+        if nonce[0 : int(self.DNSCRYPT_NONCE_SIZE / 2)] != clientNonce:
             raise Exception("Invalid encrypted response: bad nonce")
 
         cleartext = libnacl.crypto_box_open(encryptedResponse[32:], nonce, resolverCert.publicKey, self._privateKey)
@@ -209,7 +215,7 @@ class DNSCryptClient(object):
 
         idx -= 1
 
-        return cleartext[:idx+1]
+        return cleartext[: idx + 1]
 
     def query(self, queryContent, tcp=False):
 
index 4b62b2b08b1e8e0b054d3c27aca570723d6c74ce..3c80fadd1127bb545128657103deb1db5d9248bf 100644 (file)
@@ -6,27 +6,32 @@ from dnsdisttests import DNSDistTest, pickAvailablePort
 
 _maintenanceWaitTime = 2
 
+
 def waitForMaintenanceToRun():
     time.sleep(_maintenanceWaitTime)
 
-class DynBlocksTest(DNSDistTest):
 
+class DynBlocksTest(DNSDistTest):
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
+    _webServerBasicAuthPassword = "secret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
     _dynBlockQPS = 10
     _dynBlockANYQPS = 10
     _dynBlockPeriod = 2
     # this needs to be greater than maintenanceWaitTime
     _dynBlockDuration = _maintenanceWaitTime + 2
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _config_params = ["_dynBlockQPS", "_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
 
     def doTestDynBlockViaAPI(self, ipRange, reason, minSeconds, maxSeconds, minBlocks, maxBlocks, ebpf=False):
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/jsonstat?command=dynblocklist'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/jsonstat?command=dynblocklist"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -36,24 +41,20 @@ class DynBlocksTest(DNSDistTest):
         self.assertIn(ipRange, content)
 
         values = content[ipRange]
-        for key in ['reason', 'seconds', 'blocks', 'action', 'ebpf']:
+        for key in ["reason", "seconds", "blocks", "action", "ebpf"]:
             self.assertIn(key, values)
 
-        self.assertEqual(values['reason'], reason)
-        self.assertGreaterEqual(values['seconds'], minSeconds)
-        self.assertLessEqual(values['seconds'], maxSeconds)
-        self.assertGreaterEqual(values['blocks'], minBlocks)
-        self.assertLessEqual(values['blocks'], maxBlocks)
-        self.assertEqual(values['ebpf'], True if ebpf else False)
+        self.assertEqual(values["reason"], reason)
+        self.assertGreaterEqual(values["seconds"], minSeconds)
+        self.assertLessEqual(values["seconds"], maxSeconds)
+        self.assertGreaterEqual(values["blocks"], minBlocks)
+        self.assertLessEqual(values["blocks"], maxBlocks)
+        self.assertEqual(values["ebpf"], True if ebpf else False)
 
     def doTestQRate(self, name, testViaAPI=True, ebpf=False):
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         allowed = 0
@@ -83,7 +84,15 @@ class DynBlocksTest(DNSDistTest):
         self.assertEqual(receivedResponse, None)
 
         if testViaAPI:
-            self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', 1, self._dynBlockDuration, (sent-allowed)+1, (sent-allowed)+1, ebpf)
+            self.doTestDynBlockViaAPI(
+                "127.0.0.1/32",
+                "Exceeded query rate",
+                1,
+                self._dynBlockDuration,
+                (sent - allowed) + 1,
+                (sent - allowed) + 1,
+                ebpf,
+            )
 
         # wait until we are not blocked anymore
         time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
@@ -131,7 +140,7 @@ class DynBlocksTest(DNSDistTest):
         self.assertEqual(response, receivedResponse)
 
     def doTestQTypeRate(self, name):
-        query = dns.message.make_query(name, 'ANY', 'IN')
+        query = dns.message.make_query(name, "ANY", "IN")
         response = dns.message.make_response(query)
         blockedResponse = dns.message.make_response(query)
         blockedResponse.set_rcode(dns.rcode.REFUSED)
@@ -172,13 +181,9 @@ class DynBlocksTest(DNSDistTest):
         self.assertEqual(response, receivedResponse)
 
     def doTestQRateRCode(self, name, rcode):
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(rcode)
@@ -257,18 +262,14 @@ class DynBlocksTest(DNSDistTest):
         self.assertEqual(response, receivedResponse)
 
     def doTestResponseByteRate(self, name, dynBlockBytesPerSecond):
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        response.answer.append(dns.rrset.from_text_list(name,
-                                                       60,
-                                                       dns.rdataclass.IN,
-                                                       dns.rdatatype.A,
-                                                       ['192.0.2.1', '192.0.2.2', '192.0.2.3', '192.0.2.4']))
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.AAAA,
-                                                   '2001:DB8::1'))
+        response.answer.append(
+            dns.rrset.from_text_list(
+                name, 60, dns.rdataclass.IN, dns.rdatatype.A, ["192.0.2.1", "192.0.2.2", "192.0.2.3", "192.0.2.4"]
+            )
+        )
+        response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1"))
 
         allowed = 0
         sent = 0
@@ -300,7 +301,7 @@ class DynBlocksTest(DNSDistTest):
         self.assertGreaterEqual(allowed, dynBlockBytesPerSecond)
 
         print(self.sendConsoleCommand("showDynBlocks()"))
-        print(self.sendConsoleCommand("grepq(\"\")"))
+        print(self.sendConsoleCommand('grepq("")'))
         print(time.time())
 
         if allowed == sent:
@@ -308,7 +309,7 @@ class DynBlocksTest(DNSDistTest):
             waitForMaintenanceToRun()
 
         print(self.sendConsoleCommand("showDynBlocks()"))
-        print(self.sendConsoleCommand("grepq(\"\")"))
+        print(self.sendConsoleCommand('grepq("")'))
         print(time.time())
 
         # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
@@ -316,14 +317,14 @@ class DynBlocksTest(DNSDistTest):
         self.assertEqual(receivedResponse, None)
 
         print(self.sendConsoleCommand("showDynBlocks()"))
-        print(self.sendConsoleCommand("grepq(\"\")"))
+        print(self.sendConsoleCommand('grepq("")'))
         print(time.time())
 
         # wait until we are not blocked anymore
         time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
 
         print(self.sendConsoleCommand("showDynBlocks()"))
-        print(self.sendConsoleCommand("grepq(\"\")"))
+        print(self.sendConsoleCommand('grepq("")'))
         print(time.time())
 
         # this one should succeed
@@ -373,13 +374,9 @@ class DynBlocksTest(DNSDistTest):
         self.assertEqual(response, receivedResponse)
 
     def doTestRCodeRate(self, name, rcode):
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(rcode)
@@ -485,21 +482,17 @@ class DynBlocksTest(DNSDistTest):
 
     def doTestRCodeRatioViaProtocol(self, name, rcode, noerrorcount, rcodecount, method, cached=False):
         sender = getattr(self, method)
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
-        rcodeQuery = dns.message.make_query('rcode-' + name, 'A', 'IN')
+        rcodeQuery = dns.message.make_query("rcode-" + name, "A", "IN")
         expectedResponse = dns.message.make_response(rcodeQuery)
         expectedResponse.set_rcode(rcode)
 
         firstQuery = True
         # start with normal responses
-        for _ in range(noerrorcount-1):
+        for _ in range(noerrorcount - 1):
             if cached and not firstQuery:
                 # should be a cache hit
                 (receivedQuery, receivedResponse) = sender(query, response=None, useQueue=False)
@@ -564,14 +557,10 @@ class DynBlocksTest(DNSDistTest):
         self.doTestRCodeRatioViaProtocol(name, rcode, noerrorcount, rcodecount, "sendTCPQuery")
 
     def doTestCacheMissRatio(self, name, cacheHits, cacheMisses):
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
 
         for idx in range(cacheMisses):
-            query = dns.message.make_query(str(idx) + '.' + name, 'A', 'IN')
+            query = dns.message.make_query(str(idx) + "." + name, "A", "IN")
             response = dns.message.make_response(query)
             response.answer.append(rrset)
             (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -584,7 +573,7 @@ class DynBlocksTest(DNSDistTest):
                 # let's clear the response queue
                 self.clearToResponderQueue()
 
-        query = dns.message.make_query('0.' + name, 'A', 'IN')
+        query = dns.message.make_query("0." + name, "A", "IN")
         response = dns.message.make_response(query)
         response.answer.append(rrset)
         for _ in range(cacheHits):
@@ -600,7 +589,7 @@ class DynBlocksTest(DNSDistTest):
         time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
 
         # this one should succeed
-        query = dns.message.make_query(str(cacheMisses + 1) + name, 'A', 'IN')
+        query = dns.message.make_query(str(cacheMisses + 1) + name, "A", "IN")
         response = dns.message.make_response(query)
         response.answer.append(rrset)
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
index ad44b2f53ca1075486495f82c88e518e6a85efe0..22d541ec946561e9320a5d75ff65884e1f62c3a8 100644 (file)
@@ -5,12 +5,11 @@ import unittest
 from dnsdisttests import DNSDistTest
 
 
-@unittest.skipIf('SKIP_DOH_TESTS' in os.environ, 'DNS over HTTPS tests are disabled')
+@unittest.skipIf("SKIP_DOH_TESTS" in os.environ, "DNS over HTTPS tests are disabled")
 class DNSDistDOHTest(DNSDistTest):
-
     def getHeaderValue(self, name):
         for header in self._response_headers.decode().splitlines(False):
-            values = header.split(':')
+            values = header.split(":")
             key = values[0]
             if key.lower() == name.lower():
                 return values[1].strip()
@@ -27,8 +26,8 @@ class DNSDistDOHTest(DNSDistTest):
     def setUpClass(cls):
 
         # for some reason, @unittest.skipIf() is not applied to derived classes with some versions of Python
-        if 'SKIP_DOH_TESTS' in os.environ:
-            raise unittest.SkipTest('DNS over HTTPS tests are disabled')
+        if "SKIP_DOH_TESTS" in os.environ:
+            raise unittest.SkipTest("DNS over HTTPS tests are disabled")
 
         cls.startResponders()
         cls.startDNSDist()
index 3f3fa2eac18afbd9daf3634721a22202f7befa60..80f69d77ae1cef03845e9b1e74d69abc8c14581b 100644 (file)
@@ -36,39 +36,45 @@ from proxyprotocol import ProxyProtocol
 
 # Python2/3 compatibility hacks
 try:
-  from queue import Queue
+    from queue import Queue
 except ImportError:
-  from Queue import Queue
+    from Queue import Queue
 
 try:
-  range = xrange
+    range = xrange
 except NameError:
-  pass
+    pass
+
 
 def getWorkerID():
-    if not 'PYTEST_XDIST_WORKER' in os.environ:
-      return 0
-    workerName = os.environ['PYTEST_XDIST_WORKER']
+    if not "PYTEST_XDIST_WORKER" in os.environ:
+        return 0
+    workerName = os.environ["PYTEST_XDIST_WORKER"]
     return int(workerName[2:])
 
+
 workerPorts = {}
 
+
 def pickAvailablePort():
     global workerPorts
     workerID = getWorkerID()
     if workerID in workerPorts:
-      port = workerPorts[workerID] + 1
+        port = workerPorts[workerID] + 1
     else:
-      port = 11000 + (workerID * 1000)
+        port = 11000 + (workerID * 1000)
     workerPorts[workerID] = port
     return port
 
+
 class ResponderDropAction(object):
     """
     An object to indicate a drop action shall be taken
     """
+
     pass
 
+
 class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     """
     Set up a dnsdist instance and responder threads.
@@ -78,6 +84,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     from dnsdist on a separate queue, allowing the tests to check
     that the queries sent from dnsdist were as expected.
     """
+
     _dnsDistListeningAddr = "127.0.0.1"
     _toResponderQueue = Queue()
     _fromResponderQueue = Queue()
@@ -86,12 +93,12 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     _responsesCounter = {}
     _config_template = """
     """
-    _config_params = ['_testServerPort']
+    _config_params = ["_testServerPort"]
     _yaml_config_template = None
     _yaml_config_params = []
-    _acl = ['127.0.0.1/32']
+    _acl = ["127.0.0.1/32"]
     _consoleKey = None
-    _healthCheckName = 'a.root-servers.net.'
+    _healthCheckName = "a.root-servers.net."
     _healthCheckCounter = 0
     _answerUnexpected = True
     _checkConfigExpectedOutput = None
@@ -121,22 +128,31 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
                 return
             except Exception as err:
                 if err.errno != errno.ECONNREFUSED:
-                    print(f'Error occurred: {try_number} {err}', file=sys.stderr)
+                    print(f"Error occurred: {try_number} {err}", file=sys.stderr)
             time.sleep(0.1)
-       # We assume the dnsdist instance does not listen. That's fine.
+
+    # We assume the dnsdist instance does not listen. That's fine.
 
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
         cls._testServerPort = pickAvailablePort()
 
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
-        cls.waitForTCPSocket("127.0.0.1", cls._testServerPort);
+        cls.waitForTCPSocket("127.0.0.1", cls._testServerPort)
 
     @classmethod
     def startDNSDist(cls):
@@ -145,87 +161,100 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
 
         print("Launching dnsdist..")
         if cls._yaml_config_template:
-            if 'SKIP_YAML_TESTS' in os.environ:
-                raise unittest.SkipTest('YAML tests are disabled')
+            if "SKIP_YAML_TESTS" in os.environ:
+                raise unittest.SkipTest("YAML tests are disabled")
 
             params = tuple([getattr(cls, param) for param in cls._yaml_config_params])
-            confFile = os.path.join('configs', 'dnsdist_%s.yml' % (cls.__name__))
-            with open(confFile, 'w') as conf:
+            confFile = os.path.join("configs", "dnsdist_%s.yml" % (cls.__name__))
+            with open(confFile, "w") as conf:
                 conf.write(cls._yaml_config_template % params)
                 conf.write("\nsecurity_polling:\n  suffix: ''\n")
 
         params = tuple([getattr(cls, param) for param in cls._config_params])
         print(params)
-        extension = 'lua' if cls._yaml_config_template else 'conf'
-        luaConfFile = os.path.join('configs', 'dnsdist_%s.%s' % (cls.__name__, extension))
+        extension = "lua" if cls._yaml_config_template else "conf"
+        luaConfFile = os.path.join("configs", "dnsdist_%s.%s" % (cls.__name__, extension))
         if not cls._yaml_config_template:
-          confFile = luaConfFile
-
-        if len(cls._config_template.strip(' \n\t')) > 0:
-          with open(luaConfFile, 'w') as conf:
-            conf.write("-- Autogenerated by dnsdisttests.py\n")
-            conf.write(f"-- dnsdist will listen on {cls._dnsDistPort}\n")
-            conf.write(cls._config_template % params)
-            if not cls._yaml_config_template:
-              conf.write("\n")
-              conf.write("setSecurityPollSuffix('')")
+            confFile = luaConfFile
+
+        if len(cls._config_template.strip(" \n\t")) > 0:
+            with open(luaConfFile, "w") as conf:
+                conf.write("-- Autogenerated by dnsdisttests.py\n")
+                conf.write(f"-- dnsdist will listen on {cls._dnsDistPort}\n")
+                conf.write(cls._config_template % params)
+                if not cls._yaml_config_template:
+                    conf.write("\n")
+                    conf.write("setSecurityPollSuffix('')")
         else:
-          try:
-            os.unlink(luaConfFile)
-          except OSError:
-            pass
+            try:
+                os.unlink(luaConfFile)
+            except OSError:
+                pass
 
         if cls._skipListeningOnCL:
-          dnsdistcmd = [os.environ['DNSDISTBIN'], '--supervised', '-C', confFile ]
+            dnsdistcmd = [os.environ["DNSDISTBIN"], "--supervised", "-C", confFile]
         else:
-          dnsdistcmd = [os.environ['DNSDISTBIN'], '--supervised', '-C', confFile,
-                        '-l', '%s:%d' % (cls._dnsDistListeningAddr, cls._dnsDistPort) ]
+            dnsdistcmd = [
+                os.environ["DNSDISTBIN"],
+                "--supervised",
+                "-C",
+                confFile,
+                "-l",
+                "%s:%d" % (cls._dnsDistListeningAddr, cls._dnsDistPort),
+            ]
 
         if cls._verboseMode:
-            dnsdistcmd.append('-v')
+            dnsdistcmd.append("-v")
 
-        dnsdistcmd.append('--structured-logging')
-        dnsdistcmd.append('true' if cls._enableStructuredLoggingOnCL else 'false')
+        dnsdistcmd.append("--structured-logging")
+        dnsdistcmd.append("true" if cls._enableStructuredLoggingOnCL else "false")
 
         if cls._sudoMode:
-            preserve_env_values = ['LD_LIBRARY_PATH', 'LLVM_PROFILE_FILE']
+            preserve_env_values = ["LD_LIBRARY_PATH", "LLVM_PROFILE_FILE"]
             for value in preserve_env_values:
                 if value in os.environ:
-                    dnsdistcmd.insert(0, value + '=' + os.environ[value])
-            dnsdistcmd.insert(0, 'sudo')
+                    dnsdistcmd.insert(0, value + "=" + os.environ[value])
+            dnsdistcmd.insert(0, "sudo")
 
         for acl in cls._acl:
-            dnsdistcmd.extend(['--acl', acl])
-        print(' '.join(dnsdistcmd))
+            dnsdistcmd.extend(["--acl", acl])
+        print(" ".join(dnsdistcmd))
 
         # validate config with --check-config, which sets client=true, possibly exposing bugs.
-        testcmd = dnsdistcmd + ['--check-config']
+        testcmd = dnsdistcmd + ["--check-config"]
         try:
             output = subprocess.check_output(testcmd, stderr=subprocess.STDOUT, close_fds=True)
         except subprocess.CalledProcessError as exc:
-            raise AssertionError('dnsdist --check-config failed (%d): %s' % (exc.returncode, exc.output))
+            raise AssertionError("dnsdist --check-config failed (%d): %s" % (exc.returncode, exc.output))
 
         if cls._checkConfigExpectedOutputPrefix is not None:
             if not output.startswith(cls._checkConfigExpectedOutputPrefix):
-                raise AssertionError('dnsdist --check-config failed: %s (expected prefix %s)' % (output, cls._checkConfigExpectedOutputPrefix))
+                raise AssertionError(
+                    "dnsdist --check-config failed: %s (expected prefix %s)"
+                    % (output, cls._checkConfigExpectedOutputPrefix)
+                )
         else:
             if cls._checkConfigExpectedOutput is not None:
                 expectedOutput = cls._checkConfigExpectedOutput
                 if not cls._verboseMode and output != expectedOutput:
-                  raise AssertionError('dnsdist --check-config failed: %s (expected %s)' % (output, expectedOutput))
+                    raise AssertionError("dnsdist --check-config failed: %s (expected %s)" % (output, expectedOutput))
             elif not cls._verboseMode:
                 if cls._enableStructuredLoggingOnCL:
                     expectedPrefix = b'msg="Configuration OK" subsystem="setup" level="0" prio="Info" ts="'
                     if not output.startswith(expectedPrefix):
-                        raise AssertionError('dnsdist --check-config failed: %s (expected prefix %s)' % (output, expectedPrefix))
+                        raise AssertionError(
+                            "dnsdist --check-config failed: %s (expected prefix %s)" % (output, expectedPrefix)
+                        )
                 else:
-                    expectedOutput = ('Configuration \'%s\' OK!\n' % (confFile)).encode()
+                    expectedOutput = ("Configuration '%s' OK!\n" % (confFile)).encode()
                     if output != expectedOutput:
-                        raise AssertionError('dnsdist --check-config failed: %s (expected %s)' % (output, expectedOutput))
+                        raise AssertionError(
+                            "dnsdist --check-config failed: %s (expected %s)" % (output, expectedOutput)
+                        )
 
-        logFile = os.path.join('configs', 'dnsdist_%s.log' % (cls.__name__))
-        with open(logFile, 'w') as fdLog:
-          cls._dnsdist = subprocess.Popen(dnsdistcmd, close_fds=True, stdout=fdLog, stderr=fdLog)
+        logFile = os.path.join("configs", "dnsdist_%s.log" % (cls.__name__))
+        with open(logFile, "w") as fdLog:
+            cls._dnsdist = subprocess.Popen(dnsdistcmd, close_fds=True, stdout=fdLog, stderr=fdLog)
 
         if cls._alternateListeningAddr and cls._alternateListeningPort:
             cls.waitForTCPSocket(cls._alternateListeningAddr, cls._alternateListeningPort)
@@ -234,10 +263,10 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
 
         if cls._dnsdist.poll() is not None:
             print(f"\n*** startDNSDist log for {logFile} ***")
-            with open(logFile, 'r') as fdLog:
+            with open(logFile, "r") as fdLog:
                 print(fdLog.read())
             print(f"*** End startDNSDist log for {logFile} ***")
-            raise AssertionError('%s failed (%d)' % (dnsdistcmd, cls._dnsdist.returncode))
+            raise AssertionError("%s failed (%d)" % (dnsdistcmd, cls._dnsdist.returncode))
         time.sleep(cls._extraStartupSleep)
 
     @classmethod
@@ -264,10 +293,10 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
                 p.kill()
                 p.wait()
             if p.returncode != 0:
-              if p.returncode < 0:
-                raise AssertionError('Process was killed by signal %d' % (-p.returncode))
-              else:
-                raise AssertionError('Process exited with return code %d' % (p.returncode))
+                if p.returncode < 0:
+                    raise AssertionError("Process was killed by signal %d" % (-p.returncode))
+                else:
+                    raise AssertionError("Process exited with return code %d" % (p.returncode))
         except OSError as e:
             # There is a race-condition with the poll() and
             # kill() statements, when the process is dead on the
@@ -315,12 +344,12 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
                 toQueue.put(request, True, cls._queueTimeout)
                 response = fromQueue.get(True, cls._queueTimeout)
                 if response:
-                  response = copy.copy(response)
-                  response.id = request.id
+                    response = copy.copy(response)
+                    response.id = request.id
 
         if synthesize is not None:
-          response = dns.message.make_response(request)
-          response.set_rcode(synthesize)
+            response = dns.message.make_response(request)
+            response.set_rcode(synthesize)
 
         if not response:
             if cls._answerUnexpected:
@@ -344,19 +373,19 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
         sock.settimeout(0.5)
         while True:
             try:
-              data, addr = sock.recvfrom(4096)
+                data, addr = sock.recvfrom(4096)
             except socket.timeout:
-              if cls._backgroundThreads.get(threading.get_native_id(), False) == False:
-                del cls._backgroundThreads[threading.get_native_id()]
-                break
-              else:
-                continue
+                if cls._backgroundThreads.get(threading.get_native_id(), False) == False:
+                    del cls._backgroundThreads[threading.get_native_id()]
+                    break
+                else:
+                    continue
 
             forceRcode = None
             try:
                 request = dns.message.from_wire(data, ignore_trailing=ignoreTrailing)
             except dns.message.TrailingJunk as e:
-                print('trailing data exception in UDPResponder')
+                print("trailing data exception in UDPResponder")
                 if trailingDataResponse is False or forceRcode is True:
                     raise
                 print("UDP query with trailing data, synthesizing response")
@@ -365,96 +394,117 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
 
             wire = None
             if callback:
-              wire = callback(request)
+                wire = callback(request)
             else:
-              if request.edns > 1:
-                forceRcode = dns.rcode.BADVERS
-              response = cls._getResponse(request, fromQueue, toQueue, synthesize=forceRcode)
-              if response:
-                wire = response.to_wire()
+                if request.edns > 1:
+                    forceRcode = dns.rcode.BADVERS
+                response = cls._getResponse(request, fromQueue, toQueue, synthesize=forceRcode)
+                if response:
+                    wire = response.to_wire()
 
             if not wire:
-              continue
+                continue
             elif isinstance(wire, ResponderDropAction):
-              continue
+                continue
 
             sock.sendto(wire, addr)
 
         sock.close()
 
     @classmethod
-    def handleTCPConnection(cls, conn, fromQueue, toQueue, trailingDataResponse=False, multipleResponses=False, callback=None, partialWrite=False):
-      ignoreTrailing = trailingDataResponse is True
-      try:
-        data = conn.recv(2)
-      except Exception as err:
-        data = None
-        print(f'Error while reading query size in TCP responder thread {err=}, {type(err)=}')
-      if not data:
-        conn.close()
-        return
-
-      (datalen,) = struct.unpack("!H", data)
-      data = conn.recv(datalen)
-      forceRcode = None
-      try:
-        request = dns.message.from_wire(data, ignore_trailing=ignoreTrailing)
-      except dns.message.TrailingJunk as e:
-        if trailingDataResponse is False or forceRcode is True:
-          raise
-        print("TCP query with trailing data, synthesizing response")
-        request = dns.message.from_wire(data, ignore_trailing=True)
-        forceRcode = trailingDataResponse
-
-      if callback:
-        wire = callback(request)
-      else:
-        if request.edns > 1:
-          forceRcode = dns.rcode.BADVERS
-        response = cls._getResponse(request, fromQueue, toQueue, synthesize=forceRcode)
-        if response:
-          wire = response.to_wire(max_size=65535)
-
-      if not wire:
-        conn.close()
-        return
-      elif isinstance(wire, ResponderDropAction):
-        return
-
-      wireLen = struct.pack("!H", len(wire))
-      if partialWrite:
-        for b in wireLen:
-          conn.send(bytes([b]))
-          time.sleep(0.5)
-      else:
-        conn.send(wireLen)
-      conn.send(wire)
-
-      while multipleResponses:
-        # do not block, and stop as soon as the queue is empty, either the next response is already here or we are done
-        # otherwise we might read responses intended for the next connection
-        if fromQueue.empty():
-          break
-
-        response = fromQueue.get(False)
-        if not response:
-          break
+    def handleTCPConnection(
+        cls,
+        conn,
+        fromQueue,
+        toQueue,
+        trailingDataResponse=False,
+        multipleResponses=False,
+        callback=None,
+        partialWrite=False,
+    ):
+        ignoreTrailing = trailingDataResponse is True
+        try:
+            data = conn.recv(2)
+        except Exception as err:
+            data = None
+            print(f"Error while reading query size in TCP responder thread {err=}, {type(err)=}")
+        if not data:
+            conn.close()
+            return
 
-        response = copy.copy(response)
-        response.id = request.id
-        wire = response.to_wire(max_size=65535)
+        (datalen,) = struct.unpack("!H", data)
+        data = conn.recv(datalen)
+        forceRcode = None
         try:
-          conn.send(struct.pack("!H", len(wire)))
-          conn.send(wire)
-        except socket.error as e:
-          # some of the tests are going to close
-          # the connection on us, just deal with it
-          break
+            request = dns.message.from_wire(data, ignore_trailing=ignoreTrailing)
+        except dns.message.TrailingJunk as e:
+            if trailingDataResponse is False or forceRcode is True:
+                raise
+            print("TCP query with trailing data, synthesizing response")
+            request = dns.message.from_wire(data, ignore_trailing=True)
+            forceRcode = trailingDataResponse
 
-      conn.close()
+        if callback:
+            wire = callback(request)
+        else:
+            if request.edns > 1:
+                forceRcode = dns.rcode.BADVERS
+            response = cls._getResponse(request, fromQueue, toQueue, synthesize=forceRcode)
+            if response:
+                wire = response.to_wire(max_size=65535)
+
+        if not wire:
+            conn.close()
+            return
+        elif isinstance(wire, ResponderDropAction):
+            return
+
+        wireLen = struct.pack("!H", len(wire))
+        if partialWrite:
+            for b in wireLen:
+                conn.send(bytes([b]))
+                time.sleep(0.5)
+        else:
+            conn.send(wireLen)
+        conn.send(wire)
+
+        while multipleResponses:
+            # do not block, and stop as soon as the queue is empty, either the next response is already here or we are done
+            # otherwise we might read responses intended for the next connection
+            if fromQueue.empty():
+                break
+
+            response = fromQueue.get(False)
+            if not response:
+                break
+
+            response = copy.copy(response)
+            response.id = request.id
+            wire = response.to_wire(max_size=65535)
+            try:
+                conn.send(struct.pack("!H", len(wire)))
+                conn.send(wire)
+            except socket.error as e:
+                # some of the tests are going to close
+                # the connection on us, just deal with it
+                break
+
+        conn.close()
 
     @classmethod
-    def TCPResponder(cls, port, fromQueue, toQueue, trailingDataResponse=False, multipleResponses=False, callback=None, tlsContext=None, multipleConnections=False, listeningAddr='127.0.0.1', partialWrite=False):
+    def TCPResponder(
+        cls,
+        port,
+        fromQueue,
+        toQueue,
+        trailingDataResponse=False,
+        multipleResponses=False,
+        callback=None,
+        tlsContext=None,
+        multipleConnections=False,
+        listeningAddr="127.0.0.1",
+        partialWrite=False,
+    ):
         cls._backgroundThreads[threading.get_native_id()] = True
         # trailingDataResponse=True means "ignore trailing data".
         # Other values are either False (meaning "raise an exception")
@@ -473,47 +523,62 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
         sock.listen(100)
         sock.settimeout(0.5)
         if tlsContext:
-          sock = tlsContext.wrap_socket(sock, server_side=True)
+            sock = tlsContext.wrap_socket(sock, server_side=True)
 
         while True:
             try:
-              (conn, _) = sock.accept()
+                (conn, _) = sock.accept()
             except ssl.SSLError:
-              continue
+                continue
             except ConnectionResetError:
-              continue
-            except socket.timeout:
-              if cls._backgroundThreads.get(threading.get_native_id(), False) == False:
-                 del cls._backgroundThreads[threading.get_native_id()]
-                 break
-              else:
                 continue
+            except socket.timeout:
+                if cls._backgroundThreads.get(threading.get_native_id(), False) == False:
+                    del cls._backgroundThreads[threading.get_native_id()]
+                    break
+                else:
+                    continue
 
             conn.settimeout(5.0)
             if multipleConnections:
-              thread = threading.Thread(name='TCP Connection Handler',
-                                        target=cls.handleTCPConnection,
-                                        args=[conn, fromQueue, toQueue, trailingDataResponse, multipleResponses, callback, partialWrite])
-              thread.daemon = True
-              thread.start()
+                thread = threading.Thread(
+                    name="TCP Connection Handler",
+                    target=cls.handleTCPConnection,
+                    args=[conn, fromQueue, toQueue, trailingDataResponse, multipleResponses, callback, partialWrite],
+                )
+                thread.daemon = True
+                thread.start()
             else:
-              cls.handleTCPConnection(conn, fromQueue, toQueue, trailingDataResponse, multipleResponses, callback, partialWrite)
+                cls.handleTCPConnection(
+                    conn, fromQueue, toQueue, trailingDataResponse, multipleResponses, callback, partialWrite
+                )
 
         sock.close()
 
     @classmethod
-    def handleDoHConnection(cls, config, conn, fromQueue, toQueue, trailingDataResponse, multipleResponses, callback, tlsContext, useProxyProtocol):
+    def handleDoHConnection(
+        cls,
+        config,
+        conn,
+        fromQueue,
+        toQueue,
+        trailingDataResponse,
+        multipleResponses,
+        callback,
+        tlsContext,
+        useProxyProtocol,
+    ):
         ignoreTrailing = trailingDataResponse is True
         try:
-          h2conn = h2.connection.H2Connection(config=config)
-          h2conn.initiate_connection()
-          conn.sendall(h2conn.data_to_send())
+            h2conn = h2.connection.H2Connection(config=config)
+            h2conn.initiate_connection()
+            conn.sendall(h2conn.data_to_send())
         except ssl.SSLEOFError as e:
-          print("Unexpected EOF: %s" % (e))
-          return
+            print("Unexpected EOF: %s" % (e))
+            return
         except Exception as err:
-          print(f'Unexpected exception in DoH responder thread (connection init) {err=}, {type(err)=}')
-          return
+            print(f"Unexpected exception in DoH responder thread (connection init) {err=}, {type(err)=}")
+            return
 
         dnsData = {}
 
@@ -522,19 +587,19 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
             proxy = ProxyProtocol()
             header = conn.recv(proxy.HEADER_SIZE)
             if not header:
-                print('unable to get header')
+                print("unable to get header")
                 conn.close()
                 return
 
             if not proxy.parseHeader(header):
-                print('unable to parse header')
+                print("unable to parse header")
                 print(header)
                 conn.close()
                 return
 
             proxyContent = conn.recv(proxy.contentLen)
             if not proxyContent:
-                print('unable to get content')
+                print("unable to get content")
                 conn.close()
                 return
 
@@ -545,10 +610,10 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
         requestHeaders = None
         while True:
             try:
-              data = conn.recv(65535)
+                data = conn.recv(65535)
             except Exception as err:
-              data = None
-              print(f'Unexpected exception in DoH responder thread {err=}, {type(err)=}')
+                data = None
+                print(f"Unexpected exception in DoH responder thread {err=}, {type(err)=}")
             if not data:
                 break
 
@@ -559,7 +624,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
                 if isinstance(event, h2.events.DataReceived):
                     h2conn.acknowledge_received_data(event.flow_controlled_length, event.stream_id)
                     if not event.stream_id in dnsData:
-                      dnsData[event.stream_id] = b''
+                        dnsData[event.stream_id] = b""
                     dnsData[event.stream_id] = dnsData[event.stream_id] + (event.data)
                     if event.stream_ended:
                         forceRcode = None
@@ -588,9 +653,9 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
                             break
 
                         headers = [
-                          (':status', str(status)),
-                          ('content-length', str(len(wire))),
-                          ('content-type', 'application/dns-message'),
+                            (":status", str(status)),
+                            ("content-length", str(len(wire))),
+                            ("content-type", "application/dns-message"),
                         ]
                         h2conn.send_headers(stream_id=event.stream_id, headers=headers)
                         h2conn.send_data(stream_id=event.stream_id, data=wire, end_stream=True)
@@ -606,7 +671,17 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
             conn.close()
 
     @classmethod
-    def DOHResponder(cls, port, fromQueue, toQueue, trailingDataResponse=False, multipleResponses=False, callback=None, tlsContext=None, useProxyProtocol=False):
+    def DOHResponder(
+        cls,
+        port,
+        fromQueue,
+        toQueue,
+        trailingDataResponse=False,
+        multipleResponses=False,
+        callback=None,
+        tlsContext=None,
+        useProxyProtocol=False,
+    ):
         cls._backgroundThreads[threading.get_native_id()] = True
         # trailingDataResponse=True means "ignore trailing data".
         # Other values are either False (meaning "raise an exception")
@@ -635,7 +710,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
             except ssl.SSLError:
                 continue
             except ConnectionResetError:
-              continue
+                continue
             except socket.timeout:
                 if cls._backgroundThreads.get(threading.get_native_id(), False) == False:
                     del cls._backgroundThreads[threading.get_native_id()]
@@ -644,9 +719,21 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
                     continue
 
             conn.settimeout(5.0)
-            thread = threading.Thread(name='DoH Connection Handler',
-                                      target=cls.handleDoHConnection,
-                                      args=[config, conn, fromQueue, toQueue, trailingDataResponse, multipleResponses, callback, tlsContext, useProxyProtocol])
+            thread = threading.Thread(
+                name="DoH Connection Handler",
+                target=cls.handleDoHConnection,
+                args=[
+                    config,
+                    conn,
+                    fromQueue,
+                    toQueue,
+                    trailingDataResponse,
+                    multipleResponses,
+                    callback,
+                    tlsContext,
+                    useProxyProtocol,
+                ],
+            )
             thread.daemon = True
             thread.start()
 
@@ -687,7 +774,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
             sock.settimeout(timeout)
 
         if not port:
-          port = cls._dnsDistPort
+            port = cls._dnsDistPort
 
         sock.connect((cls._dnsDistListeningAddr, port))
         return sock
@@ -700,10 +787,10 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
             sock.settimeout(timeout)
 
         # 2.7.9+
-        if hasattr(ssl, 'create_default_context'):
+        if hasattr(ssl, "create_default_context"):
             if not sslctx:
                 sslctx = ssl.create_default_context(cafile=caCert)
-                if len(alpn)> 0 and hasattr(sslctx, 'set_alpn_protocols'):
+                if len(alpn) > 0 and hasattr(sslctx, "set_alpn_protocols"):
                     sslctx.set_alpn_protocols(alpn)
             sslsock = sslctx.wrap_socket(sock, server_hostname=serverName, session=session)
         else:
@@ -753,7 +840,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
         conn = cls.openTLSConnection(port, serverName, caFile, timeout=timeout)
         cls.sendTCPQueryOverConnection(conn, query, response=response, timeout=timeout)
         if useQueue:
-          return cls.recvTCPResponseOverConnection(conn, useQueue=useQueue, timeout=timeout)
+            return cls.recvTCPResponseOverConnection(conn, useQueue=useQueue, timeout=timeout)
         return None, cls.recvTCPResponseOverConnection(conn, useQueue=useQueue, timeout=timeout)
 
     @classmethod
@@ -784,7 +871,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
             print(receivedQuery)
             receivedQuery = cls._fromResponderQueue.get(True, timeout)
         else:
-          print("queue is empty")
+            print("queue is empty")
 
         return (receivedQuery, message)
 
@@ -864,7 +951,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
 
     @classmethod
     def _encryptConsole(cls, command, nonce):
-        command = command.encode('UTF-8')
+        command = command.encode("UTF-8")
         if cls._consoleKey is None:
             return command
         return libnacl.crypto_secretbox(command, nonce, cls._consoleKey)
@@ -875,7 +962,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
             result = command
         else:
             result = libnacl.crypto_secretbox_open(command, nonce, cls._consoleKey)
-        return result.decode('UTF-8')
+        return result.decode("UTF-8")
 
     @classmethod
     def sendConsoleCommand(cls, command, timeout=5.0, IPv6=False):
@@ -890,9 +977,14 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
         sock.send(ourNonce)
         theirNonce = sock.recv(len(ourNonce))
         if len(theirNonce) != len(ourNonce):
-            print("Received a nonce of size %d, expecting %d, console command will not be sent!" % (len(theirNonce), len(ourNonce)))
+            print(
+                "Received a nonce of size %d, expecting %d, console command will not be sent!"
+                % (len(theirNonce), len(ourNonce))
+            )
             if len(theirNonce) == 0:
-                raise socket.error("Got EOF while reading a nonce of size %d, console command will not be sent!" % (len(ourNonce)))
+                raise socket.error(
+                    "Got EOF while reading a nonce of size %d, console command will not be sent!" % (len(ourNonce))
+                )
             return None
 
         halfNonceSize = int(len(ourNonce) / 2)
@@ -988,32 +1080,95 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     @staticmethod
     def generateNewCertificateAndKey(filePrefix):
         # generate and sign a new cert
-        cmd = ['openssl', 'req', '-new', '-newkey', 'rsa:2048', '-nodes', '-keyout', filePrefix + '.key', '-out', filePrefix + '.csr', '-config', 'configServer.conf']
+        cmd = [
+            "openssl",
+            "req",
+            "-new",
+            "-newkey",
+            "rsa:2048",
+            "-nodes",
+            "-keyout",
+            filePrefix + ".key",
+            "-out",
+            filePrefix + ".csr",
+            "-config",
+            "configServer.conf",
+        ]
         try:
-            process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
-            process.communicate(input='')
+            process = subprocess.Popen(
+                cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True
+            )
+            process.communicate(input="")
         except subprocess.CalledProcessError as exc:
-            raise AssertionError('openssl req failed (%d): %s' % (exc.returncode, exc.output))
-        cmd = ['openssl', 'x509', '-req', '-days', '1', '-CA', 'ca.pem', '-CAkey', 'ca.key', '-CAcreateserial', '-in', filePrefix + '.csr', '-out', filePrefix + '.pem', '-extfile', 'configServer.conf', '-extensions', 'v3_req']
+            raise AssertionError("openssl req failed (%d): %s" % (exc.returncode, exc.output))
+        cmd = [
+            "openssl",
+            "x509",
+            "-req",
+            "-days",
+            "1",
+            "-CA",
+            "ca.pem",
+            "-CAkey",
+            "ca.key",
+            "-CAcreateserial",
+            "-in",
+            filePrefix + ".csr",
+            "-out",
+            filePrefix + ".pem",
+            "-extfile",
+            "configServer.conf",
+            "-extensions",
+            "v3_req",
+        ]
         try:
-            process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
-            process.communicate(input='')
+            process = subprocess.Popen(
+                cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True
+            )
+            process.communicate(input="")
         except subprocess.CalledProcessError as exc:
-            raise AssertionError('openssl x509 failed (%d): %s' % (exc.returncode, exc.output))
+            raise AssertionError("openssl x509 failed (%d): %s" % (exc.returncode, exc.output))
 
-        with open(filePrefix + '.chain', 'w') as outFile:
-            for inFileName in [filePrefix + '.pem', 'ca.pem']:
+        with open(filePrefix + ".chain", "w") as outFile:
+            for inFileName in [filePrefix + ".pem", "ca.pem"]:
                 with open(inFileName) as inFile:
                     outFile.write(inFile.read())
 
-        cmd = ['openssl', 'pkcs12', '-export', '-passout', 'pass:passw0rd', '-clcerts', '-in', filePrefix + '.pem', '-CAfile', 'ca.pem', '-inkey', filePrefix + '.key', '-out', filePrefix + '.p12']
+        cmd = [
+            "openssl",
+            "pkcs12",
+            "-export",
+            "-passout",
+            "pass:passw0rd",
+            "-clcerts",
+            "-in",
+            filePrefix + ".pem",
+            "-CAfile",
+            "ca.pem",
+            "-inkey",
+            filePrefix + ".key",
+            "-out",
+            filePrefix + ".p12",
+        ]
         try:
-            process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
-            process.communicate(input='')
+            process = subprocess.Popen(
+                cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True
+            )
+            process.communicate(input="")
         except subprocess.CalledProcessError as exc:
-            raise AssertionError('openssl pkcs12 failed (%d): %s' % (exc.returncode, exc.output))
-
-    def checkMessageProxyProtocol(self, receivedProxyPayload, source, destination, isTCP, values=None, v6=False, sourcePort=None, destinationPort=None):
+            raise AssertionError("openssl pkcs12 failed (%d): %s" % (exc.returncode, exc.output))
+
+    def checkMessageProxyProtocol(
+        self,
+        receivedProxyPayload,
+        source,
+        destination,
+        isTCP,
+        values=None,
+        v6=False,
+        sourcePort=None,
+        destinationPort=None,
+    ):
         if values is None:
             values = []
         proxy = ProxyProtocol()
@@ -1051,7 +1206,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
             wire = query
         else:
             wire = query.to_wire()
-        param = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
+        param = base64.urlsafe_b64encode(wire).decode("UTF8").rstrip("=")
         return baseurl + "?dns=" + param
 
     @classmethod
@@ -1059,15 +1214,31 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
         conn = pycurl.Curl()
         conn.setopt(pycurl.HTTP_VERSION, pycurl.CURL_HTTP_VERSION_2)
 
-        conn.setopt(pycurl.HTTPHEADER, ["Content-type: application/dns-message",
-                                         "Accept: application/dns-message"])
+        conn.setopt(pycurl.HTTPHEADER, ["Content-type: application/dns-message", "Accept: application/dns-message"])
         if timeout:
-          conn.setopt(pycurl.TIMEOUT_MS, int(timeout*1000))
+            conn.setopt(pycurl.TIMEOUT_MS, int(timeout * 1000))
 
         return conn
 
     @classmethod
-    def sendDOHQuery(cls, port, servername, baseurl, query, response=None, timeout=2.0, caFile=None, useQueue=True, rawQuery=False, rawResponse=False, customHeaders=[], useHTTPS=True, fromQueue=None, toQueue=None, conn=None):
+    def sendDOHQuery(
+        cls,
+        port,
+        servername,
+        baseurl,
+        query,
+        response=None,
+        timeout=2.0,
+        caFile=None,
+        useQueue=True,
+        rawQuery=False,
+        rawResponse=False,
+        customHeaders=[],
+        useHTTPS=True,
+        fromQueue=None,
+        toQueue=None,
+        conn=None,
+    ):
         url = cls.getDOHGetURL(baseurl, query, rawQuery)
 
         if not conn:
@@ -1082,7 +1253,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
                 conn.setopt(pycurl.CAINFO, caFile)
 
         response_headers = BytesIO()
-        #conn.setopt(pycurl.VERBOSE, True)
+        # conn.setopt(pycurl.VERBOSE, True)
         conn.setopt(pycurl.URL, url)
         conn.setopt(pycurl.RESOLVE, ["%s:%d:%s" % (servername, port, cls._dnsDistListeningAddr)])
 
@@ -1097,7 +1268,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
 
         receivedQuery = None
         message = None
-        cls._response_headers = ''
+        cls._response_headers = ""
         data = conn.perform_rb()
         cls._rcode = conn.getinfo(pycurl.RESPONSE_CODE)
         if cls._rcode == 200 and not rawResponse:
@@ -1117,11 +1288,25 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
         return (receivedQuery, message)
 
     @classmethod
-    def sendDOHPostQuery(cls, port, servername, baseurl, query, response=None, timeout=2.0, caFile=None, useQueue=True, rawQuery=False, rawResponse=False, customHeaders=[], useHTTPS=True):
+    def sendDOHPostQuery(
+        cls,
+        port,
+        servername,
+        baseurl,
+        query,
+        response=None,
+        timeout=2.0,
+        caFile=None,
+        useQueue=True,
+        rawQuery=False,
+        rawResponse=False,
+        customHeaders=[],
+        useHTTPS=True,
+    ):
         url = baseurl
         conn = cls.openDOHConnection(port, caFile=caFile, timeout=timeout)
         response_headers = BytesIO()
-        #conn.setopt(pycurl.VERBOSE, True)
+        # conn.setopt(pycurl.VERBOSE, True)
         conn.setopt(pycurl.URL, url)
         conn.setopt(pycurl.RESOLVE, ["%s:%d:%s" % (servername, port, cls._dnsDistListeningAddr)])
         # this means "really do HTTP/2, not HTTP/1 with Upgrade headers"
@@ -1146,7 +1331,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
 
         receivedQuery = None
         message = None
-        cls._response_headers = ''
+        cls._response_headers = ""
         data = conn.perform_rb()
         cls._rcode = conn.getinfo(pycurl.RESPONSE_CODE)
         if cls._rcode == 200 and not rawResponse:
@@ -1161,31 +1346,88 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
         return (receivedQuery, message)
 
     def sendDOHQueryWrapper(self, query, response, useQueue=True, timeout=2, serverName=None):
-        return self.sendDOHQuery(self._dohServerPort, self._serverName if not serverName else serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, useQueue=useQueue, timeout=timeout)
+        return self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName if not serverName else serverName,
+            self._dohBaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            useQueue=useQueue,
+            timeout=timeout,
+        )
 
     def sendDOHWithNGHTTP2QueryWrapper(self, query, response, useQueue=True, timeout=2, serverName=None):
-        return self.sendDOHQuery(self._dohWithNGHTTP2ServerPort, self._serverName if not serverName else serverName, self._dohWithNGHTTP2BaseURL, query, response=response, caFile=self._caCert, useQueue=useQueue, timeout=timeout)
+        return self.sendDOHQuery(
+            self._dohWithNGHTTP2ServerPort,
+            self._serverName if not serverName else serverName,
+            self._dohWithNGHTTP2BaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            useQueue=useQueue,
+            timeout=timeout,
+        )
 
     def sendDOTQueryWrapper(self, query, response, useQueue=True, timeout=2, serverName=None):
-        return self.sendDOTQuery(self._tlsServerPort, self._serverName if not serverName else serverName, query, response, self._caCert, useQueue=useQueue, timeout=timeout)
+        return self.sendDOTQuery(
+            self._tlsServerPort,
+            self._serverName if not serverName else serverName,
+            query,
+            response,
+            self._caCert,
+            useQueue=useQueue,
+            timeout=timeout,
+        )
 
     def sendDOQQueryWrapper(self, query, response, useQueue=True, timeout=2, serverName=None, passExceptions=False):
-        return self.sendDOQQuery(self._doqServerPort, query, response=response, caFile=self._caCert, useQueue=useQueue, serverName=self._serverName if not serverName else serverName, timeout=timeout, passExceptions=passExceptions)
+        return self.sendDOQQuery(
+            self._doqServerPort,
+            query,
+            response=response,
+            caFile=self._caCert,
+            useQueue=useQueue,
+            serverName=self._serverName if not serverName else serverName,
+            timeout=timeout,
+            passExceptions=passExceptions,
+        )
 
     def sendDOH3QueryWrapper(self, query, response, useQueue=True, timeout=2, serverName=None, passExceptions=False):
-        return self.sendDOH3Query(self._doh3ServerPort, self._dohBaseURL, query, response=response, caFile=self._caCert, useQueue=useQueue, serverName=self._serverName if not serverName else serverName, timeout=timeout, passExceptions=passExceptions)
+        return self.sendDOH3Query(
+            self._doh3ServerPort,
+            self._dohBaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            useQueue=useQueue,
+            serverName=self._serverName if not serverName else serverName,
+            timeout=timeout,
+            passExceptions=passExceptions,
+        )
 
     @classmethod
     def getDOQConnection(cls, port, caFile=None, source=None, source_port=0):
 
-        manager = dns.quic.SyncQuicManager(
-            verify_mode=caFile
-        )
+        manager = dns.quic.SyncQuicManager(verify_mode=caFile)
 
         return manager.connect(cls._dnsDistListeningAddr, port, source, source_port)
 
     @classmethod
-    def sendDOQQuery(cls, port, query, response=None, timeout=2.0, caFile=None, useQueue=True, rawQuery=False, fromQueue=None, toQueue=None, connection=None, serverName=None, passExceptions=False):
+    def sendDOQQuery(
+        cls,
+        port,
+        query,
+        response=None,
+        timeout=2.0,
+        caFile=None,
+        useQueue=True,
+        rawQuery=False,
+        fromQueue=None,
+        toQueue=None,
+        connection=None,
+        serverName=None,
+        passExceptions=False,
+    ):
 
         if response:
             if toQueue:
@@ -1194,7 +1436,9 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
                 cls._toResponderQueue.put(response, True, timeout)
 
         try:
-            (message, _) = doqclient.quic_query(query, cls._dnsDistListeningAddr, timeout, port, verify=caFile, server_hostname=serverName)
+            (message, _) = doqclient.quic_query(
+                query, cls._dnsDistListeningAddr, timeout, port, verify=caFile, server_hostname=serverName
+            )
         except doqclient.StreamResetError as e:
             if passExceptions:
                 raise
@@ -1213,7 +1457,25 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
         return (receivedQuery, message)
 
     @classmethod
-    def sendDOH3Query(cls, port, baseurl, query, response=None, timeout=2.0, caFile=None, useQueue=True, rawQuery=False, fromQueue=None, toQueue=None, connection=None, serverName=None, post=False, customHeaders=None, rawResponse=False, passExceptions=False):
+    def sendDOH3Query(
+        cls,
+        port,
+        baseurl,
+        query,
+        response=None,
+        timeout=2.0,
+        caFile=None,
+        useQueue=True,
+        rawQuery=False,
+        fromQueue=None,
+        toQueue=None,
+        connection=None,
+        serverName=None,
+        post=False,
+        customHeaders=None,
+        rawResponse=False,
+        passExceptions=False,
+    ):
 
         if response:
             if toQueue:
@@ -1222,14 +1484,36 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
                 cls._toResponderQueue.put(response, True, timeout)
 
         if rawResponse:
-          return doh3_query(query, cls._dnsDistListeningAddr, baseurl, timeout, port, verify=caFile, server_hostname=serverName, post=post, additional_headers=customHeaders, raw_response=rawResponse)
+            return doh3_query(
+                query,
+                cls._dnsDistListeningAddr,
+                baseurl,
+                timeout,
+                port,
+                verify=caFile,
+                server_hostname=serverName,
+                post=post,
+                additional_headers=customHeaders,
+                raw_response=rawResponse,
+            )
 
         try:
-            message = doh3_query(query, cls._dnsDistListeningAddr, baseurl, timeout, port, verify=caFile, server_hostname=serverName, post=post, additional_headers=customHeaders, raw_response=rawResponse)
+            message = doh3_query(
+                query,
+                cls._dnsDistListeningAddr,
+                baseurl,
+                timeout,
+                port,
+                verify=caFile,
+                server_hostname=serverName,
+                post=post,
+                additional_headers=customHeaders,
+                raw_response=rawResponse,
+            )
         except doqclient.StreamResetError as e:
-          if passExceptions:
+            if passExceptions:
                 raise
-          return (None, None)
+            return (None, None)
 
         receivedQuery = None
 
index 2269d56808e62a03f2c047f681c32aeb53918e00..f78d5117cb8e6dfe0068b2a506741e23c050d2c4 100644 (file)
@@ -25,6 +25,7 @@ from doqclient import StreamResetError
 
 HttpConnection = Union[H0Connection, H3Connection]
 
+
 class URL:
     def __init__(self, url: str) -> None:
         parsed = urlparse(url)
@@ -52,6 +53,7 @@ class HttpRequest:
         self.method = method
         self.url = url
 
+
 class HttpClient(QuicConnectionProtocol):
     def __init__(self, *args, **kwargs) -> None:
         super().__init__(*args, **kwargs)
@@ -70,20 +72,13 @@ class HttpClient(QuicConnectionProtocol):
         """
         Perform a GET request.
         """
-        return await self._request(
-            HttpRequest(method="GET", url=URL(url), headers=headers)
-        )
+        return await self._request(HttpRequest(method="GET", url=URL(url), headers=headers))
 
-    async def post(
-        self, url: str, data: bytes, headers: Optional[Dict] = None
-    ) -> Deque[H3Event]:
+    async def post(self, url: str, data: bytes, headers: Optional[Dict] = None) -> Deque[H3Event]:
         """
         Perform a POST request.
         """
-        return await self._request(
-            HttpRequest(method="POST", url=URL(url), content=data, headers=headers)
-        )
-
+        return await self._request(HttpRequest(method="POST", url=URL(url), content=data, headers=headers))
 
     def http_event_received(self, event: H3Event) -> None:
         if isinstance(event, (HeadersReceived, DataReceived)):
@@ -132,9 +127,7 @@ class HttpClient(QuicConnectionProtocol):
             end_stream=not request.content,
         )
         if request.content:
-            self._http.send_data(
-                stream_id=stream_id, data=request.content, end_stream=True
-            )
+            self._http.send_data(stream_id=stream_id, data=request.content, end_stream=True)
 
         waiter = self._loop.create_future()
         self._request_events[stream_id] = deque()
@@ -192,7 +185,7 @@ async def async_h3_query(
 
     url = baseurl
     if not post:
-        url = "{}?dns={}".format(baseurl, base64.urlsafe_b64encode(query.to_wire()).decode('UTF8').rstrip('='))
+        url = "{}?dns={}".format(baseurl, base64.urlsafe_b64encode(query.to_wire()).decode("UTF8").rstrip("="))
     async with connect(
         host,
         port,
@@ -203,7 +196,6 @@ async def async_h3_query(
 
         try:
             async with async_timeout.timeout(timeout):
-
                 answer = await perform_http_request(
                     client=client,
                     url=url,
@@ -215,10 +207,21 @@ async def async_h3_query(
 
                 return answer
         except asyncio.TimeoutError as e:
-            return (e,{})
-
-
-def doh3_query(query, host, baseurl, timeout=2, port=853, verify=None, server_hostname=None, post=False, additional_headers=None, raw_response=False):
+            return (e, {})
+
+
+def doh3_query(
+    query,
+    host,
+    baseurl,
+    timeout=2,
+    port=853,
+    verify=None,
+    server_hostname=None,
+    post=False,
+    additional_headers=None,
+    raw_response=False,
+):
     configuration = QuicConfiguration(alpn_protocols=H3_ALPN, is_client=True, server_name=server_hostname)
     if verify:
         configuration.load_verify_locations(verify)
@@ -233,13 +236,13 @@ def doh3_query(query, host, baseurl, timeout=2, port=853, verify=None, server_ho
             timeout=timeout,
             create_protocol=HttpClient,
             post=post,
-            additional_headers=additional_headers
+            additional_headers=additional_headers,
         )
     )
 
-    if (isinstance(result, StreamReset)):
+    if isinstance(result, StreamReset):
         raise StreamResetError(result.error_code)
-    if (isinstance(result, asyncio.TimeoutError)):
+    if isinstance(result, asyncio.TimeoutError):
         raise TimeoutError()
     if raw_response:
         return (result, headers)
index 373e0516e157ecac68ed5f8432ebcf186f3f2fff..cb31c7de5bfb1c4ee208554f908674a10429d8db 100644 (file)
@@ -11,6 +11,7 @@ from aioquic.asyncio.protocol import QuicConnectionProtocol
 from aioquic.quic.configuration import QuicConfiguration
 from aioquic.quic.events import QuicEvent, StreamDataReceived, StreamReset
 
+
 class DnsClientProtocol(QuicConnectionProtocol):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
@@ -47,6 +48,7 @@ class DnsClientProtocol(QuicConnectionProtocol):
                 self._ack_waiter = None
                 waiter.set_result(event)
 
+
 class BogusDnsClientProtocol(DnsClientProtocol):
     def pack(self, data):
         # serialize query
@@ -61,7 +63,7 @@ async def async_quic_query(
     port: int,
     query: dns.message,
     timeout: float,
-    create_protocol=DnsClientProtocol
+    create_protocol=DnsClientProtocol,
 ) -> None:
     print("Connecting to {}:{}".format(host, port))
     async with connect(
@@ -79,12 +81,14 @@ async def async_quic_query(
         except asyncio.TimeoutError as e:
             return (e, None)
 
+
 class StreamResetError(Exception):
     def __init__(self, error, message="Stream reset by peer"):
         self.error = error
         super().__init__(message)
 
-def quic_query(query, host='127.0.0.1', timeout=2, port=853, verify=None, server_hostname=None):
+
+def quic_query(query, host="127.0.0.1", timeout=2, port=853, verify=None, server_hostname=None):
     configuration = QuicConfiguration(alpn_protocols=["doq"], is_client=True, server_name=server_hostname)
     if verify:
         configuration.load_verify_locations(verify)
@@ -95,16 +99,17 @@ def quic_query(query, host='127.0.0.1', timeout=2, port=853, verify=None, server
             port=port,
             query=query,
             timeout=timeout,
-            create_protocol=DnsClientProtocol
+            create_protocol=DnsClientProtocol,
         )
     )
-    if (isinstance(result, StreamReset)):
+    if isinstance(result, StreamReset):
         raise StreamResetError(result.error_code)
-    if (isinstance(result, asyncio.TimeoutError)):
+    if isinstance(result, asyncio.TimeoutError):
         raise TimeoutError()
     return (result, serial)
 
-def quic_bogus_query(query, host='127.0.0.1', timeout=2, port=853, verify=None, server_hostname=None):
+
+def quic_bogus_query(query, host="127.0.0.1", timeout=2, port=853, verify=None, server_hostname=None):
     configuration = QuicConfiguration(alpn_protocols=["doq"], is_client=True, server_name=server_hostname)
     if verify:
         configuration.load_verify_locations(verify)
@@ -115,11 +120,11 @@ def quic_bogus_query(query, host='127.0.0.1', timeout=2, port=853, verify=None,
             port=port,
             query=query,
             timeout=timeout,
-            create_protocol=BogusDnsClientProtocol
+            create_protocol=BogusDnsClientProtocol,
         )
     )
-    if (isinstance(result, StreamReset)):
+    if isinstance(result, StreamReset):
         raise StreamResetError(result.error_code)
-    if (isinstance(result, asyncio.TimeoutError)):
+    if isinstance(result, asyncio.TimeoutError):
         raise TimeoutError()
     return result
index 5fb548140a8c85f5b8f561119c150d3d82c6dade..034fc7fbad34c8242e9d28bf62c55a8b00c2686a 100644 (file)
@@ -7,6 +7,7 @@ import sys
 
 from proxyprotocol import ProxyProtocol
 
+
 def ProxyProtocolUDPResponder(port, fromQueue, toQueue):
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
@@ -28,7 +29,7 @@ def ProxyProtocolUDPResponder(port, fromQueue, toQueue):
 
         if proxy.local:
             # likely a healthcheck
-            data = data[proxy.HEADER_SIZE:]
+            data = data[proxy.HEADER_SIZE :]
             request = dns.message.from_wire(data)
             response = dns.message.make_response(request)
             wire = response.to_wire()
@@ -38,8 +39,8 @@ def ProxyProtocolUDPResponder(port, fromQueue, toQueue):
 
             continue
 
-        payload = data[:(proxy.HEADER_SIZE + proxy.contentLen)]
-        dnsData = data[(proxy.HEADER_SIZE + proxy.contentLen):]
+        payload = data[: (proxy.HEADER_SIZE + proxy.contentLen)]
+        dnsData = data[(proxy.HEADER_SIZE + proxy.contentLen) :]
         toQueue.put([payload, dnsData], True, 2.0)
         # computing the correct ID for the response
         request = dns.message.from_wire(dnsData)
@@ -50,6 +51,7 @@ def ProxyProtocolUDPResponder(port, fromQueue, toQueue):
         sock.sendto(response.to_wire(), addr)
         sock.settimeout(None)
 
+
 def ProxyProtocolTCPResponder(port, fromQueue, toQueue):
     # be aware that this responder will not accept a new connection
     # until the last one has been closed. This is done on purpose to
@@ -86,31 +88,31 @@ def ProxyProtocolTCPResponder(port, fromQueue, toQueue):
 
         payload = header + proxyContent
         while True:
-          try:
-            data = conn.recv(2)
-          except socket.timeout:
-            data = None
+            try:
+                data = conn.recv(2)
+            except socket.timeout:
+                data = None
 
-          if not data:
-            conn.close()
-            break
+            if not data:
+                conn.close()
+                break
 
-          (datalen,) = struct.unpack("!H", data)
-          data = conn.recv(datalen)
+            (datalen,) = struct.unpack("!H", data)
+            data = conn.recv(datalen)
 
-          toQueue.put([payload, data], True, 2.0)
+            toQueue.put([payload, data], True, 2.0)
 
-          response = copy.deepcopy(fromQueue.get(True, 2.0))
-          if not response:
-            conn.close()
-            break
+            response = copy.deepcopy(fromQueue.get(True, 2.0))
+            if not response:
+                conn.close()
+                break
 
-          # computing the correct ID for the response
-          request = dns.message.from_wire(data)
-          response.id = request.id
+            # computing the correct ID for the response
+            request = dns.message.from_wire(data)
+            response.id = request.id
 
-          wire = response.to_wire()
-          conn.send(struct.pack("!H", len(wire)))
-          conn.send(wire)
+            wire = response.to_wire()
+            conn.send(struct.pack("!H", len(wire)))
+            conn.send(wire)
 
         conn.close()
index ac5aa5c34053e12314dad079c93030c09af0279a..da6b6a9055c2b412a5c29c8eef750e22eeb46766 100644 (file)
@@ -3,23 +3,19 @@
 import dns
 from doqclient import StreamResetError
 
-class QUICTests(object):
 
+class QUICTests(object):
     def testQUICSimple(self):
         """
         QUIC: Simple query
         """
-        name = 'simple.doq.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.doq.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         (receivedQuery, receivedResponse) = self.sendQUICQuery(query, response=response)
         self.assertTrue(receivedQuery)
@@ -32,17 +28,13 @@ class QUICTests(object):
         """
         QUIC: Test multiple queries using the same connection
         """
-        name = 'simple.doq.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.doq.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         connection = self.getQUICConnection()
@@ -63,20 +55,20 @@ class QUICTests(object):
         """
         QUIC: Dropped query
         """
-        name = 'drop.doq.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "drop.doq.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         try:
             (_, receivedResponse) = self.sendQUICQuery(query, response=None, useQueue=False, passExceptions=True)
             self.fail()
         except StreamResetError as e:
-            self.assertEqual(e.error, 5);
+            self.assertEqual(e.error, 5)
 
     def testRefused(self):
         """
         QUIC: Refused
         """
-        name = 'refused.doq.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "refused.doq.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
@@ -89,16 +81,12 @@ class QUICTests(object):
         """
         QUIC: Spoofed
         """
-        name = 'spoof.doq.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "spoof.doq.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.4')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4")
         expectedResponse.answer.append(rrset)
 
         (_, receivedResponse) = self.sendQUICQuery(query, response=None, useQueue=False)
@@ -108,46 +96,43 @@ class QUICTests(object):
         """
         QUIC: No backend
         """
-        name = 'no-backend.doq.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "no-backend.doq.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         try:
             (_, receivedResponse) = self.sendQUICQuery(query, response=None, useQueue=False, passExceptions=True)
             self.fail()
-        except StreamResetError as e :
-            self.assertEqual(e.error, 5);
+        except StreamResetError as e:
+            self.assertEqual(e.error, 5)
 
-class QUICACLTests(object):
 
+class QUICACLTests(object):
     def testDropped(self):
         """
         QUIC: Dropped query because of ACL
         """
-        name = 'acl.doq.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "acl.doq.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         dropped = False
         try:
             (_, receivedResponse) = self.sendQUICQuery(query, response=None, useQueue=False, passExceptions=True)
             self.fail()
         except StreamResetError as e:
-            self.assertEqual(e.error, 5);
+            self.assertEqual(e.error, 5)
             dropped = True
         self.assertTrue(dropped)
 
+
 class QUICWithCacheTests(object):
     def testCached(self):
         """
         QUIC Cache: Served from cache
         """
         numberOfQueries = 10
-        name = 'cached.quic.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cached.quic.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -168,37 +153,39 @@ class QUICWithCacheTests(object):
 
         self.assertEqual(total, 1)
 
-class QUICGetLocalAddressOnAnyBindTests(object):
 
+class QUICGetLocalAddressOnAnyBindTests(object):
     def testGetLocalAddressOnAnyBind(self):
         """
         QUIC: Return CNAME containing the local address for an ANY bind
         """
-        name = 'local-address-any.quic.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "local-address-any.quic.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'address-was-127-0-0-1.local-address-any.advanced.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.CNAME,
+            "address-was-127-0-0-1.local-address-any.advanced.tests.powerdns.com.",
+        )
         response.answer.append(rrset)
 
         (_, receivedResponse) = self.sendQUICQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, response)
 
-class QUICXFRTests(object):
 
+class QUICXFRTests(object):
     def testXFR(self):
         """
         QUIC: XFR
         """
-        name = 'xfr.doq.tests.powerdns.com.'
+        name = "xfr.doq.tests.powerdns.com."
         for xfrType in [dns.rdatatype.AXFR, dns.rdatatype.IXFR]:
-            query = dns.message.make_query(name, xfrType, 'IN')
+            query = dns.message.make_query(name, xfrType, "IN")
             expectedResponse = dns.message.make_response(query)
             expectedResponse.set_rcode(dns.rcode.NOTIMP)
 
index c2673ecccfe1e7de07a2731a0d8bb11e4fef843d..d67032148fcf50a261d6bf860e1a388ec2112f0d 100644 (file)
@@ -2,9 +2,9 @@
 import os
 import paddingoption
 
+
 class RandomPaddingOption(paddingoption.PaddingOption):
-    """Implementation of rfc7830 using random bytes in the payload.
-    """
+    """Implementation of rfc7830 using random bytes in the payload."""
 
     def __init__(self, numberOfBytes):
         super(RandomPaddingOption, self).__init__(12)
index ffaa3fccbb263e12cd91ffe2afc0e9b4615e906e..5fe74e04501939e4062441ed157ad8dfd9289207 100644 (file)
@@ -9,41 +9,118 @@ import socket
 import time
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
+
 class APITestsBase(DNSDistTest):
     __test__ = False
     _webTimeout = 5.0
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
-    _config_params = ['_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _webServerBasicAuthPassword = "secret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
+    _config_params = [
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setACL({"127.0.0.1/32", "::1/128"})
     newServer{address="127.0.0.1:%d", pool={'', 'mypool'}}
     webserver("127.0.0.1:%d")
     setWebserverConfig({password="%s", apiKey="%s"})
     """
-    _expectedMetrics = ['responses', 'servfail-responses', 'queries', 'acl-drops',
-                        'frontend-noerror', 'frontend-nxdomain', 'frontend-servfail',
-                        'rule-drop', 'rule-nxdomain', 'rule-refused', 'self-answered', 'downstream-timeouts',
-                        'downstream-send-errors', 'trunc-failures', 'no-policy', 'latency0-1',
-                        'latency1-10', 'latency10-50', 'latency50-100', 'latency100-1000',
-                        'latency-slow', 'latency-sum', 'latency-count', 'latency-avg100', 'latency-avg1000',
-                        'latency-avg10000', 'latency-avg1000000', 'latency-tcp-avg100', 'latency-tcp-avg1000',
-                        'latency-tcp-avg10000', 'latency-tcp-avg1000000', 'latency-dot-avg100', 'latency-dot-avg1000',
-                        'latency-dot-avg10000', 'latency-dot-avg1000000', 'latency-doh-avg100', 'latency-doh-avg1000',
-                        'latency-doh-avg10000', 'latency-doh-avg1000000', 'latency-doq-avg100', 'latency-doq-avg1000',
-                        'latency-doq-avg10000', 'latency-doq-avg1000000', 'latency-doh3-avg100', 'latency-doh3-avg1000',
-                        'latency-doh3-avg10000', 'latency-doh3-avg1000000','uptime', 'real-memory-usage', 'noncompliant-queries',
-                        'noncompliant-responses', 'rdqueries', 'empty-queries', 'cache-hits',
-                        'cache-misses', 'cpu-iowait', 'cpu-steal', 'cpu-sys-msec', 'cpu-user-msec', 'fd-usage', 'dyn-blocked',
-                        'dyn-block-nmg-size', 'rule-servfail', 'rule-truncated', 'security-status',
-                        'udp-in-csum-errors', 'udp-in-errors', 'udp-noport-errors', 'udp-recvbuf-errors', 'udp-sndbuf-errors',
-                        'udp6-in-errors', 'udp6-recvbuf-errors', 'udp6-sndbuf-errors', 'udp6-noport-errors', 'udp6-in-csum-errors',
-                        'doh-query-pipe-full', 'doh-response-pipe-full', 'doq-response-pipe-full', 'doh3-response-pipe-full', 'proxy-protocol-invalid', 'tcp-listen-overflows',
-                        'outgoing-doh-query-pipe-full', 'tcp-query-pipe-full', 'tcp-cross-protocol-query-pipe-full',
-                        'tcp-cross-protocol-response-pipe-full']
+    _expectedMetrics = [
+        "responses",
+        "servfail-responses",
+        "queries",
+        "acl-drops",
+        "frontend-noerror",
+        "frontend-nxdomain",
+        "frontend-servfail",
+        "rule-drop",
+        "rule-nxdomain",
+        "rule-refused",
+        "self-answered",
+        "downstream-timeouts",
+        "downstream-send-errors",
+        "trunc-failures",
+        "no-policy",
+        "latency0-1",
+        "latency1-10",
+        "latency10-50",
+        "latency50-100",
+        "latency100-1000",
+        "latency-slow",
+        "latency-sum",
+        "latency-count",
+        "latency-avg100",
+        "latency-avg1000",
+        "latency-avg10000",
+        "latency-avg1000000",
+        "latency-tcp-avg100",
+        "latency-tcp-avg1000",
+        "latency-tcp-avg10000",
+        "latency-tcp-avg1000000",
+        "latency-dot-avg100",
+        "latency-dot-avg1000",
+        "latency-dot-avg10000",
+        "latency-dot-avg1000000",
+        "latency-doh-avg100",
+        "latency-doh-avg1000",
+        "latency-doh-avg10000",
+        "latency-doh-avg1000000",
+        "latency-doq-avg100",
+        "latency-doq-avg1000",
+        "latency-doq-avg10000",
+        "latency-doq-avg1000000",
+        "latency-doh3-avg100",
+        "latency-doh3-avg1000",
+        "latency-doh3-avg10000",
+        "latency-doh3-avg1000000",
+        "uptime",
+        "real-memory-usage",
+        "noncompliant-queries",
+        "noncompliant-responses",
+        "rdqueries",
+        "empty-queries",
+        "cache-hits",
+        "cache-misses",
+        "cpu-iowait",
+        "cpu-steal",
+        "cpu-sys-msec",
+        "cpu-user-msec",
+        "fd-usage",
+        "dyn-blocked",
+        "dyn-block-nmg-size",
+        "rule-servfail",
+        "rule-truncated",
+        "security-status",
+        "udp-in-csum-errors",
+        "udp-in-errors",
+        "udp-noport-errors",
+        "udp-recvbuf-errors",
+        "udp-sndbuf-errors",
+        "udp6-in-errors",
+        "udp6-recvbuf-errors",
+        "udp6-sndbuf-errors",
+        "udp6-noport-errors",
+        "udp6-in-csum-errors",
+        "doh-query-pipe-full",
+        "doh-response-pipe-full",
+        "doq-response-pipe-full",
+        "doh3-response-pipe-full",
+        "proxy-protocol-invalid",
+        "tcp-listen-overflows",
+        "outgoing-doh-query-pipe-full",
+        "tcp-query-pipe-full",
+        "tcp-cross-protocol-query-pipe-full",
+        "tcp-cross-protocol-response-pipe-full",
+    ]
     _verboseMode = True
 
     @classmethod
@@ -51,17 +128,21 @@ class APITestsBase(DNSDistTest):
         cls.startResponders()
         cls.startDNSDist()
         cls.setUpSockets()
-        cls.waitForTCPSocket('127.0.0.1', cls._webServerPort)
+        cls.waitForTCPSocket("127.0.0.1", cls._webServerPort)
         print("Launching tests..")
 
-class TestAPIBasics(APITestsBase):
 
+class TestAPIBasics(APITestsBase):
     # paths accessible using the API key only
-    _apiOnlyPaths = ['/api/v1/servers/localhost/config', '/api/v1/servers/localhost/config/allow-from', '/api/v1/servers/localhost/statistics']
+    _apiOnlyPaths = [
+        "/api/v1/servers/localhost/config",
+        "/api/v1/servers/localhost/config/allow-from",
+        "/api/v1/servers/localhost/statistics",
+    ]
     # paths accessible using an API key or basic auth
-    _statsPaths = [ '/jsonstat?command=stats', '/jsonstat?command=dynblocklist', '/api/v1/servers/localhost']
+    _statsPaths = ["/jsonstat?command=stats", "/jsonstat?command=dynblocklist", "/api/v1/servers/localhost"]
     # paths accessible using basic auth only (list not exhaustive)
-    _basicOnlyPaths = ['/', '/index.html']
+    _basicOnlyPaths = ["/", "/index.html"]
     __test__ = True
 
     def testBasicAuth(self):
@@ -69,10 +150,10 @@ class TestAPIBasics(APITestsBase):
         API: Basic Authentication
         """
         for path in self._basicOnlyPaths + self._statsPaths:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
-            r = requests.get(url, auth=('whatever', "evilsecret"), timeout=self._webTimeout)
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
+            r = requests.get(url, auth=("whatever", "evilsecret"), timeout=self._webTimeout)
             self.assertEqual(r.status_code, 401)
-            r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+            r = requests.get(url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout)
             self.assertTrue(r)
             self.assertEqual(r.status_code, 200)
 
@@ -80,9 +161,9 @@ class TestAPIBasics(APITestsBase):
         """
         API: X-Api-Key
         """
-        headers = {'x-api-key': self._webServerAPIKey}
+        headers = {"x-api-key": self._webServerAPIKey}
         for path in self._apiOnlyPaths + self._statsPaths:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
             r = requests.get(url, headers=headers, timeout=self._webTimeout)
             self.assertTrue(r)
             self.assertEqual(r.status_code, 200)
@@ -91,9 +172,9 @@ class TestAPIBasics(APITestsBase):
         """
         API: Wrong X-Api-Key
         """
-        headers = {'x-api-key': "evilapikey"}
+        headers = {"x-api-key": "evilapikey"}
         for path in self._apiOnlyPaths + self._statsPaths:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
             r = requests.get(url, headers=headers, timeout=self._webTimeout)
             self.assertEqual(r.status_code, 401)
 
@@ -101,9 +182,9 @@ class TestAPIBasics(APITestsBase):
         """
         API: Basic Authentication Only
         """
-        headers = {'x-api-key': self._webServerAPIKey}
+        headers = {"x-api-key": self._webServerAPIKey}
         for path in self._basicOnlyPaths:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
             r = requests.get(url, headers=headers, timeout=self._webTimeout)
             self.assertEqual(r.status_code, 401)
 
@@ -112,65 +193,134 @@ class TestAPIBasics(APITestsBase):
         API: API Key Only
         """
         for path in self._apiOnlyPaths:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
-            r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
+            r = requests.get(url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout)
             self.assertEqual(r.status_code, 401)
 
     def testServersLocalhost(self):
         """
         API: /api/v1/servers/localhost
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
 
-        self.assertEqual(content['daemon_type'], 'dnsdist')
+        self.assertEqual(content["daemon_type"], "dnsdist")
 
-        rule_groups = ['response-rules', 'cache-hit-response-rules', 'self-answered-response-rules', 'rules']
-        for key in ['version', 'acl', 'local', 'servers', 'frontends', 'pools'] + rule_groups:
+        rule_groups = ["response-rules", "cache-hit-response-rules", "self-answered-response-rules", "rules"]
+        for key in ["version", "acl", "local", "servers", "frontends", "pools"] + rule_groups:
             self.assertIn(key, content)
 
         for rule_group in rule_groups:
             for rule in content[rule_group]:
-                for key in ['id', 'creationOrder', 'matches', 'rule', 'action', 'uuid']:
+                for key in ["id", "creationOrder", "matches", "rule", "action", "uuid"]:
                     self.assertIn(key, rule)
-                for key in ['id', 'creationOrder', 'matches']:
+                for key in ["id", "creationOrder", "matches"]:
                     self.assertGreaterEqual(rule[key], 0)
 
-        for server in content['servers']:
-            for key in ['id', 'latency', 'name', 'weight', 'outstanding', 'qpsLimit',
-                        'reuseds', 'state', 'address', 'pools', 'qps', 'queries', 'order', 'sendErrors',
-                        'dropRate', 'responses', 'nonCompliantResponses', 'tcpDiedSendingQuery', 'tcpDiedReadingResponse',
-                        'tcpGaveUp', 'tcpReadTimeouts', 'tcpWriteTimeouts', 'tcpCurrentConnections',
-                        'tcpNewConnections', 'tcpReusedConnections', 'tlsResumptions', 'tcpAvgQueriesPerConnection',
-                        'tcpAvgConnectionDuration', 'tcpLatency', 'protocol', 'healthCheckFailures', 'healthCheckFailuresParsing', 'healthCheckFailuresTimeout', 'healthCheckFailuresNetwork', 'healthCheckFailuresMismatch', 'healthCheckFailuresInvalid']:
+        for server in content["servers"]:
+            for key in [
+                "id",
+                "latency",
+                "name",
+                "weight",
+                "outstanding",
+                "qpsLimit",
+                "reuseds",
+                "state",
+                "address",
+                "pools",
+                "qps",
+                "queries",
+                "order",
+                "sendErrors",
+                "dropRate",
+                "responses",
+                "nonCompliantResponses",
+                "tcpDiedSendingQuery",
+                "tcpDiedReadingResponse",
+                "tcpGaveUp",
+                "tcpReadTimeouts",
+                "tcpWriteTimeouts",
+                "tcpCurrentConnections",
+                "tcpNewConnections",
+                "tcpReusedConnections",
+                "tlsResumptions",
+                "tcpAvgQueriesPerConnection",
+                "tcpAvgConnectionDuration",
+                "tcpLatency",
+                "protocol",
+                "healthCheckFailures",
+                "healthCheckFailuresParsing",
+                "healthCheckFailuresTimeout",
+                "healthCheckFailuresNetwork",
+                "healthCheckFailuresMismatch",
+                "healthCheckFailuresInvalid",
+            ]:
                 self.assertIn(key, server)
 
-            for key in ['id', 'latency', 'weight', 'outstanding', 'qpsLimit', 'reuseds',
-                        'qps', 'queries', 'order', 'tcpLatency', 'responses', 'nonCompliantResponses']:
+            for key in [
+                "id",
+                "latency",
+                "weight",
+                "outstanding",
+                "qpsLimit",
+                "reuseds",
+                "qps",
+                "queries",
+                "order",
+                "tcpLatency",
+                "responses",
+                "nonCompliantResponses",
+            ]:
                 self.assertGreaterEqual(server[key], 0)
 
-            self.assertIn(server['state'], ['up', 'down', 'UP', 'DOWN'])
+            self.assertIn(server["state"], ["up", "down", "UP", "DOWN"])
 
-        for frontend in content['frontends']:
-            for key in ['id', 'address', 'udp', 'tcp', 'type', 'queries', 'nonCompliantQueries']:
+        for frontend in content["frontends"]:
+            for key in ["id", "address", "udp", "tcp", "type", "queries", "nonCompliantQueries"]:
                 self.assertIn(key, frontend)
 
-            for key in ['id', 'queries', 'nonCompliantQueries']:
+            for key in ["id", "queries", "nonCompliantQueries"]:
                 self.assertGreaterEqual(frontend[key], 0)
 
-        for pool in content['pools']:
-            for key in ['id', 'name', 'cacheSize', 'cacheEntries', 'cacheHits', 'cacheMisses', 'cacheDeferredInserts', 'cacheDeferredLookups', 'cacheLookupCollisions', 'cacheInsertCollisions', 'cacheTTLTooShorts', 'cacheCleanupCount']:
+        for pool in content["pools"]:
+            for key in [
+                "id",
+                "name",
+                "cacheSize",
+                "cacheEntries",
+                "cacheHits",
+                "cacheMisses",
+                "cacheDeferredInserts",
+                "cacheDeferredLookups",
+                "cacheLookupCollisions",
+                "cacheInsertCollisions",
+                "cacheTTLTooShorts",
+                "cacheCleanupCount",
+            ]:
                 self.assertIn(key, pool)
 
-            for key in ['id', 'cacheSize', 'cacheEntries', 'cacheHits', 'cacheMisses', 'cacheDeferredInserts', 'cacheDeferredLookups', 'cacheLookupCollisions', 'cacheInsertCollisions', 'cacheTTLTooShorts', 'cacheCleanupCount']:
+            for key in [
+                "id",
+                "cacheSize",
+                "cacheEntries",
+                "cacheHits",
+                "cacheMisses",
+                "cacheDeferredInserts",
+                "cacheDeferredLookups",
+                "cacheLookupCollisions",
+                "cacheInsertCollisions",
+                "cacheTTLTooShorts",
+                "cacheCleanupCount",
+            ]:
                 self.assertGreaterEqual(pool[key], 0)
 
-        stats = content['statistics']
+        stats = content["statistics"]
         for key in self._expectedMetrics:
             self.assertIn(key, stats)
             self.assertGreaterEqual(stats[key], 0)
@@ -181,44 +331,102 @@ class TestAPIBasics(APITestsBase):
         """
         API: /api/v1/servers/localhost/pool?name=mypool
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost/pool?name=mypool'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost/pool?name=mypool"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
 
-        self.assertIn('stats', content)
-        self.assertIn('servers', content)
-
-        for key in ['name', 'cacheSize', 'cacheEntries', 'cacheHits', 'cacheMisses', 'cacheDeferredInserts', 'cacheDeferredLookups', 'cacheLookupCollisions', 'cacheInsertCollisions', 'cacheTTLTooShorts']:
-            self.assertIn(key, content['stats'])
-
-        for key in ['cacheSize', 'cacheEntries', 'cacheHits', 'cacheMisses', 'cacheDeferredInserts', 'cacheDeferredLookups', 'cacheLookupCollisions', 'cacheInsertCollisions', 'cacheTTLTooShorts']:
-            self.assertGreaterEqual(content['stats'][key], 0)
-
-        for server in content['servers']:
-            for key in ['id', 'latency', 'name', 'weight', 'outstanding', 'qpsLimit',
-                        'reuseds', 'state', 'address', 'pools', 'qps', 'queries', 'order', 'sendErrors',
-                        'dropRate', 'responses', 'nonCompliantResponses', 'tcpDiedSendingQuery', 'tcpDiedReadingResponse',
-                        'tcpGaveUp', 'tcpReadTimeouts', 'tcpWriteTimeouts', 'tcpCurrentConnections',
-                        'tcpNewConnections', 'tcpReusedConnections', 'tcpAvgQueriesPerConnection',
-                        'tcpAvgConnectionDuration', 'tcpLatency', 'protocol']:
+        self.assertIn("stats", content)
+        self.assertIn("servers", content)
+
+        for key in [
+            "name",
+            "cacheSize",
+            "cacheEntries",
+            "cacheHits",
+            "cacheMisses",
+            "cacheDeferredInserts",
+            "cacheDeferredLookups",
+            "cacheLookupCollisions",
+            "cacheInsertCollisions",
+            "cacheTTLTooShorts",
+        ]:
+            self.assertIn(key, content["stats"])
+
+        for key in [
+            "cacheSize",
+            "cacheEntries",
+            "cacheHits",
+            "cacheMisses",
+            "cacheDeferredInserts",
+            "cacheDeferredLookups",
+            "cacheLookupCollisions",
+            "cacheInsertCollisions",
+            "cacheTTLTooShorts",
+        ]:
+            self.assertGreaterEqual(content["stats"][key], 0)
+
+        for server in content["servers"]:
+            for key in [
+                "id",
+                "latency",
+                "name",
+                "weight",
+                "outstanding",
+                "qpsLimit",
+                "reuseds",
+                "state",
+                "address",
+                "pools",
+                "qps",
+                "queries",
+                "order",
+                "sendErrors",
+                "dropRate",
+                "responses",
+                "nonCompliantResponses",
+                "tcpDiedSendingQuery",
+                "tcpDiedReadingResponse",
+                "tcpGaveUp",
+                "tcpReadTimeouts",
+                "tcpWriteTimeouts",
+                "tcpCurrentConnections",
+                "tcpNewConnections",
+                "tcpReusedConnections",
+                "tcpAvgQueriesPerConnection",
+                "tcpAvgConnectionDuration",
+                "tcpLatency",
+                "protocol",
+            ]:
                 self.assertIn(key, server)
 
-            for key in ['id', 'latency', 'weight', 'outstanding', 'qpsLimit', 'reuseds',
-                        'qps', 'queries', 'order', 'tcpLatency', 'responses', 'nonCompliantResponses']:
+            for key in [
+                "id",
+                "latency",
+                "weight",
+                "outstanding",
+                "qpsLimit",
+                "reuseds",
+                "qps",
+                "queries",
+                "order",
+                "tcpLatency",
+                "responses",
+                "nonCompliantResponses",
+            ]:
                 self.assertGreaterEqual(server[key], 0)
 
-            self.assertIn(server['state'], ['up', 'down', 'UP', 'DOWN'])
+            self.assertIn(server["state"], ["up", "down", "UP", "DOWN"])
 
     def testServersIDontExist(self):
         """
         API: /api/v1/servers/idonotexist (should be 404)
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/idonotexist'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/idonotexist"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertEqual(r.status_code, 404)
 
@@ -226,8 +434,8 @@ class TestAPIBasics(APITestsBase):
         """
         API: /api/v1/servers/localhost/config
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost/config'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost/config"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -235,42 +443,53 @@ class TestAPIBasics(APITestsBase):
         content = r.json()
         values = {}
         for entry in content:
-            for key in ['type', 'name', 'value']:
+            for key in ["type", "name", "value"]:
                 self.assertIn(key, entry)
 
-            self.assertEqual(entry['type'], 'ConfigSetting')
-            values[entry['name']] = entry['value']
-
-        for key in ['acl', 'control-socket', 'ecs-override', 'ecs-source-prefix-v4',
-                    'ecs-source-prefix-v6', 'fixup-case', 'max-outstanding', 'server-policy',
-                    'stale-cache-entries-ttl', 'tcp-recv-timeout', 'tcp-send-timeout',
-                    'truncate-tc', 'verbose', 'verbose-health-checks']:
+            self.assertEqual(entry["type"], "ConfigSetting")
+            values[entry["name"]] = entry["value"]
+
+        for key in [
+            "acl",
+            "control-socket",
+            "ecs-override",
+            "ecs-source-prefix-v4",
+            "ecs-source-prefix-v6",
+            "fixup-case",
+            "max-outstanding",
+            "server-policy",
+            "stale-cache-entries-ttl",
+            "tcp-recv-timeout",
+            "tcp-send-timeout",
+            "truncate-tc",
+            "verbose",
+            "verbose-health-checks",
+        ]:
             self.assertIn(key, values)
 
-        for key in ['max-outstanding', 'stale-cache-entries-ttl', 'tcp-recv-timeout',
-                    'tcp-send-timeout']:
+        for key in ["max-outstanding", "stale-cache-entries-ttl", "tcp-recv-timeout", "tcp-send-timeout"]:
             self.assertGreaterEqual(values[key], 0)
 
-        self.assertTrue(values['ecs-source-prefix-v4'] >= 0 and values['ecs-source-prefix-v4'] <= 32)
-        self.assertTrue(values['ecs-source-prefix-v6'] >= 0 and values['ecs-source-prefix-v6'] <= 128)
+        self.assertTrue(values["ecs-source-prefix-v4"] >= 0 and values["ecs-source-prefix-v4"] <= 32)
+        self.assertTrue(values["ecs-source-prefix-v6"] >= 0 and values["ecs-source-prefix-v6"] <= 128)
 
     def testServersLocalhostConfigAllowFrom(self):
         """
         API: /api/v1/servers/localhost/config/allow-from
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost/config/allow-from'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost/config/allow-from"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        for key in ['type', 'name', 'value']:
+        for key in ["type", "name", "value"]:
             self.assertIn(key, content)
 
-        self.assertEqual(content['name'], 'allow-from')
-        self.assertEqual(content['type'], 'ConfigSetting')
-        acl = content['value']
+        self.assertEqual(content["name"], "allow-from")
+        self.assertEqual(content["type"], "ConfigSetting")
+        acl = content["value"]
         expectedACL = ["127.0.0.1/32", "::1/128"]
         acl.sort()
         expectedACL.sort()
@@ -283,11 +502,9 @@ class TestAPIBasics(APITestsBase):
         The API is read-only by default, so this should be refused
         """
         newACL = ["192.0.2.0/24", "198.51.100.0/24", "203.0.113.0/24"]
-        payload = json.dumps({"name": "allow-from",
-                              "type": "ConfigSetting",
-                              "value": newACL})
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost/config/allow-from'
+        payload = json.dumps({"name": "allow-from", "type": "ConfigSetting", "value": newACL})
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost/config/allow-from"
         r = requests.put(url, headers=headers, timeout=self._webTimeout, data=payload)
         self.assertFalse(r)
         self.assertEqual(r.status_code, 405)
@@ -296,8 +513,8 @@ class TestAPIBasics(APITestsBase):
         """
         API: /api/v1/servers/localhost/statistics
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost/statistics'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost/statistics"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -305,11 +522,11 @@ class TestAPIBasics(APITestsBase):
         content = r.json()
         values = {}
         for entry in content:
-            self.assertIn('type', entry)
-            self.assertIn('name', entry)
-            self.assertIn('value', entry)
-            self.assertEqual(entry['type'], 'StatisticItem')
-            values[entry['name']] = entry['value']
+            self.assertIn("type", entry)
+            self.assertIn("name", entry)
+            self.assertIn("value", entry)
+            self.assertEqual(entry["type"], "StatisticItem")
+            values[entry["name"]] = entry["value"]
 
         for key in self._expectedMetrics:
             self.assertIn(key, values)
@@ -322,8 +539,8 @@ class TestAPIBasics(APITestsBase):
         """
         API: /jsonstat?command=stats
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/jsonstat?command=stats'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/jsonstat?command=stats"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -338,8 +555,8 @@ class TestAPIBasics(APITestsBase):
         """
         API: /jsonstat?command=dynblocklist
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/jsonstat?command=dynblocklist'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/jsonstat?command=dynblocklist"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -347,38 +564,34 @@ class TestAPIBasics(APITestsBase):
         content = r.json()
 
         if content:
-            for key in ['reason', 'seconds', 'blocks', 'action']:
+            for key in ["reason", "seconds", "blocks", "action"]:
                 self.assertIn(key, content)
 
-            for key in ['blocks']:
+            for key in ["blocks"]:
                 self.assertGreaterEqual(content[key], 0)
 
     def testServersLocalhostRings(self):
         """
         API: /api/v1/servers/localhost/rings
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost/rings'
-        expectedValues = ['age', 'id', 'name', 'requestor', 'size', 'qtype', 'protocol', 'rd']
-        expectedResponseValues = expectedValues + ['latency', 'rcode', 'tc', 'aa', 'answers', 'backend']
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost/rings"
+        expectedValues = ["age", "id", "name", "requestor", "size", "qtype", "protocol", "rd"]
+        expectedResponseValues = expectedValues + ["latency", "rcode", "tc", "aa", "answers", "backend"]
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        self.assertIn('queries', content)
-        self.assertIn('responses', content)
-        self.assertEqual(len(content['queries']), 0)
-        self.assertEqual(len(content['responses']), 0)
+        self.assertIn("queries", content)
+        self.assertIn("responses", content)
+        self.assertEqual(len(content["queries"]), 0)
+        self.assertEqual(len(content["responses"]), 0)
 
-        name = 'simple.api.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "simple.api.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -395,17 +608,18 @@ class TestAPIBasics(APITestsBase):
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        self.assertIn('queries', content)
-        self.assertIn('responses', content)
-        self.assertEqual(len(content['queries']), 2)
-        self.assertEqual(len(content['responses']), 2)
-        for entry in content['queries']:
+        self.assertIn("queries", content)
+        self.assertIn("responses", content)
+        self.assertEqual(len(content["queries"]), 2)
+        self.assertEqual(len(content["responses"]), 2)
+        for entry in content["queries"]:
             for value in expectedValues:
                 self.assertIn(value, entry)
-        for entry in content['responses']:
+        for entry in content["responses"]:
             for value in expectedResponseValues:
                 self.assertIn(value, entry)
 
+
 class TestAPIServerDown(APITestsBase):
     __test__ = True
     _config_template = """
@@ -420,21 +634,29 @@ class TestAPIServerDown(APITestsBase):
         """
         API: /api/v1/servers/localhost, no latency for a down server
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
 
-        self.assertEqual(content['servers'][0]['latency'], None)
-        self.assertEqual(content['servers'][0]['tcpLatency'], None)
+        self.assertEqual(content["servers"][0]["latency"], None)
+        self.assertEqual(content["servers"][0]["tcpLatency"], None)
+
 
 class TestAPIWritable(APITestsBase):
     __test__ = True
-    _APIWriteDir = '/tmp'
-    _config_params = ['_testServerPort', '_webServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed', '_APIWriteDir']
+    _APIWriteDir = "/tmp"
+    _config_params = [
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+        "_APIWriteDir",
+    ]
     _config_template = """
     setACL({"127.0.0.1/32", "::1/128"})
     newServer{address="127.0.0.1:%d"}
@@ -448,29 +670,27 @@ class TestAPIWritable(APITestsBase):
         """
         API: Set ACL
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost/config/allow-from'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost/config/allow-from"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        acl = content['value']
+        acl = content["value"]
         expectedACL = ["127.0.0.1/32", "::1/128"]
         acl.sort()
         expectedACL.sort()
         self.assertEqual(acl, expectedACL)
 
         newACL = ["192.0.2.0/24", "198.51.100.0/24", "203.0.113.0/24"]
-        payload = json.dumps({"name": "allow-from",
-                              "type": "ConfigSetting",
-                              "value": newACL})
+        payload = json.dumps({"name": "allow-from", "type": "ConfigSetting", "value": newACL})
         r = requests.put(url, headers=headers, timeout=self._webTimeout, data=payload)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        acl = content['value']
+        acl = content["value"]
         acl.sort()
         self.assertEqual(acl, newACL)
 
@@ -479,36 +699,47 @@ class TestAPIWritable(APITestsBase):
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        acl = content['value']
+        acl = content["value"]
         acl.sort()
         self.assertEqual(acl, newACL)
 
-        configFile = self._APIWriteDir + '/' + 'acl.conf'
+        configFile = self._APIWriteDir + "/" + "acl.conf"
         self.assertTrue(os.path.isfile(configFile))
-        with open(configFile, 'rt') as f:
+        with open(configFile, "rt") as f:
             header = f.readline()
             body = f.readline()
 
         self.assertEqual(header, """-- Generated by the REST API, DO NOT EDIT\n""")
 
-        self.assertIn(body, {
-            """setACL({"192.0.2.0/24", "198.51.100.0/24", "203.0.113.0/24"})\n""",
-            """setACL({"192.0.2.0/24", "203.0.113.0/24", "198.51.100.0/24"})\n""",
-            """setACL({"198.51.100.0/24", "192.0.2.0/24", "203.0.113.0/24"})\n""",
-            """setACL({"198.51.100.0/24", "203.0.113.0/24", "192.0.2.0/24"})\n""",
-            """setACL({"203.0.113.0/24", "192.0.2.0/24", "198.51.100.0/24"})\n""",
-            """setACL({"203.0.113.0/24", "198.51.100.0/24", "192.0.2.0/24"})\n"""
-        })
+        self.assertIn(
+            body,
+            {
+                """setACL({"192.0.2.0/24", "198.51.100.0/24", "203.0.113.0/24"})\n""",
+                """setACL({"192.0.2.0/24", "203.0.113.0/24", "198.51.100.0/24"})\n""",
+                """setACL({"198.51.100.0/24", "192.0.2.0/24", "203.0.113.0/24"})\n""",
+                """setACL({"198.51.100.0/24", "203.0.113.0/24", "192.0.2.0/24"})\n""",
+                """setACL({"203.0.113.0/24", "192.0.2.0/24", "198.51.100.0/24"})\n""",
+                """setACL({"203.0.113.0/24", "198.51.100.0/24", "192.0.2.0/24"})\n""",
+            },
+        )
+
 
 class TestAPICustomHeaders(APITestsBase):
     __test__ = True
     # paths accessible using the API key only
-    _apiOnlyPath = '/api/v1/servers/localhost/config'
+    _apiOnlyPath = "/api/v1/servers/localhost/config"
     # paths accessible using basic auth only (list not exhaustive)
-    _basicOnlyPath = '/'
+    _basicOnlyPath = "/"
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -523,12 +754,12 @@ class TestAPICustomHeaders(APITestsBase):
         API: Basic custom headers
         """
 
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + self._basicOnlyPath
+        url = "http://127.0.0.1:" + str(self._webServerPort) + self._basicOnlyPath
 
-        r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+        r = requests.get(url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
-        self.assertEqual(r.headers.get('x-custom'), "custom")
+        self.assertEqual(r.headers.get("x-custom"), "custom")
         self.assertNotIn("x-frame-options", r.headers)
 
     def testBasicHeadersUpdate(self):
@@ -536,24 +767,32 @@ class TestAPICustomHeaders(APITestsBase):
         API: Basic update of custom headers
         """
 
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + self._basicOnlyPath
+        url = "http://127.0.0.1:" + str(self._webServerPort) + self._basicOnlyPath
         self.sendConsoleCommand('setWebserverConfig({customHeaders={["x-powered-by"]="dnsdist"}})')
-        r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+        r = requests.get(url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
-        self.assertEqual(r.headers.get('x-powered-by'), "dnsdist")
+        self.assertEqual(r.headers.get("x-powered-by"), "dnsdist")
         self.assertIn("x-frame-options", r.headers)
 
+
 class TestStatsWithoutAuthentication(APITestsBase):
     __test__ = True
     # paths accessible using the API key only
-    _apiOnlyPath = '/api/v1/servers/localhost/config'
+    _apiOnlyPath = "/api/v1/servers/localhost/config"
     # paths accessible using basic auth only (list not exhaustive)
-    _basicOnlyPath = '/'
-    _noAuthenticationPaths = [ '/metrics', '/jsonstat?command=dynblocklist' ]
+    _basicOnlyPath = "/"
+    _noAuthenticationPaths = ["/metrics", "/jsonstat?command=dynblocklist"]
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -569,7 +808,7 @@ class TestStatsWithoutAuthentication(APITestsBase):
         """
 
         for path in self._noAuthenticationPaths:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
 
             r = requests.get(url, timeout=self._webTimeout)
             self.assertTrue(r)
@@ -577,40 +816,52 @@ class TestStatsWithoutAuthentication(APITestsBase):
 
         # these should still require basic authentication
         for path in [self._basicOnlyPath]:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
 
             r = requests.get(url, timeout=self._webTimeout)
             self.assertEqual(r.status_code, 401)
 
-            r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+            r = requests.get(url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout)
             self.assertTrue(r)
             self.assertEqual(r.status_code, 200)
 
         # these should still require API authentication
         for path in [self._apiOnlyPath]:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
 
             r = requests.get(url, timeout=self._webTimeout)
             self.assertEqual(r.status_code, 401)
 
-            headers = {'x-api-key': self._webServerAPIKey}
+            headers = {"x-api-key": self._webServerAPIKey}
             r = requests.get(url, headers=headers, timeout=self._webTimeout)
             self.assertTrue(r)
             self.assertEqual(r.status_code, 200)
 
+
 class TestAPIAuth(APITestsBase):
     __test__ = True
-    _webServerBasicAuthPasswordNew = 'password'
-    _webServerBasicAuthPasswordNewHashed = '$scrypt$ln=10,p=1,r=8$yefz8SAuT3lj3moXqUYvmw==$T98/RYMp76ZYNjd7MpAkcVXZEDqpLtrc3tQ52QflVBA='
-    _webServerAPIKeyNew = 'apipassword'
-    _webServerAPIKeyNewHashed = '$scrypt$ln=9,p=1,r=8$y96I9nfkY0LWDQEdSUzWgA==$jiyn9QD36o9d0ADrlqiIBk4AKyQrkD1KYw3CexwtHp4='
+    _webServerBasicAuthPasswordNew = "password"
+    _webServerBasicAuthPasswordNewHashed = (
+        "$scrypt$ln=10,p=1,r=8$yefz8SAuT3lj3moXqUYvmw==$T98/RYMp76ZYNjd7MpAkcVXZEDqpLtrc3tQ52QflVBA="
+    )
+    _webServerAPIKeyNew = "apipassword"
+    _webServerAPIKeyNewHashed = (
+        "$scrypt$ln=9,p=1,r=8$y96I9nfkY0LWDQEdSUzWgA==$jiyn9QD36o9d0ADrlqiIBk4AKyQrkD1KYw3CexwtHp4="
+    )
     # paths accessible using the API key only
-    _apiOnlyPath = '/api/v1/servers/localhost/config'
+    _apiOnlyPath = "/api/v1/servers/localhost/config"
     # paths accessible using basic auth only (list not exhaustive)
-    _basicOnlyPath = '/'
+    _basicOnlyPath = "/"
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -625,15 +876,17 @@ class TestAPIAuth(APITestsBase):
         API: Basic Authentication updating credentials
         """
 
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + self._basicOnlyPath
-        self.sendConsoleCommand('setWebserverConfig({{password="{}"}})'.format(self._webServerBasicAuthPasswordNewHashed))
+        url = "http://127.0.0.1:" + str(self._webServerPort) + self._basicOnlyPath
+        self.sendConsoleCommand(
+            'setWebserverConfig({{password="{}"}})'.format(self._webServerBasicAuthPasswordNewHashed)
+        )
 
-        r = requests.get(url, auth=('whatever', self._webServerBasicAuthPasswordNew), timeout=self._webTimeout)
+        r = requests.get(url, auth=("whatever", self._webServerBasicAuthPasswordNew), timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
 
         # Make sure the old password is not usable any more
-        r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+        r = requests.get(url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout)
         self.assertEqual(r.status_code, 401)
 
     def testXAPIKeyChange(self):
@@ -641,16 +894,16 @@ class TestAPIAuth(APITestsBase):
         API: X-Api-Key updating credentials
         """
 
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + self._apiOnlyPath
+        url = "http://127.0.0.1:" + str(self._webServerPort) + self._apiOnlyPath
         self.sendConsoleCommand('setWebserverConfig({{apiKey="{}"}})'.format(self._webServerAPIKeyNewHashed))
 
-        headers = {'x-api-key': self._webServerAPIKeyNew}
+        headers = {"x-api-key": self._webServerAPIKeyNew}
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
 
         # Make sure the old password is not usable any more
-        headers = {'x-api-key': self._webServerAPIKey}
+        headers = {"x-api-key": self._webServerAPIKey}
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertEqual(r.status_code, 401)
 
@@ -659,10 +912,10 @@ class TestAPIAuth(APITestsBase):
         API: X-Api-Key updated to none (disabled)
         """
 
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + self._apiOnlyPath
+        url = "http://127.0.0.1:" + str(self._webServerPort) + self._apiOnlyPath
         self.sendConsoleCommand('setWebserverConfig({{apiKey="{}"}})'.format(self._webServerAPIKeyNewHashed))
 
-        headers = {'x-api-key': self._webServerAPIKeyNew}
+        headers = {"x-api-key": self._webServerAPIKeyNew}
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -673,11 +926,19 @@ class TestAPIAuth(APITestsBase):
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertEqual(r.status_code, 401)
 
+
 class TestAPIACL(APITestsBase):
     __test__ = True
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -692,9 +953,9 @@ class TestAPIACL(APITestsBase):
         API: Should be denied by ACL then allowed
         """
 
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + "/"
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/"
         try:
-            requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+            requests.get(url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout)
             self.fail()
         except requests.exceptions.ConnectionError as exp:
             pass
@@ -702,16 +963,17 @@ class TestAPIACL(APITestsBase):
         # reset the ACL
         self.sendConsoleCommand('setWebserverConfig({acl="127.0.0.1"})')
 
-        r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+        r = requests.get(url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
 
+
 class TestAPIWithoutAuthentication(APITestsBase):
     __test__ = True
-    _apiPath = '/api/v1/servers/localhost/config'
+    _apiPath = "/api/v1/servers/localhost/config"
     # paths accessible using basic auth only (list not exhaustive)
-    _basicOnlyPath = '/'
-    _config_params = ['_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed']
+    _basicOnlyPath = "/"
+    _config_params = ["_testServerPort", "_webServerPort", "_webServerBasicAuthPasswordHashed"]
     _config_template = """
     setACL({"127.0.0.1/32", "::1/128"})
     newServer({address="127.0.0.1:%d"})
@@ -725,7 +987,7 @@ class TestAPIWithoutAuthentication(APITestsBase):
         """
 
         for path in [self._apiPath]:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
 
             r = requests.get(url, timeout=self._webTimeout)
             self.assertTrue(r)
@@ -733,26 +995,27 @@ class TestAPIWithoutAuthentication(APITestsBase):
 
         # these should still require basic authentication
         for path in [self._basicOnlyPath]:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
 
             r = requests.get(url, timeout=self._webTimeout)
             self.assertEqual(r.status_code, 401)
 
-            r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+            r = requests.get(url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout)
             self.assertTrue(r)
             self.assertEqual(r.status_code, 200)
 
+
 class TestDashboardWithoutAuthentication(APITestsBase):
     __test__ = True
-    _basicPath = '/'
-    _config_params = ['_testServerPort', '_webServerPort']
+    _basicPath = "/"
+    _config_params = ["_testServerPort", "_webServerPort"]
     _config_template = """
     setACL({"127.0.0.1/32", "::1/128"})
     newServer({address="127.0.0.1:%d"})
     webserver("127.0.0.1:%d")
     setWebserverConfig({ dashboardRequiresAuthentication=false })
     """
-    _verboseMode=True
+    _verboseMode = True
 
     def testDashboard(self):
         """
@@ -760,12 +1023,13 @@ class TestDashboardWithoutAuthentication(APITestsBase):
         """
 
         for path in [self._basicPath]:
-            url = 'http://127.0.0.1:' + str(self._webServerPort) + path
+            url = "http://127.0.0.1:" + str(self._webServerPort) + path
 
             r = requests.get(url, timeout=self._webTimeout)
             self.assertTrue(r)
             self.assertEqual(r.status_code, 200)
 
+
 class TestCustomLuaEndpoint(APITestsBase):
     __test__ = True
     _config_template = """
@@ -808,25 +1072,34 @@ class TestCustomLuaEndpoint(APITestsBase):
     end
     registerWebHandler('/foo', customHTTPHandler)
     """
-    _config_params = ['_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed']
+    _config_params = ["_testServerPort", "_webServerPort", "_webServerBasicAuthPasswordHashed"]
 
     def testBasic(self):
         """
         Custom Web Handler
         """
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/foo?param=42'
-        headers = {'customheader': 'foobar'}
-        r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout, headers=headers)
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/foo?param=42"
+        headers = {"customheader": "foobar"}
+        r = requests.get(
+            url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout, headers=headers
+        )
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
-        self.assertEqual(r.content, b'It works!')
-        self.assertEqual(r.headers.get('foo'), "Bar")
+        self.assertEqual(r.content, b"It works!")
+        self.assertEqual(r.headers.get("foo"), "Bar")
+
 
 class TestWebConcurrentConnections(APITestsBase):
     __test__ = True
     _maxConns = 2
 
-    _config_params = ['_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed', '_maxConns']
+    _config_params = [
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+        "_maxConns",
+    ]
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     webserver("127.0.0.1:%d")
@@ -854,8 +1127,14 @@ class TestWebConcurrentConnections(APITestsBase):
             conns.append(conn)
 
         # we now hold all the slots, let's try to establish a new connection
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + "/"
-        self.assertRaises(requests.exceptions.ConnectionError, requests.get, url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/"
+        self.assertRaises(
+            requests.exceptions.ConnectionError,
+            requests.get,
+            url,
+            auth=("whatever", self._webServerBasicAuthPassword),
+            timeout=self._webTimeout,
+        )
 
         # free one slot
         conns[0].close()
@@ -863,15 +1142,21 @@ class TestWebConcurrentConnections(APITestsBase):
         time.sleep(1)
 
         # this should work
-        r = requests.get(url, auth=('whatever', self._webServerBasicAuthPassword), timeout=self._webTimeout)
+        r = requests.get(url, auth=("whatever", self._webServerBasicAuthPassword), timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
 
+
 class TestAPICustomStatistics(APITestsBase):
     __test__ = True
     _maxConns = 2
 
-    _config_params = ['_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     webserver("127.0.0.1:%d")
@@ -890,21 +1175,21 @@ class TestAPICustomStatistics(APITestsBase):
         API: /jsonstat?command=stats
         Test custom statistics are exposed
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/jsonstat?command=stats'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/jsonstat?command=stats"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
 
-        expected = ['my-custom-metric', 'my-other-metric', 'my-gauge']
+        expected = ["my-custom-metric", "my-other-metric", "my-gauge"]
 
         for key in expected:
             self.assertIn(key, content)
             self.assertGreaterEqual(content[key], 0)
 
-        unexpected = ['my-labeled-gauge', 'my-labeled-counter']
+        unexpected = ["my-labeled-gauge", "my-labeled-counter"]
 
         for key in unexpected:
             self.assertNotIn(key, content)
index c71ef80a63ddac5ee956288fb6d30c905a8e307f..af893e511cc30190058739611878b3af5f464419 100644 (file)
@@ -4,8 +4,8 @@ import time
 import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class TestAXFR(DNSDistTest):
 
+class TestAXFR(DNSDistTest):
     # this test suite uses a different responder port
     # because, contrary to the other ones, its
     # TCP responder allows multiple responses and we don't want
@@ -19,10 +19,18 @@ class TestAXFR(DNSDistTest):
     def startResponders(cls):
         print("Launching responders..")
 
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, True, None, None, True])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, True, None, None, True],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
@@ -37,20 +45,18 @@ class TestAXFR(DNSDistTest):
         """
         AXFR: One message
         """
-        name = 'one.axfr.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AXFR', 'IN')
+        name = "one.axfr.tests.powerdns.com."
+        query = dns.message.make_query(name, "AXFR", "IN")
         response = dns.message.make_response(query)
-        soa = dns.rrset.from_text(name,
-                                  60,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
         response.answer.append(soa)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '192.0.2.1'))
+        response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
         response.answer.append(soa)
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
@@ -62,14 +68,10 @@ class TestAXFR(DNSDistTest):
         """
         AXFR: One message, no SOA
         """
-        name = 'onenosoa.axfr.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AXFR', 'IN')
+        name = "onenosoa.axfr.tests.powerdns.com."
+        query = dns.message.make_query(name, "AXFR", "IN")
         response = dns.message.make_response(query)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '192.0.2.1'))
+        response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
         receivedQuery.id = query.id
@@ -80,41 +82,31 @@ class TestAXFR(DNSDistTest):
         """
         AXFR: Four messages
         """
-        name = 'four.axfr.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AXFR', 'IN')
+        name = "four.axfr.tests.powerdns.com."
+        query = dns.message.make_query(name, "AXFR", "IN")
         responses = []
-        soa = dns.rrset.from_text(name,
-                                  60,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
         response = dns.message.make_response(query)
         response.answer.append(soa)
         responses.append(response)
 
         response = dns.message.make_response(query)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '192.0.2.1'))
+        response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
         responses.append(response)
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         response.answer.append(rrset)
         responses.append(response)
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'dummy')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.TXT, "dummy")
         response.answer.append(rrset)
         responses.append(response)
 
@@ -131,41 +123,31 @@ class TestAXFR(DNSDistTest):
         """
         AXFR: Four messages, no final SOA
         """
-        name = 'fournosoa.axfr.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AXFR', 'IN')
+        name = "fournosoa.axfr.tests.powerdns.com."
+        query = dns.message.make_query(name, "AXFR", "IN")
         responses = []
-        soa = dns.rrset.from_text(name,
-                                  60,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
         response = dns.message.make_response(query)
         response.answer.append(soa)
         responses.append(response)
 
         response = dns.message.make_response(query)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '192.0.2.1'))
+        response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
         responses.append(response)
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         response.answer.append(rrset)
         responses.append(response)
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'dummy')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.TXT, "dummy")
         response.answer.append(rrset)
         responses.append(response)
 
@@ -178,14 +160,16 @@ class TestAXFR(DNSDistTest):
         """
         AXFR: Three messages including the final SOA, plus a trailing one
         """
-        name = 'threeplustrailing.axfr.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AXFR', 'IN')
+        name = "threeplustrailing.axfr.tests.powerdns.com."
+        query = dns.message.make_query(name, "AXFR", "IN")
         responses = []
-        soa = dns.rrset.from_text(name,
-                                  60,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
 
         # the SOA starts the AXFR
         response = dns.message.make_response(query)
@@ -194,30 +178,18 @@ class TestAXFR(DNSDistTest):
 
         # one A
         response = dns.message.make_response(query)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '192.0.2.1'))
+        response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
         responses.append(response)
 
         # one AAAA
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         response.answer.append(rrset)
         responses.append(response)
 
         # one TXT then the SOA that ends the AXFR
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    "Some text")
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.TXT, "Some text")
         response.answer.append(rrset)
         response.answer.append(soa)
         responses.append(response)
@@ -226,11 +198,7 @@ class TestAXFR(DNSDistTest):
         # be sent by the backend but that dnsdist should not
         # pass along to the client
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'dummy')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.TXT, "dummy")
         response.answer.append(rrset)
         responses.append(response)
 
@@ -243,52 +211,60 @@ class TestAXFR(DNSDistTest):
         """
         IXFR: Three messages including the final SOA, plus a trailing one
         """
-        name = 'threeplustrailing.ixfr.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AXFR', 'IN')
+        name = "threeplustrailing.ixfr.tests.powerdns.com."
+        query = dns.message.make_query(name, "AXFR", "IN")
         responses = []
 
-        finalSoa = dns.rrset.from_text(name,
-                                       60,
-                                       dns.rdataclass.IN,
-                                       dns.rdatatype.SOA,
-                                       'ns.' + name + ' hostmaster.' + name + ' 3 3600 3600 3600 60')
+        finalSoa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 3 3600 3600 3600 60",
+        )
 
         # the final SOA starts the IXFR, with first an update from 1 to 2 (one removal, two additions)
         response = dns.message.make_response(query)
         response.answer.append(finalSoa)
         # update from 1 to 2
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.SOA,
-                                                   'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60'))
+        response.answer.append(
+            dns.rrset.from_text(
+                name,
+                60,
+                dns.rdataclass.IN,
+                dns.rdatatype.SOA,
+                "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+            )
+        )
         # one removal
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '192.0.2.1'))
+        response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
         # then additions
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.SOA,
-                                                   'ns.' + name + ' hostmaster.' + name + ' 2 3600 3600 3600 60'))
+        response.answer.append(
+            dns.rrset.from_text(
+                name,
+                60,
+                dns.rdataclass.IN,
+                dns.rdatatype.SOA,
+                "ns." + name + " hostmaster." + name + " 2 3600 3600 3600 60",
+            )
+        )
         # new message in the middle of the additions
         responses.append(response)
         response = dns.message.make_response(query)
 
-        response.answer.append(dns.rrset.from_text_list(name,
-                                                        60,
-                                                        dns.rdataclass.IN,
-                                                        dns.rdatatype.A,
-                                                        ['192.0.2.2', '192.0.2.3']))
+        response.answer.append(
+            dns.rrset.from_text_list(name, 60, dns.rdataclass.IN, dns.rdatatype.A, ["192.0.2.2", "192.0.2.3"])
+        )
         # done with 1 -> 2
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.SOA,
-                                                   'ns.' + name + ' hostmaster.' + name + ' 2 3600 3600 3600 60'))
+        response.answer.append(
+            dns.rrset.from_text(
+                name,
+                60,
+                dns.rdataclass.IN,
+                dns.rdatatype.SOA,
+                "ns." + name + " hostmaster." + name + " 2 3600 3600 3600 60",
+            )
+        )
         # new message
         responses.append(response)
         response = dns.message.make_response(query)
@@ -298,11 +274,7 @@ class TestAXFR(DNSDistTest):
         response.answer.append(finalSoa)
 
         # and one addition
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '192.0.2.4'))
+        response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.4"))
         # and the final SOA
         response.answer.append(finalSoa)
         responses.append(response)
@@ -311,11 +283,7 @@ class TestAXFR(DNSDistTest):
         # be sent by the backend but that dnsdist should not
         # pass along to the client
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'dummy')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.TXT, "dummy")
         response.answer.append(rrset)
         responses.append(response)
 
index 82fcea4218fc448021a09999e8f5ad885b448385..f3b258ceeb51a2c31f3830908f046c35b566a66d 100644 (file)
@@ -7,8 +7,8 @@ import unittest
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestAdvancedFixupCase(DNSDistTest):
 
+class TestAdvancedFixupCase(DNSDistTest):
     _config_template = """
     truncateTC(true)
     fixupCase(true)
@@ -23,16 +23,12 @@ class TestAdvancedFixupCase(DNSDistTest):
         make the backend return a lowercase version,
         check that dnsdist fixes the response.
         """
-        name = 'fiXuPCasE.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        lowercasequery = dns.message.make_query(name.lower(), 'A', 'IN')
+        name = "fiXuPCasE.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        lowercasequery = dns.message.make_query(name.lower(), "A", "IN")
         response = dns.message.make_response(lowercasequery)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -45,12 +41,12 @@ class TestAdvancedFixupCase(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestAdvancedACL(DNSDistTest):
 
+class TestAdvancedACL(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     """
-    _acl = ['192.0.2.1/32']
+    _acl = ["192.0.2.1/32"]
 
     def testACLBlocked(self):
         """
@@ -60,16 +56,16 @@ class TestAdvancedACL(DNSDistTest):
         we expect no response since 127.0.0.1 is not on the
         ACL.
         """
-        name = 'tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, None)
 
-class TestAdvancedStringOnlyServer(DNSDistTest):
 
+class TestAdvancedStringOnlyServer(DNSDistTest):
     _config_template = """
     newServer("127.0.0.1:%d")
     """
@@ -78,14 +74,10 @@ class TestAdvancedStringOnlyServer(DNSDistTest):
         """
         Advanced: "string-only" server is placed in the default pool
         """
-        name = 'string-only-server.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "string-only-server.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -97,9 +89,9 @@ class TestAdvancedStringOnlyServer(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-@unittest.skipIf('SKIP_INCLUDEDIR_TESTS' in os.environ, 'IncludeDir tests are disabled')
-class TestAdvancedIncludeDir(DNSDistTest):
 
+@unittest.skipIf("SKIP_INCLUDEDIR_TESTS" in os.environ, "IncludeDir tests are disabled")
+class TestAdvancedIncludeDir(DNSDistTest):
     _config_template = """
     -- this directory contains a file allowing includedir.advanced.tests.powerdns.com.
     includeDirectory('test-include-dir')
@@ -110,14 +102,10 @@ class TestAdvancedIncludeDir(DNSDistTest):
         """
         Advanced: includeDirectory()
         """
-        name = 'includedir.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "includedir.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -130,8 +118,8 @@ class TestAdvancedIncludeDir(DNSDistTest):
             self.assertEqual(response, receivedResponse)
 
         # this one should be refused
-        name = 'notincludedir.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "notincludedir.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -141,11 +129,11 @@ class TestAdvancedIncludeDir(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestStatNodeRespRingSince(DNSDistTest):
 
+class TestStatNodeRespRingSince(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -161,14 +149,10 @@ class TestStatNodeRespRingSince(DNSDistTest):
         Advanced: StatNodeRespRing with optional since parameter
 
         """
-        name = 'statnodesince.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "statnodesince.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    1,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 1, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -180,54 +164,76 @@ class TestStatNodeRespRingSince(DNSDistTest):
 
         self.sendConsoleCommand("nodesSeen = {}")
         self.sendConsoleCommand("statNodeRespRing(visitor)")
-        nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
+        nodes = self.sendConsoleCommand(
+            "str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str"
+        )
         nodes = nodes.strip("\n")
-        self.assertEqual(nodes, """statnodesince.advanced.tests.powerdns.com.
+        self.assertEqual(
+            nodes,
+            """statnodesince.advanced.tests.powerdns.com.
 advanced.tests.powerdns.com.
 tests.powerdns.com.
 powerdns.com.
-com.""")
+com.""",
+        )
 
         self.sendConsoleCommand("nodesSeen = {}")
         self.sendConsoleCommand("statNodeRespRing(visitor, 0)")
-        nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
+        nodes = self.sendConsoleCommand(
+            "str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str"
+        )
         nodes = nodes.strip("\n")
-        self.assertEqual(nodes, """statnodesince.advanced.tests.powerdns.com.
+        self.assertEqual(
+            nodes,
+            """statnodesince.advanced.tests.powerdns.com.
 advanced.tests.powerdns.com.
 tests.powerdns.com.
 powerdns.com.
-com.""")
+com.""",
+        )
 
         time.sleep(5)
 
         self.sendConsoleCommand("nodesSeen = {}")
         self.sendConsoleCommand("statNodeRespRing(visitor)")
-        nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
+        nodes = self.sendConsoleCommand(
+            "str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str"
+        )
         nodes = nodes.strip("\n")
-        self.assertEqual(nodes, """statnodesince.advanced.tests.powerdns.com.
+        self.assertEqual(
+            nodes,
+            """statnodesince.advanced.tests.powerdns.com.
 advanced.tests.powerdns.com.
 tests.powerdns.com.
 powerdns.com.
-com.""")
+com.""",
+        )
 
         self.sendConsoleCommand("nodesSeen = {}")
         self.sendConsoleCommand("statNodeRespRing(visitor, 5)")
-        nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
+        nodes = self.sendConsoleCommand(
+            "str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str"
+        )
         nodes = nodes.strip("\n")
         self.assertEqual(nodes, """""")
 
         self.sendConsoleCommand("nodesSeen = {}")
         self.sendConsoleCommand("statNodeRespRing(visitor, 10)")
-        nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
+        nodes = self.sendConsoleCommand(
+            "str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str"
+        )
         nodes = nodes.strip("\n")
-        self.assertEqual(nodes, """statnodesince.advanced.tests.powerdns.com.
+        self.assertEqual(
+            nodes,
+            """statnodesince.advanced.tests.powerdns.com.
 advanced.tests.powerdns.com.
 tests.powerdns.com.
 powerdns.com.
-com.""")
+com.""",
+        )
 
-class TestAdvancedGetLocalPort(DNSDistTest):
 
+class TestAdvancedGetLocalPort(DNSDistTest):
     _config_template = """
     function answerBasedOnLocalPort(dq)
       local port = dq.localaddr:getPort()
@@ -241,17 +247,19 @@ class TestAdvancedGetLocalPort(DNSDistTest):
         """
         Advanced: Return CNAME containing the local port
         """
-        name = 'local-port.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "local-port.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'port-was-{}.local-port.advanced.tests.powerdns.com.'.format(self._dnsDistPort))
+        rrset = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.CNAME,
+            "port-was-{}.local-port.advanced.tests.powerdns.com.".format(self._dnsDistPort),
+        )
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -259,8 +267,8 @@ class TestAdvancedGetLocalPort(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, response)
 
-class TestAdvancedGetLocalPortOnAnyBind(DNSDistTest):
 
+class TestAdvancedGetLocalPortOnAnyBind(DNSDistTest):
     _config_template = """
     function answerBasedOnLocalPort(dq)
       local port = dq.localaddr:getPort()
@@ -269,23 +277,25 @@ class TestAdvancedGetLocalPortOnAnyBind(DNSDistTest):
     addAction("local-port-any.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalPort))
     newServer{address="127.0.0.1:%d"}
     """
-    _dnsDistListeningAddr = '0.0.0.0'
+    _dnsDistListeningAddr = "0.0.0.0"
 
     def testAdvancedGetLocalPortOnAnyBind(self):
         """
         Advanced: Return CNAME containing the local port for an ANY bind
         """
-        name = 'local-port-any.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "local-port-any.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'port-was-{}.local-port-any.advanced.tests.powerdns.com.'.format(self._dnsDistPort))
+        rrset = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.CNAME,
+            "port-was-{}.local-port-any.advanced.tests.powerdns.com.".format(self._dnsDistPort),
+        )
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -293,8 +303,8 @@ class TestAdvancedGetLocalPortOnAnyBind(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, response)
 
-class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
 
+class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
     _config_template = """
     function answerBasedOnLocalAddress(dq)
       local dest = tostring(dq.localaddr)
@@ -308,8 +318,8 @@ class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
     addLocal('0.0.0.0:%d')
     addLocal('[::]:%d')
     """
-    _config_params = ['_testServerPort', '_dnsDistPort', '_dnsDistPort']
-    _acl = ['127.0.0.1/32', '::1/128']
+    _config_params = ["_testServerPort", "_dnsDistPort", "_dnsDistPort"]
+    _acl = ["127.0.0.1/32", "::1/128"]
     _skipListeningOnCL = True
     _verboseMode = True
 
@@ -317,17 +327,19 @@ class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
         """
         Advanced: Return CNAME containing the local address for an ANY bind
         """
-        name = 'local-address-any.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "local-address-any.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'address-was-127-0-0-1.local-address-any.advanced.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.CNAME,
+            "address-was-127-0-0-1.local-address-any.advanced.tests.powerdns.com.",
+        )
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -337,20 +349,22 @@ class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
 
         # now a bit more tricky, UDP-only IPv4
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'address-was-127-0-0-2.local-address-any.advanced.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.CNAME,
+            "address-was-127-0-0-2.local-address-any.advanced.tests.powerdns.com.",
+        )
         response.answer.append(rrset)
         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         sock.settimeout(2.0)
-        sock.connect(('127.0.0.2', self._dnsDistPort))
+        sock.connect(("127.0.0.2", self._dnsDistPort))
         try:
             query = query.to_wire()
             sock.send(query)
             (data, remote) = sock.recvfrom(4096)
-            self.assertEqual(remote[0], '127.0.0.2')
+            self.assertEqual(remote[0], "127.0.0.2")
         except socket.timeout:
             data = None
 
@@ -362,29 +376,25 @@ class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
         """
         Advanced: Check the source address on responses for an ANY bind
         """
-        name = 'source-addr-any.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "source-addr-any.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.42')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.42")
         response.answer.append(rrset)
 
         # a bit more tricky, UDP-only IPv4
         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         sock.settimeout(2.0)
-        sock.connect(('127.0.0.2', self._dnsDistPort))
+        sock.connect(("127.0.0.2", self._dnsDistPort))
         self._toResponderQueue.put(response, True, 1.0)
         try:
             data = query.to_wire()
             sock.send(data)
             (data, remote) = sock.recvfrom(4096)
-            self.assertEqual(remote[0], '127.0.0.2')
+            self.assertEqual(remote[0], "127.0.0.2")
         except socket.timeout:
             data = None
 
@@ -395,19 +405,19 @@ class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
 
-        if 'SKIP_IPV6_TESTS' in os.environ:
-          return
+        if "SKIP_IPV6_TESTS" in os.environ:
+            return
 
         # a bit more tricky, UDP-only IPv6
         sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
         sock.settimeout(2.0)
-        sock.connect(('::1', self._dnsDistPort))
+        sock.connect(("::1", self._dnsDistPort))
         self._toResponderQueue.put(response, True, 1.0)
         try:
             data = query.to_wire()
             sock.send(data)
             (data, remote) = sock.recvfrom(4096)
-            self.assertEqual(remote[0], '::1')
+            self.assertEqual(remote[0], "::1")
         except socket.timeout:
             data = None
 
@@ -418,6 +428,7 @@ class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
 
+
 class TestAdvancedGetLocalAddressOnNonDefaultLoopbackBind(DNSDistTest):
     # this one is tricky: on the loopback interface we cannot harvest the destination
     # address, so we exercise a different code path when we bind on a different address
@@ -426,36 +437,32 @@ class TestAdvancedGetLocalAddressOnNonDefaultLoopbackBind(DNSDistTest):
     newServer{address="127.0.0.1:%d"}
     addLocal('127.0.1.19:%d')
     """
-    _config_params = ['_testServerPort', '_dnsDistPort']
-    _acl = ['127.0.0.1/32']
+    _config_params = ["_testServerPort", "_dnsDistPort"]
+    _acl = ["127.0.0.1/32"]
     _skipListeningOnCL = True
-    _alternateListeningAddr = '127.0.1.19'
+    _alternateListeningAddr = "127.0.1.19"
     _alternateListeningPort = DNSDistTest._dnsDistPort
 
     def testAdvancedCheckSourceAddrOnNonDefaultLoopbackBind(self):
         """
         Advanced: Check the source address used to reply on a non-default loopback bind
         """
-        name = 'source-addr-non-default-loopback.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "source-addr-non-default-loopback.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.42')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.42")
         response.answer.append(rrset)
 
         # a bit more tricky, UDP-only IPv4
         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         sock.settimeout(2.0)
-        sock.connect(('127.0.1.19', self._dnsDistPort))
+        sock.connect(("127.0.1.19", self._dnsDistPort))
         self._toResponderQueue.put(response, True, 1.0)
         try:
             data = query.to_wire()
             sock.send(data)
             (data, remote) = sock.recvfrom(4096)
-            self.assertEqual(remote[0], '127.0.1.19')
+            self.assertEqual(remote[0], "127.0.1.19")
         except socket.timeout:
             data = None
 
@@ -466,8 +473,8 @@ class TestAdvancedGetLocalAddressOnNonDefaultLoopbackBind(DNSDistTest):
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
 
-class TestAdvancedAllowHeaderOnly(DNSDistTest):
 
+class TestAdvancedAllowHeaderOnly(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     setAllowEmptyResponse(true)
@@ -477,8 +484,8 @@ class TestAdvancedAllowHeaderOnly(DNSDistTest):
         """
         Advanced: Header-only refused response
         """
-        name = 'header-only-refused-response.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "header-only-refused-response.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.REFUSED)
         response.question = []
@@ -495,8 +502,8 @@ class TestAdvancedAllowHeaderOnly(DNSDistTest):
         """
         Advanced: Header-only NoError response should be allowed
         """
-        name = 'header-only-noerror-response.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "header-only-noerror-response.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.question = []
 
@@ -512,8 +519,8 @@ class TestAdvancedAllowHeaderOnly(DNSDistTest):
         """
         Advanced: Header-only NXD response should be allowed
         """
-        name = 'header-only-nxd-response.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "header-only-nxd-response.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.NXDOMAIN)
         response.question = []
@@ -526,8 +533,8 @@ class TestAdvancedAllowHeaderOnly(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(receivedResponse, response)
 
-class TestAdvancedDropEmptyQueries(DNSDistTest):
 
+class TestAdvancedDropEmptyQueries(DNSDistTest):
     _config_template = """
     setDropEmptyQueries(true)
     newServer{address="127.0.0.1:%d"}
@@ -544,6 +551,7 @@ class TestAdvancedDropEmptyQueries(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, None)
 
+
 class TestProtocols(DNSDistTest):
     _config_template = """
     function checkUDP(dq)
@@ -569,8 +577,8 @@ class TestProtocols(DNSDistTest):
         """
         Advanced: Test DNSQuestion.Protocol over UDP
         """
-        name = 'udp.protocols.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.protocols.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -582,8 +590,8 @@ class TestProtocols(DNSDistTest):
         """
         Advanced: Test DNSQuestion.Protocol over TCP
         """
-        name = 'tcp.protocols.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tcp.protocols.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
@@ -591,6 +599,7 @@ class TestProtocols(DNSDistTest):
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
 
+
 class TestCustomMetrics(DNSDistTest):
     _config_template = """
     function custommetrics(dq)
@@ -623,8 +632,8 @@ class TestCustomMetrics(DNSDistTest):
         """
         Advanced: Test custom metric declaration after config done
         """
-        name = 'declare.metric.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "declare.metric.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -638,16 +647,12 @@ class TestCustomMetrics(DNSDistTest):
         """
         Advanced: Test basic operations on custom metrics
         """
-        name = 'operations.metric.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "operations.metric.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '4.3.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "4.3.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -655,6 +660,7 @@ class TestCustomMetrics(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, response)
 
+
 class TestDNSQuestionTime(DNSDistTest):
     _config_template = """
     local queryTime = nil
@@ -710,14 +716,10 @@ class TestDNSQuestionTime(DNSDistTest):
         """
         Advanced: Test query time
         """
-        name = 'query.time.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "query.time.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '4.3.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "4.3.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -727,6 +729,7 @@ class TestDNSQuestionTime(DNSDistTest):
             self.assertEqual(receivedQuery, query)
             self.assertEqual(receivedResponse, response)
 
+
 class TestChangeName(DNSDistTest):
     _config_template = """
     local tagName = 'initial-name'
@@ -757,40 +760,36 @@ class TestChangeName(DNSDistTest):
         """
         Advanced: ChangeName the query name
         """
-        name = 'changeName.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "changeName.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
-        changedName = 'changeName.advanced.tests.dnsdist.org.'
-        changedQuery = dns.message.make_query(changedName, 'A', 'IN')
+        changedName = "changeName.advanced.tests.dnsdist.org."
+        changedQuery = dns.message.make_query(changedName, "A", "IN")
         changedQuery.id = query.id
 
         response = dns.message.make_response(changedQuery)
-        rrset = dns.rrset.from_text(changedName,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '4.3.2.1')
+        rrset = dns.rrset.from_text(changedName, 60, dns.rdataclass.IN, dns.rdatatype.A, "4.3.2.1")
         response.answer.append(rrset)
-        rrset = dns.rrset.from_text('sub.sub2.changeName.advanced.tests.dnsdist.org.',
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'This text contains sub.sub2.changeName.advanced.tests.dnsdist.org.')
+        rrset = dns.rrset.from_text(
+            "sub.sub2.changeName.advanced.tests.dnsdist.org.",
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.TXT,
+            "This text contains sub.sub2.changeName.advanced.tests.dnsdist.org.",
+        )
         response.additional.append(rrset)
 
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '4.3.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "4.3.2.1")
         expectedResponse.answer.append(rrset)
         # we only rewrite records if the owner name matches the new target, nothing else
-        rrset = dns.rrset.from_text('sub.sub2.changeName.advanced.tests.dnsdist.org.',
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'This text contains sub.sub2.changeName.advanced.tests.dnsdist.org.')
+        rrset = dns.rrset.from_text(
+            "sub.sub2.changeName.advanced.tests.dnsdist.org.",
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.TXT,
+            "This text contains sub.sub2.changeName.advanced.tests.dnsdist.org.",
+        )
         expectedResponse.additional.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -800,11 +799,11 @@ class TestChangeName(DNSDistTest):
             self.assertEqual(receivedQuery, changedQuery)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestFlagsOnTimeout(DNSDistTest):
 
+class TestFlagsOnTimeout(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -816,10 +815,10 @@ class TestFlagsOnTimeout(DNSDistTest):
         """
         Advanced: Test that we record the correct incoming flags on a timeout
         """
-        name = 'timeout-flags.advanced.tests.powerdns.com.'
+        name = "timeout-flags.advanced.tests.powerdns.com."
 
         # first with RD=1
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 42
         query.flags |= dns.flags.RD
 
@@ -827,7 +826,7 @@ class TestFlagsOnTimeout(DNSDistTest):
         self.assertFalse(receivedResponse)
 
         # then with RD=0
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 84
         query.flags &= ~dns.flags.RD
 
@@ -846,52 +845,50 @@ class TestFlagsOnTimeout(DNSDistTest):
         print(lines)
         self.assertEqual(len(lines), 5)
         # header line
-        self.assertIn('TC RD AA', lines[0])
+        self.assertIn("TC RD AA", lines[0])
 
         queries = {}
         timeouts = {}
 
         for line in lines[1:]:
-            self.assertIn('DoUDP', line)
-            if 'T.O' in line:
+            self.assertIn("DoUDP", line)
+            if "T.O" in line:
                 queryID = int(line.split()[4])
                 timeouts[queryID] = line
             else:
                 queryID = int(line.split()[3])
                 queries[queryID] = line
             if queryID == 42:
-                self.assertIn('RD', line)
+                self.assertIn("RD", line)
             else:
-                self.assertNotIn('RD', line)
+                self.assertNotIn("RD", line)
 
         self.assertEqual(len(timeouts), 2)
         self.assertEqual(len(queries), 2)
 
+
 class TestTruncatedUDPLargeAnswers(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     """
+
     def testVeryLargeAnswer(self):
         """
         Advanced: Check that UDP responses that are too large for our buffer are dismissed
         """
-        name = 'very-large-answer-dismissed.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        name = "very-large-answer-dismissed.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "TXT", "IN")
         response = dns.message.make_response(query)
         # we prepare a large answer
-        content = ''
+        content = ""
         for i in range(31):
             if len(content) > 0:
-                content = content + ' '
-            content = content + 'A' * 255
+                content = content + " "
+            content = content + "A" * 255
         # pad up to 8192
-        content = content + ' ' + 'B' * 170
+        content = content + " " + "B" * 170
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    content)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, content)
         response.answer.append(rrset)
         self.assertEqual(len(response.to_wire()), 8192)
 
index 96292f249cd5e435a93cf2a99dd057bdf076adfd..fe83fcd6558c18ac70503c5d95dbb8b71ea124fd 100644 (file)
@@ -115,9 +115,7 @@ class AsyncTests(object):
             query = dns.message.make_query(name, "A", "IN")
 
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(
-                name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"
-            )
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
             response.answer.append(rrset)
 
             for method in (
@@ -144,9 +142,7 @@ class AsyncTests(object):
         query = dns.message.make_query(name, "A", "IN")
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(
-            name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"
-        )
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in (
@@ -184,9 +180,7 @@ class AsyncTests(object):
             query = dns.message.make_query(name, "A", "IN")
 
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(
-                name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"
-            )
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
             response.answer.append(rrset)
 
             for method in (
@@ -216,9 +210,7 @@ class AsyncTests(object):
             query = dns.message.make_query(name, "A", "IN")
 
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(
-                name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"
-            )
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
             response.answer.append(rrset)
 
             for method in (
@@ -248,9 +240,7 @@ class AsyncTests(object):
             query = dns.message.make_query(name, "A", "IN")
 
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(
-                name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"
-            )
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
             response.answer.append(rrset)
 
             expectedResponse = dns.message.make_response(query)
@@ -284,9 +274,7 @@ class AsyncTests(object):
             query = dns.message.make_query(name, "A", "IN")
 
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(
-                name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"
-            )
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
             response.answer.append(rrset)
 
             expectedQuery = dns.message.make_query(name, "A", "IN")
@@ -322,9 +310,7 @@ class AsyncTests(object):
             query = dns.message.make_query(name, "A", "IN")
 
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(
-                name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"
-            )
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
             response.answer.append(rrset)
 
             for method in (
@@ -336,7 +322,7 @@ class AsyncTests(object):
             ):
                 sender = getattr(self, method)
                 try:
-                    if method in ['sendDOQQueryWrapper']:
+                    if method in ["sendDOQQueryWrapper"]:
                         (receivedQuery, receivedResponse) = sender(query, response, passExceptions=True)
                     else:
                         (receivedQuery, receivedResponse) = sender(query, response)
@@ -433,14 +419,10 @@ class AsyncTests(object):
             name = "timeout-then-accept." + method + ".tc.async.tests.powerdns.com."
             query = dns.message.make_query(name, "A", "IN")
             query.id = 42
-            expectedQuery = dns.message.make_query(
-                name, "A", "IN", use_edns=True, payload=4096
-            )
+            expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
             expectedQuery.id = 42
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(
-                name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1"
-            )
+            rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
             response.answer.append(rrset)
 
             # first response is a TC=1
index ff9b170b7f25687e15fd929a6743f3784b4cd29b..f022772ce8c6f699e8d27a1d076771d3db2b908a 100644 (file)
@@ -7,6 +7,7 @@ import ssl
 
 from dnsdisttests import DNSDistTest
 
+
 class TestBackendDiscovery(DNSDistTest):
     # these ports are hardcoded for now, sorry about that!
     _noSVCBackendPort = 10600
@@ -27,11 +28,33 @@ class TestBackendDiscovery(DNSDistTest):
     _badQNameBackendPort = 10615
     _svcUpgradeDoTNoPortBackendPort = 10616
     _svcUpgradeDoHNoPortBackendPort = 10617
-    _upgradedBackendsPool = 'upgraded'
+    _upgradedBackendsPool = "upgraded"
 
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_noSVCBackendPort', '_svcNoUpgradeBackendPort', '_svcUpgradeDoTBackendPort', '_upgradedBackendsPool', '_svcUpgradeDoHBackendPort', '_svcUpgradeDoTBackendDifferentAddrPort1', '_svcUpgradeDoTBackendDifferentAddrPort2', '_svcUpgradeDoTUnreachableBackendPort', '_svcBrokenDNSResponseBackendPort', '_svcUpgradeDoHBackendWithoutPathPort', '_connectionRefusedBackendPort', '_eofBackendPort', '_servfailBackendPort', '_wrongNameBackendPort', '_wrongIDBackendPort', '_tooManyQuestionsBackendPort', '_badQNameBackendPort', '_svcUpgradeDoTNoPortBackendPort', '_svcUpgradeDoHNoPortBackendPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_noSVCBackendPort",
+        "_svcNoUpgradeBackendPort",
+        "_svcUpgradeDoTBackendPort",
+        "_upgradedBackendsPool",
+        "_svcUpgradeDoHBackendPort",
+        "_svcUpgradeDoTBackendDifferentAddrPort1",
+        "_svcUpgradeDoTBackendDifferentAddrPort2",
+        "_svcUpgradeDoTUnreachableBackendPort",
+        "_svcBrokenDNSResponseBackendPort",
+        "_svcUpgradeDoHBackendWithoutPathPort",
+        "_connectionRefusedBackendPort",
+        "_eofBackendPort",
+        "_servfailBackendPort",
+        "_wrongNameBackendPort",
+        "_wrongIDBackendPort",
+        "_tooManyQuestionsBackendPort",
+        "_badQNameBackendPort",
+        "_svcUpgradeDoTNoPortBackendPort",
+        "_svcUpgradeDoHNoPortBackendPort",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -99,88 +122,80 @@ class TestBackendDiscovery(DNSDistTest):
 
     def NoUpgradePathCallback(request):
         response = dns.message.make_response(request)
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SVCB,
-                                    '1 no-upgrade. alpn="h3"')
+        rrset = dns.rrset.from_text(
+            request.question[0].name, 60, dns.rdataclass.IN, dns.rdatatype.SVCB, '1 no-upgrade. alpn="h3"'
+        )
         response.answer.append(rrset)
         return response.to_wire()
 
     def UpgradeDoTCallback(request):
         response = dns.message.make_response(request)
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SVCB,
-                                    '1 tls.tests.dnsdist.org. alpn="dot" port=10652 ipv4hint=127.0.0.1')
+        rrset = dns.rrset.from_text(
+            request.question[0].name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SVCB,
+            '1 tls.tests.dnsdist.org. alpn="dot" port=10652 ipv4hint=127.0.0.1',
+        )
         response.answer.append(rrset)
         # add a useless A record for good measure
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(request.question[0].name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         # plus more useless records in authority
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(request.question[0].name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.authority.append(rrset)
         # and finally valid, albeit useless, hints
-        rrset = dns.rrset.from_text('tls.tests.dnsdist.org.',
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text("tls.tests.dnsdist.org.", 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.additional.append(rrset)
-        rrset = dns.rrset.from_text('tls.tests.dnsdist.org.',
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text("tls.tests.dnsdist.org.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.additional.append(rrset)
         return response.to_wire()
 
     def UpgradeDoHCallback(request):
         response = dns.message.make_response(request)
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SVCB,
-                                    '1 tls.tests.dnsdist.org. alpn="h2" port=10653 ipv4hint=127.0.0.1 key7="/dns-query{?dns}"')
+        rrset = dns.rrset.from_text(
+            request.question[0].name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SVCB,
+            '1 tls.tests.dnsdist.org. alpn="h2" port=10653 ipv4hint=127.0.0.1 key7="/dns-query{?dns}"',
+        )
         response.answer.append(rrset)
         return response.to_wire()
 
     def UpgradeDoTDifferentAddr1Callback(request):
         response = dns.message.make_response(request)
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SVCB,
-                                    '1 tls.tests.dnsdist.org. alpn="dot" port=10654 ipv4hint=127.0.0.2')
+        rrset = dns.rrset.from_text(
+            request.question[0].name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SVCB,
+            '1 tls.tests.dnsdist.org. alpn="dot" port=10654 ipv4hint=127.0.0.2',
+        )
         response.answer.append(rrset)
         return response.to_wire()
 
     def UpgradeDoTDifferentAddr2Callback(request):
         response = dns.message.make_response(request)
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SVCB,
-                                    '1 tls.tests.dnsdist.org. alpn="dot" port=10655 ipv4hint=127.0.0.1')
+        rrset = dns.rrset.from_text(
+            request.question[0].name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SVCB,
+            '1 tls.tests.dnsdist.org. alpn="dot" port=10655 ipv4hint=127.0.0.1',
+        )
         response.answer.append(rrset)
         return response.to_wire()
 
     def UpgradeDoTUnreachableCallback(request):
         response = dns.message.make_response(request)
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SVCB,
-                                    '1 tls.tests.dnsdist.org. alpn="dot" port=10656 ipv4hint=127.0.0.1')
+        rrset = dns.rrset.from_text(
+            request.question[0].name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SVCB,
+            '1 tls.tests.dnsdist.org. alpn="dot" port=10656 ipv4hint=127.0.0.1',
+        )
         response.answer.append(rrset)
         return response.to_wire()
 
@@ -192,11 +207,13 @@ class TestBackendDiscovery(DNSDistTest):
 
     def UpgradeDoHMissingPathCallback(request):
         response = dns.message.make_response(request)
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SVCB,
-                                    '1 tls.tests.dnsdist.org. alpn="h2" port=10653 ipv4hint=127.0.0.1')
+        rrset = dns.rrset.from_text(
+            request.question[0].name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SVCB,
+            '1 tls.tests.dnsdist.org. alpn="h2" port=10653 ipv4hint=127.0.0.1',
+        )
         response.answer.append(rrset)
         return response.to_wire()
 
@@ -209,7 +226,7 @@ class TestBackendDiscovery(DNSDistTest):
         return response.to_wire()
 
     def WrongNameCallback(request):
-        query = dns.message.make_query('not-the-right-one.', dns.rdatatype.SVCB)
+        query = dns.message.make_query("not-the-right-one.", dns.rdatatype.SVCB)
         response = dns.message.make_response(query)
         response.id = request.id
         return response.to_wire()
@@ -233,162 +250,378 @@ class TestBackendDiscovery(DNSDistTest):
 
     def UpgradeDoTNoPortCallback(request):
         response = dns.message.make_response(request)
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SVCB,
-                                    '1 tls.tests.dnsdist.org. alpn="dot" ipv4hint=127.0.0.1')
+        rrset = dns.rrset.from_text(
+            request.question[0].name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SVCB,
+            '1 tls.tests.dnsdist.org. alpn="dot" ipv4hint=127.0.0.1',
+        )
         response.answer.append(rrset)
         return response.to_wire()
 
     def UpgradeDoHNoPortCallback(request):
         response = dns.message.make_response(request)
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SVCB,
-                                    '1 tls.tests.dnsdist.org. alpn="h2" ipv4hint=127.0.0.1 key7="/dns-query{?dns}"')
+        rrset = dns.rrset.from_text(
+            request.question[0].name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SVCB,
+            '1 tls.tests.dnsdist.org. alpn="h2" ipv4hint=127.0.0.1 key7="/dns-query{?dns}"',
+        )
         response.answer.append(rrset)
         return response.to_wire()
 
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
-
-        TCPNoSVCResponder = threading.Thread(name='TCP no SVC Responder', target=cls.TCPResponder, args=[cls._noSVCBackendPort, cls._toResponderQueue, cls._fromResponderQueue, True, False, cls.NoSVCCallback])
+        tlsContext.load_cert_chain("server.chain", "server.key")
+
+        TCPNoSVCResponder = threading.Thread(
+            name="TCP no SVC Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._noSVCBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                True,
+                False,
+                cls.NoSVCCallback,
+            ],
+        )
         TCPNoSVCResponder.daemon = True
         TCPNoSVCResponder.start()
 
-        TCPNoUpgradeResponder = threading.Thread(name='TCP no upgrade Responder', target=cls.TCPResponder, args=[cls._svcNoUpgradeBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.NoUpgradePathCallback])
+        TCPNoUpgradeResponder = threading.Thread(
+            name="TCP no upgrade Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._svcNoUpgradeBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.NoUpgradePathCallback,
+            ],
+        )
         TCPNoUpgradeResponder.daemon = True
         TCPNoUpgradeResponder.start()
 
         # this one is special, does partial writes!
-        TCPUpgradeToDoTResponder = threading.Thread(name='TCP upgrade to DoT Responder', target=cls.TCPResponder, args=[cls._svcUpgradeDoTBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.UpgradeDoTCallback, None, False, '127.0.0.1', True])
+        TCPUpgradeToDoTResponder = threading.Thread(
+            name="TCP upgrade to DoT Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._svcUpgradeDoTBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.UpgradeDoTCallback,
+                None,
+                False,
+                "127.0.0.1",
+                True,
+            ],
+        )
         TCPUpgradeToDoTResponder.daemon = True
         TCPUpgradeToDoTResponder.start()
         # and the corresponding DoT responder
-        UpgradedDoTResponder = threading.Thread(name='DoT upgraded Responder', target=cls.TCPResponder, args=[10652, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        UpgradedDoTResponder = threading.Thread(
+            name="DoT upgraded Responder",
+            target=cls.TCPResponder,
+            args=[10652, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         UpgradedDoTResponder.daemon = True
         UpgradedDoTResponder.start()
 
-        TCPUpgradeToDoHResponder = threading.Thread(name='TCP upgrade to DoH Responder', target=cls.TCPResponder, args=[cls._svcUpgradeDoHBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.UpgradeDoHCallback])
+        TCPUpgradeToDoHResponder = threading.Thread(
+            name="TCP upgrade to DoH Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._svcUpgradeDoHBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.UpgradeDoHCallback,
+            ],
+        )
         TCPUpgradeToDoHResponder.daemon = True
         TCPUpgradeToDoHResponder.start()
         # and the corresponding DoH responder
-        UpgradedDOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[10653, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        UpgradedDOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[10653, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         UpgradedDOHResponder.daemon = True
         UpgradedDOHResponder.start()
 
-        TCPUpgradeToDoTDifferentAddrResponder = threading.Thread(name='TCP upgrade to DoT different addr 1 Responder', target=cls.TCPResponder, args=[cls._svcUpgradeDoTBackendDifferentAddrPort1, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.UpgradeDoTDifferentAddr1Callback])
+        TCPUpgradeToDoTDifferentAddrResponder = threading.Thread(
+            name="TCP upgrade to DoT different addr 1 Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._svcUpgradeDoTBackendDifferentAddrPort1,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.UpgradeDoTDifferentAddr1Callback,
+            ],
+        )
         TCPUpgradeToDoTDifferentAddrResponder.daemon = True
         TCPUpgradeToDoTDifferentAddrResponder.start()
         # and the corresponding DoT responder
-        UpgradedDoTResponder = threading.Thread(name='DoT upgraded different addr 1 Responder', target=cls.TCPResponder, args=[10654, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext, False, '127.0.0.2'])
+        UpgradedDoTResponder = threading.Thread(
+            name="DoT upgraded different addr 1 Responder",
+            target=cls.TCPResponder,
+            args=[
+                10654,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                None,
+                tlsContext,
+                False,
+                "127.0.0.2",
+            ],
+        )
         UpgradedDoTResponder.daemon = True
         UpgradedDoTResponder.start()
 
-        TCPUpgradeToDoTDifferentAddrResponder = threading.Thread(name='TCP upgrade to DoT different addr 2 Responder', target=cls.TCPResponder, args=[cls._svcUpgradeDoTBackendDifferentAddrPort2, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.UpgradeDoTDifferentAddr2Callback, None, False, '127.0.0.2'])
+        TCPUpgradeToDoTDifferentAddrResponder = threading.Thread(
+            name="TCP upgrade to DoT different addr 2 Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._svcUpgradeDoTBackendDifferentAddrPort2,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.UpgradeDoTDifferentAddr2Callback,
+                None,
+                False,
+                "127.0.0.2",
+            ],
+        )
         TCPUpgradeToDoTDifferentAddrResponder.daemon = True
         TCPUpgradeToDoTDifferentAddrResponder.start()
         # and the corresponding DoT responder
-        UpgradedDoTResponder = threading.Thread(name='DoT upgraded different addr 2 Responder', target=cls.TCPResponder, args=[10655, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext, False])
+        UpgradedDoTResponder = threading.Thread(
+            name="DoT upgraded different addr 2 Responder",
+            target=cls.TCPResponder,
+            args=[10655, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext, False],
+        )
         UpgradedDoTResponder.daemon = True
         UpgradedDoTResponder.start()
 
-        TCPUpgradeToUnreachableDoTResponder = threading.Thread(name='TCP upgrade to unreachable DoT Responder', target=cls.TCPResponder, args=[cls._svcUpgradeDoTUnreachableBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.UpgradeDoTUnreachableCallback])
+        TCPUpgradeToUnreachableDoTResponder = threading.Thread(
+            name="TCP upgrade to unreachable DoT Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._svcUpgradeDoTUnreachableBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.UpgradeDoTUnreachableCallback,
+            ],
+        )
         TCPUpgradeToUnreachableDoTResponder.daemon = True
         TCPUpgradeToUnreachableDoTResponder.start()
         # and NO corresponding DoT responder
         # this is not a mistake!
 
-        BrokenResponseResponder = threading.Thread(name='Broken response Responder', target=cls.TCPResponder, args=[cls._svcBrokenDNSResponseBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.BrokenResponseCallback])
+        BrokenResponseResponder = threading.Thread(
+            name="Broken response Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._svcBrokenDNSResponseBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.BrokenResponseCallback,
+            ],
+        )
         BrokenResponseResponder.daemon = True
         BrokenResponseResponder.start()
 
-        DOHMissingPathResponder = threading.Thread(name='DoH missing path Responder', target=cls.TCPResponder, args=[cls._svcUpgradeDoHBackendWithoutPathPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.UpgradeDoHMissingPathCallback])
+        DOHMissingPathResponder = threading.Thread(
+            name="DoH missing path Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._svcUpgradeDoHBackendWithoutPathPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.UpgradeDoHMissingPathCallback,
+            ],
+        )
         DOHMissingPathResponder.daemon = True
         DOHMissingPathResponder.start()
 
-        EOFResponder = threading.Thread(name='EOF Responder', target=cls.TCPResponder, args=[cls._eofBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.EOFCallback])
+        EOFResponder = threading.Thread(
+            name="EOF Responder",
+            target=cls.TCPResponder,
+            args=[cls._eofBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.EOFCallback],
+        )
         EOFResponder.daemon = True
         EOFResponder.start()
 
-        ServFailResponder = threading.Thread(name='ServFail Responder', target=cls.TCPResponder, args=[cls._servfailBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.ServFailCallback])
+        ServFailResponder = threading.Thread(
+            name="ServFail Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._servfailBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.ServFailCallback,
+            ],
+        )
         ServFailResponder.daemon = True
         ServFailResponder.start()
 
-        WrongNameResponder = threading.Thread(name='Wrong Name Responder', target=cls.TCPResponder, args=[cls._wrongNameBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.WrongNameCallback])
+        WrongNameResponder = threading.Thread(
+            name="Wrong Name Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._wrongNameBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.WrongNameCallback,
+            ],
+        )
         WrongNameResponder.daemon = True
         WrongNameResponder.start()
 
-        WrongIDResponder = threading.Thread(name='Wrong ID Responder', target=cls.TCPResponder, args=[cls._wrongIDBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.WrongIDCallback])
+        WrongIDResponder = threading.Thread(
+            name="Wrong ID Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._wrongIDBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.WrongIDCallback,
+            ],
+        )
         WrongIDResponder.daemon = True
         WrongIDResponder.start()
 
-        TooManyQuestionsResponder = threading.Thread(name='Too many questions Responder', target=cls.TCPResponder, args=[cls._tooManyQuestionsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.TooManyQuestionsCallback])
+        TooManyQuestionsResponder = threading.Thread(
+            name="Too many questions Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._tooManyQuestionsBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.TooManyQuestionsCallback,
+            ],
+        )
         TooManyQuestionsResponder.daemon = True
         TooManyQuestionsResponder.start()
 
-        badQNameResponder = threading.Thread(name='Bad QName Responder', target=cls.TCPResponder, args=[cls._badQNameBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.BadQNameCallback])
+        badQNameResponder = threading.Thread(
+            name="Bad QName Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._badQNameBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.BadQNameCallback,
+            ],
+        )
         badQNameResponder.daemon = True
         badQNameResponder.start()
 
-        TCPUpgradeToDoTNoPortResponder = threading.Thread(name='TCP upgrade to DoT (no port) Responder', target=cls.TCPResponder, args=[cls._svcUpgradeDoTNoPortBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.UpgradeDoTNoPortCallback])
+        TCPUpgradeToDoTNoPortResponder = threading.Thread(
+            name="TCP upgrade to DoT (no port) Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._svcUpgradeDoTNoPortBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.UpgradeDoTNoPortCallback,
+            ],
+        )
         TCPUpgradeToDoTNoPortResponder.daemon = True
         TCPUpgradeToDoTNoPortResponder.start()
 
-        TCPUpgradeToDoHNoPortResponder = threading.Thread(name='TCP upgrade to DoH (no port) Responder', target=cls.TCPResponder, args=[cls._svcUpgradeDoHNoPortBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.UpgradeDoHNoPortCallback])
+        TCPUpgradeToDoHNoPortResponder = threading.Thread(
+            name="TCP upgrade to DoH (no port) Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._svcUpgradeDoHNoPortBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.UpgradeDoHNoPortCallback,
+            ],
+        )
         TCPUpgradeToDoHNoPortResponder.daemon = True
         TCPUpgradeToDoHNoPortResponder.start()
 
-
     def checkBackendsUpgraded(self):
-        output = self.sendConsoleCommand('showServers()')
+        output = self.sendConsoleCommand("showServers()")
         print(output)
 
         backends = {}
         for line in output.splitlines(False):
-            if line.startswith('#') or line.startswith('All'):
+            if line.startswith("#") or line.startswith("All"):
                 continue
             tokens = line.split()
             self.assertTrue(len(tokens) == 13 or len(tokens) == 14)
-            if tokens[1] == '127.0.0.1:10652':
+            if tokens[1] == "127.0.0.1:10652":
                 # in this particular case, the upgraded backend
                 # does not replace the existing one and thus
                 # the health-check is forced to auto (or lazy auto)
-                self.assertEqual(tokens[2], 'up')
+                self.assertEqual(tokens[2], "up")
             else:
-                self.assertEqual(tokens[2], 'UP')
-            pool = ''
+                self.assertEqual(tokens[2], "UP")
+            pool = ""
             if len(tokens) == 14:
                 pool = tokens[13]
             backends[tokens[1]] = pool
 
         expected = {
-            '127.0.0.1:10600': '',
-            '127.0.0.1:10601': '',
-            '127.0.0.1:10602': 'another-pool',
+            "127.0.0.1:10600": "",
+            "127.0.0.1:10601": "",
+            "127.0.0.1:10602": "another-pool",
             # 10603 has been upgraded to 10653 and removed
             # 10604 has been upgraded to 10654 and removed
-            '127.0.0.2:10605': '',
-            '127.0.0.1:10606': '',
-            '127.0.0.1:10607': '',
-            '127.0.0.1:10608': '',
-            '127.0.0.1:10609': 'other-pool',
-            '127.0.0.1:10610': '',
-            '127.0.0.1:10611': '',
-            '127.0.0.1:10612': '',
-            '127.0.0.1:10613': '',
-            '127.0.0.1:10614': '',
-            '127.0.0.1:10615': '',
+            "127.0.0.2:10605": "",
+            "127.0.0.1:10606": "",
+            "127.0.0.1:10607": "",
+            "127.0.0.1:10608": "",
+            "127.0.0.1:10609": "other-pool",
+            "127.0.0.1:10610": "",
+            "127.0.0.1:10611": "",
+            "127.0.0.1:10612": "",
+            "127.0.0.1:10613": "",
+            "127.0.0.1:10614": "",
+            "127.0.0.1:10615": "",
             # these two are not upgraded because there is no backend listening on the default ports (443 and 853)
-            '127.0.0.1:10616': '',
-            '127.0.0.1:10617': '',
-            '127.0.0.1:10652': 'upgraded',
-            '127.0.0.1:10653': 'another-pool',
-            '127.0.0.2:10654': ''
+            "127.0.0.1:10616": "",
+            "127.0.0.1:10617": "",
+            "127.0.0.1:10652": "upgraded",
+            "127.0.0.1:10653": "another-pool",
+            "127.0.0.2:10654": "",
         }
         print(backends)
         return backends == expected
@@ -405,10 +638,11 @@ class TestBackendDiscovery(DNSDistTest):
             time.sleep(5)
             self.assertTrue(self.checkBackendsUpgraded())
 
+
 class TestBackendDiscoveryByHostname(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -427,32 +661,32 @@ class TestBackendDiscoveryByHostname(DNSDistTest):
     _verboseMode = True
 
     def checkBackends(self):
-        output = self.sendConsoleCommand('showServers()')
+        output = self.sendConsoleCommand("showServers()")
         print(output)
         backends = {}
         for line in output.splitlines(False):
-            if line.startswith('#') or line.startswith('All'):
+            if line.startswith("#") or line.startswith("All"):
                 continue
             tokens = line.split()
             self.assertTrue(len(tokens) == 13 or len(tokens) == 14)
             backends[tokens[1]] = tokens[2]
 
         if len(backends) == 4:
-            for expected in ['9.9.9.9:53', '149.112.112.112:53', '[2620:fe::9]:53', '[2620:fe::fe]:53']:
+            for expected in ["9.9.9.9:53", "149.112.112.112:53", "[2620:fe::9]:53", "[2620:fe::fe]:53"]:
                 self.assertIn(expected, backends)
         elif len(backends) == 2:
             # looks like we are not getting the IPv6 addresses, thanks GitHub!
-            for expected in ['9.9.9.9:53', '149.112.112.112:53']:
+            for expected in ["9.9.9.9:53", "149.112.112.112:53"]:
                 self.assertIn(expected, backends)
         else:
             return False
 
         for backend in backends:
-            if str(backend) in ['2620:fe::9]:53', '[2620:fe::fe]:53']:
+            if str(backend) in ["2620:fe::9]:53", "[2620:fe::fe]:53"]:
                 # IPv6 is very flaky on GH actions these days (202505),
                 # let's not require these to be up
                 continue
-            if backends[backend] != 'up':
+            if backends[backend] != "up":
                 return False
 
         return True
index 087926602a105acc167dd595b4df96e21546fabe..4e3bcfd5554a69cf9f40e9a3346acc6c04f69e78 100644 (file)
@@ -3,8 +3,8 @@ import dns
 import clientsubnetoption
 from dnsdisttests import DNSDistTest
 
-class TestBasics(DNSDistTest):
 
+class TestBasics(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     truncateTC(true)
@@ -27,8 +27,8 @@ class TestBasics(DNSDistTest):
         which is dropped by configuration. We expect
         no response.
         """
-        for name in ['drop.test.powerdns.com.', 'drop2.test.powerdns.com.']:
-            query = dns.message.make_query(name, 'A', 'IN')
+        for name in ["drop.test.powerdns.com.", "drop2.test.powerdns.com."]:
+            query = dns.message.make_query(name, "A", "IN")
             for method in ("sendUDPQuery", "sendTCPQuery"):
                 sender = getattr(self, method)
                 (_, receivedResponse) = sender(query, response=None, useQueue=False)
@@ -38,15 +38,11 @@ class TestBasics(DNSDistTest):
         """
         Basics: A query with an ECS value
         """
-        name = 'awithecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso])
+        name = "awithecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.4")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
@@ -61,14 +57,10 @@ class TestBasics(DNSDistTest):
         """
         Basics: A query without EDNS
         """
-        name = 'simplea.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simplea.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -88,8 +80,8 @@ class TestBasics(DNSDistTest):
         send an ANY query and check the result.
         It should be truncated over UDP, not over TCP.
         """
-        name = 'any.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'ANY', 'IN')
+        name = "any.tests.powerdns.com."
+        query = dns.message.make_query(name, "ANY", "IN")
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
@@ -99,11 +91,7 @@ class TestBasics(DNSDistTest):
         self.assertEqual(receivedResponse, expectedResponse)
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
@@ -123,14 +111,10 @@ class TestBasics(DNSDistTest):
         with TC set and additional content,
         and check that the received response has been fixed.
         """
-        name = 'atruncatetc.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "atruncatetc.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
         response.flags |= dns.flags.TC
@@ -159,16 +143,12 @@ class TestBasics(DNSDistTest):
         Note that the query and initial response had EDNS,
         so the final response should have it too.
         """
-        name = 'atruncatetc.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=True)
+        name = "atruncatetc.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=True)
         # force a different responder payload than the one in the query,
         # so we check that we don't just mirror it
         response = dns.message.make_response(query, our_payload=4242)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
         response.flags |= dns.flags.TC
@@ -199,8 +179,8 @@ class TestBasics(DNSDistTest):
         We send a query for evil4242.powerdns.com
         and check that the response is "refused".
         """
-        name = 'evil4242.regex.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "evil4242.regex.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -216,16 +196,12 @@ class TestBasics(DNSDistTest):
 
         dnsdist is configured to reply 1.2.3.4 for A query for exactly ds9a.nl
         """
-        name = 'ds9a.nl.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "ds9a.nl."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NOERROR)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.4')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -242,8 +218,8 @@ class TestBasics(DNSDistTest):
         We send a TXT query for "nameAndQtype.powerdns.com."
         and check that the response is 'not implemented'.
         """
-        name = 'nameAndQtype.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        name = "nameAndQtype.tests.powerdns.com."
+        query = dns.message.make_query(name, "TXT", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NOTIMP)
@@ -262,14 +238,10 @@ class TestBasics(DNSDistTest):
         We send a A query for "nameAndQtype.tests.powerdns.com."
         and check that the response is OK.
         """
-        name = 'nameAndQtype.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nameAndQtype.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -290,14 +262,10 @@ class TestBasics(DNSDistTest):
         We send a TXT query for "OtherNameAndQtype.tests.powerdns.com."
         and check that the response is OK.
         """
-        name = 'OtherNameAndQtype.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        name = "OtherNameAndQtype.tests.powerdns.com."
+        query = dns.message.make_query(name, "TXT", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'nothing to see here')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, "nothing to see here")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -319,16 +287,12 @@ class TestBasics(DNSDistTest):
         queries to a specific backend in the air over UDP,
         but does not really make sense over TCP.
         """
-        name = 'query.unrelated.tests.powerdns.com.'
-        unrelatedName = 'answer.unrelated.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'TXT', 'IN')
-        unrelatedQuery = dns.message.make_query(unrelatedName, 'TXT', 'IN')
+        name = "query.unrelated.tests.powerdns.com."
+        unrelatedName = "answer.unrelated.tests.powerdns.com."
+        query = dns.message.make_query(name, "TXT", "IN")
+        unrelatedQuery = dns.message.make_query(unrelatedName, "TXT", "IN")
         unrelatedResponse = dns.message.make_response(unrelatedQuery)
-        rrset = dns.rrset.from_text(unrelatedName,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'nothing to see here')
+        rrset = dns.rrset.from_text(unrelatedName, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, "nothing to see here")
         unrelatedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -343,8 +307,8 @@ class TestBasics(DNSDistTest):
         """
         Basics: Header-only refused response
         """
-        name = 'header-only-refused-response.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "header-only-refused-response.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.REFUSED)
         response.question = []
@@ -361,8 +325,8 @@ class TestBasics(DNSDistTest):
         """
         Basics: Header-only NoError response should be dropped
         """
-        name = 'header-only-noerror-response.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "header-only-noerror-response.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.question = []
 
@@ -378,8 +342,8 @@ class TestBasics(DNSDistTest):
         """
         Basics: Header-only NXD response should be dropped
         """
-        name = 'header-only-nxd-response.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "header-only-nxd-response.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.NXDOMAIN)
         response.question = []
@@ -396,8 +360,8 @@ class TestBasics(DNSDistTest):
         """
         Basics: test if addAction accepts a DNSName
         """
-        name = 'dnsname.addaction.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "dnsname.addaction.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -411,8 +375,8 @@ class TestBasics(DNSDistTest):
         """
         Basics: test if addAction accepts a table of DNSNames
         """
-        for name in ['dnsname-table{}.addaction.powerdns.com.'.format(i) for i in range(1,2)]:
-            query = dns.message.make_query(name, 'A', 'IN')
+        for name in ["dnsname-table{}.addaction.powerdns.com.".format(i) for i in range(1, 2)]:
+            query = dns.message.make_query(name, "A", "IN")
             query.flags &= ~dns.flags.RD
             expectedResponse = dns.message.make_response(query)
             expectedResponse.set_rcode(dns.rcode.REFUSED)
index 59d0bbe12938bb0461b6843da4591aad85619a3a..3988ee23401829dffa0927309e6bc413761262a8 100644 (file)
@@ -4,32 +4,29 @@ import clientsubnetoption
 import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
+
 def responseCallback(request):
     if len(request.question) != 1:
         print("Skipping query with question count %d" % (len(request.question)))
         return None
-    healthCheck = str(request.question[0].name).endswith('a.root-servers.net.')
+    healthCheck = str(request.question[0].name).endswith("a.root-servers.net.")
     if healthCheck:
         response = dns.message.make_response(request)
         return response.to_wire()
     # now we create a broken response
     response = dns.message.make_response(request)
-    ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 32)
+    ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 32)
     response.use_edns(edns=True, payload=4096, options=[ecso])
-    rrset = dns.rrset.from_text(request.question[0].name,
-                                3600,
-                                dns.rdataclass.IN,
-                                dns.rdatatype.A,
-                                '127.0.0.1')
+    rrset = dns.rrset.from_text(request.question[0].name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
     response.answer.append(rrset)
     raw = response.to_wire()
     # first label length of this rrset is at 12 (dnsheader) + length(qname) + 2 (leading label length + trailing 0) + 2 (qtype) + 2 (qclass)
     offset = 12 + len(str(request.question[0].name)) + 2 + 2 + 2
-    altered = raw[:offset] + b'\xff' + raw[offset+1:]
+    altered = raw[:offset] + b"\xff" + raw[offset + 1 :]
     return altered
 
-class TestBrokenAnswerECS(DNSDistTest):
 
+class TestBrokenAnswerECS(DNSDistTest):
     # this test suite uses a different responder port
     # because, contrary to the other ones, its
     # responders send raw, broken data
@@ -38,17 +35,26 @@ class TestBrokenAnswerECS(DNSDistTest):
     setECSSourcePrefixV4(32)
     newServer{address="127.0.0.1:%d", useClientSubnet=true}
     """
+
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
 
         # Returns broken data for non-healthcheck queries
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, responseCallback])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, responseCallback],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
 
         # Returns broken data for non-healthcheck queries
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, responseCallback])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, responseCallback],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
@@ -56,13 +62,9 @@ class TestBrokenAnswerECS(DNSDistTest):
         """
         Broken Answer: Invalid UDP answer with ECS
         """
-        name = 'invalid-ecs-udp.broken-answer.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        name = "invalid-ecs-udp.broken-answer.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
 
@@ -78,13 +80,9 @@ class TestBrokenAnswerECS(DNSDistTest):
         """
         Broken Answer: Invalid TCP answer with ECS
         """
-        name = 'invalid-ecs-tcp.broken-answer.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        name = "invalid-ecs-tcp.broken-answer.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
 
index 50f8474c548545e4bc8c9b875038539fcbeb166e..be119295ee02f00696b084ce043604460d0713a6 100644 (file)
@@ -7,20 +7,21 @@ import socket
 import time
 from dnsdisttests import DNSDistTest
 
+
 def writeCDB(fname, variant=1):
-    cdb = cdbx.CDB.make(fname+'.tmp')
-    cdb.add(socket.inet_aton(f'127.0.0.{variant}'), b'this is the value of the source address tag')
-    cdb.add(b'\x05qname\x03cdb\x05tests\x08powerdns\x03com\x00', b'this is the value of the qname tag')
-    cdb.add(b'\x06suffix\x03cdb\x05tests\x08powerdns\x03com\x00', b'this is the value of the suffix tag')
-    cdb.add(b'this is the value of the qname tag', b'this is the value of the second tag')
+    cdb = cdbx.CDB.make(fname + ".tmp")
+    cdb.add(socket.inet_aton(f"127.0.0.{variant}"), b"this is the value of the source address tag")
+    cdb.add(b"\x05qname\x03cdb\x05tests\x08powerdns\x03com\x00", b"this is the value of the qname tag")
+    cdb.add(b"\x06suffix\x03cdb\x05tests\x08powerdns\x03com\x00", b"this is the value of the suffix tag")
+    cdb.add(b"this is the value of the qname tag", b"this is the value of the second tag")
     cdb.commit().close()
-    os.rename(fname+'.tmp', fname)
+    os.rename(fname + ".tmp", fname)
     cdb.close()
 
-@unittest.skipIf('SKIP_CDB_TESTS' in os.environ, 'CDB tests are disabled')
-class CDBTest(DNSDistTest):
 
-    _cdbFileName = '/tmp/test-cdb-db'
+@unittest.skipIf("SKIP_CDB_TESTS" in os.environ, "CDB tests are disabled")
+class CDBTest(DNSDistTest):
+    _cdbFileName = "/tmp/test-cdb-db"
     _cdbRefreshDelay = 1
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -60,10 +61,10 @@ class CDBTest(DNSDistTest):
     -- otherwise, spoof a different response
     addAction(AllRule(), SpoofAction('9.9.9.9'))
     """
-    _config_params = ['_testServerPort', '_cdbFileName', '_cdbRefreshDelay']
+    _config_params = ["_testServerPort", "_cdbFileName", "_cdbRefreshDelay"]
 
-class TestCDBSimple(CDBTest):
 
+class TestCDBSimple(CDBTest):
     @classmethod
     def setUpCDB(cls):
         writeCDB(cls._cdbFileName, 1)
@@ -82,16 +83,12 @@ class TestCDBSimple(CDBTest):
         """
         CDB: Match on source address
         """
-        name = 'source-ip.cdb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "source-ip.cdb.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '5.6.7.8')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "5.6.7.8")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -105,16 +102,12 @@ class TestCDBSimple(CDBTest):
         """
         CDB: Match on qname then does a second lookup using the value of the first lookup
         """
-        name = 'qname.cdb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "qname.cdb.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.4')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -128,16 +121,12 @@ class TestCDBSimple(CDBTest):
         """
         CDB: Match on the qname via a suffix lookup
         """
-        name = 'sub.sub.suffix.cdb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "sub.sub.suffix.cdb.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '42.42.42.42')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "42.42.42.42")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -147,8 +136,8 @@ class TestCDBSimple(CDBTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestCDBReload(CDBTest):
 
+class TestCDBReload(CDBTest):
     @classmethod
     def setUpCDB(cls):
         writeCDB(cls._cdbFileName, 1)
@@ -167,16 +156,12 @@ class TestCDBReload(CDBTest):
         """
         CDB: Test that the CDB is correctly reloaded
         """
-        name = 'reload.cdb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "reload.cdb.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '5.6.7.8')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "5.6.7.8")
         expectedResponse.answer.append(rrset)
 
         # only the source address should match
@@ -196,11 +181,7 @@ class TestCDBReload(CDBTest):
         time.sleep(self._cdbRefreshDelay + 1)
 
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '9.9.9.9')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "9.9.9.9")
         expectedResponse.answer.append(rrset)
 
         # nothing (qname, suffix or source IP) should match
index ce7b1f442318ea919d95590942c9527d5c45d1d0..d1d9a7fe6cfcea20398d8e71f0d5938556554684 100644 (file)
@@ -4,8 +4,8 @@ import time
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestCacheHitResponses(DNSDistTest):
 
+class TestCacheHitResponses(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
@@ -18,14 +18,10 @@ class TestCacheHitResponses(DNSDistTest):
         CacheHitResponse: Drop when served from the cache
         """
         ttl = 5
-        name = 'dropwhencached.cachehitresponses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "dropwhencached.cachehitresponses.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -88,11 +84,11 @@ class TestCacheHitResponses(DNSDistTest):
 
         self.assertEqual(total, 2)
 
-class TestStaleCacheHitResponses(DNSDistTest):
 
+class TestStaleCacheHitResponses(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
@@ -109,14 +105,10 @@ class TestStaleCacheHitResponses(DNSDistTest):
         CacheHitResponse: Drop when served from the stale cache entry
         """
         ttl = 5
-        name = 'dropstaleentry.cachehitresponses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "dropstaleentry.cachehitresponses.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
index 1290eb17118e09f881494ff472b4e380476576f7..37b268ce3720d2d5c3f2a6aaa67082b5bd7e265d 100644 (file)
@@ -2,8 +2,8 @@
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestCacheInsertedResponses(DNSDistTest):
 
+class TestCacheInsertedResponses(DNSDistTest):
     capTTLMax = 3600
     capTTLMin = 60
     _config_template = """
@@ -12,30 +12,22 @@ class TestCacheInsertedResponses(DNSDistTest):
     addCacheInsertedResponseAction(SuffixMatchNodeRule("cacheinsertedresponses.tests.powerdns.com."), LimitTTLResponseAction(%d, %d))
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['capTTLMax', 'capTTLMin', '_testServerPort']
+    _config_params = ["capTTLMax", "capTTLMin", "_testServerPort"]
 
     def testTTLSetAfterInsertion(self):
         """
         CacheInsertedResponse: Check that the TTL is capped after inserting into the cache
         """
         initialTTL = 86400
-        name = 'reduce-ttl-after-insertion.cacheinsertedresponses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "reduce-ttl-after-insertion.cacheinsertedresponses.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    initialTTL,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, initialTTL, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         responseOnMiss = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    self.capTTLMax,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, self.capTTLMax, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         responseOnMiss.answer.append(rrset)
 
         # first query to fill the cache
@@ -58,23 +50,15 @@ class TestCacheInsertedResponses(DNSDistTest):
         CacheInsertedResponse: Check that the TTL can be raised after inserting into the cache
         """
         initialTTL = 0
-        name = 'raise-ttl-after-insertion.cacheinsertedresponses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "raise-ttl-after-insertion.cacheinsertedresponses.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    initialTTL,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, initialTTL, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         responseOnMiss = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    self.capTTLMax,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, self.capTTLMax, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         responseOnMiss.answer.append(rrset)
 
         # first query to fill the cache
index 6621bd691aaa8bb86a8ebbc8cba5c126161e3fbe..88bc08b2bb1c4eebf8f21e4d6d7a0284dd4d5665 100644 (file)
@@ -3,10 +3,11 @@ import base64
 import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
+
 class TestCacheMissSelfAnswered(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
 
     _config_template = """
     setKey("%s")
@@ -25,12 +26,12 @@ class TestCacheMissSelfAnswered(DNSDistTest):
         CacheMiss: Refused when not in cache
         """
         # check that the rule is in place
-        lines = self.sendConsoleCommand('showCacheMissRules()').splitlines()
+        lines = self.sendConsoleCommand("showCacheMissRules()").splitlines()
         self.assertEqual(len(lines), 2)
-        self.assertIn('myFirstRule', lines[1])
+        self.assertIn("myFirstRule", lines[1])
 
-        name = 'refused.cache-miss.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "refused.cache-miss.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
@@ -41,17 +42,13 @@ class TestCacheMissSelfAnswered(DNSDistTest):
         self.assertEqual(receivedResponse, expectedResponse)
 
         # now we remove the rule
-        self.sendConsoleCommand('clearCacheMissRules()')
-        lines = self.sendConsoleCommand('showCacheMissRules()').splitlines()
+        self.sendConsoleCommand("clearCacheMissRules()")
+        lines = self.sendConsoleCommand("showCacheMissRules()").splitlines()
         self.assertEqual(len(lines), 1)
 
         # get a response inserted into the cache
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:db8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::1")
         response.answer.append(rrset)
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=response)
         self.assertTrue(receivedQuery)
@@ -61,21 +58,24 @@ class TestCacheMissSelfAnswered(DNSDistTest):
         self.assertEqual(receivedResponse, response)
 
         # add the rule back
-        self.sendConsoleCommand('addCacheMissAction(SuffixMatchNodeRule("refused.cache-miss.tests.powerdns.com."), RCodeAction(DNSRCode.REFUSED), {name="myFirstRule"})')
-        lines = self.sendConsoleCommand('showCacheMissRules()').splitlines()
+        self.sendConsoleCommand(
+            'addCacheMissAction(SuffixMatchNodeRule("refused.cache-miss.tests.powerdns.com."), RCodeAction(DNSRCode.REFUSED), {name="myFirstRule"})'
+        )
+        lines = self.sendConsoleCommand("showCacheMissRules()").splitlines()
         self.assertEqual(len(lines), 2)
-        self.assertIn('myFirstRule', lines[1])
+        self.assertIn("myFirstRule", lines[1])
 
         # and check that we do get the cached response
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertTrue(receivedResponse)
         self.assertEqual(receivedResponse, response)
 
+
 class TestCacheMissGoToADifferentPool(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_testServer2Port']
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort", "_testServer2Port"]
 
     _config_template = """
     setKey("%s")
@@ -99,14 +99,10 @@ class TestCacheMissGoToADifferentPool(DNSDistTest):
         """
         CacheMiss: Routed to a different pool when not in cache
         """
-        name = 'routed-to-slow.cache-miss.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "routed-to-slow.cache-miss.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:db8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::1")
         response.answer.append(rrset)
 
         # first query goes to the 'slow' server
@@ -122,16 +118,16 @@ class TestCacheMissGoToADifferentPool(DNSDistTest):
         self.assertTrue(receivedResponse)
         self.assertEqual(receivedResponse, response)
 
-        backendLines = self.sendConsoleCommand('showServers()').splitlines(False)
+        backendLines = self.sendConsoleCommand("showServers()").splitlines(False)
         self.assertEqual(len(backendLines), 4)
         for line in backendLines:
-            if line.startswith('#') or line.startswith('All'):
+            if line.startswith("#") or line.startswith("All"):
                 continue
             tokens = line.split()
             self.assertEqual(len(tokens), 15)
             pool = tokens[13]
             queries = int(tokens[9])
-            if pool == 'slow':
+            if pool == "slow":
                 self.assertEqual(queries, 1)
             else:
                 self.assertEqual(queries, 0)
index a3c482381797d390d0cea2d2b00c48226fdf82f6..8fd108388ef04cea06e2657e658ed18d46846661 100644 (file)
@@ -4,8 +4,8 @@ import paddingoption
 import randompaddingoption
 from dnsdisttests import DNSDistTest
 
-class TestCachePadding(DNSDistTest):
 
+class TestCachePadding(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
@@ -16,15 +16,11 @@ class TestCachePadding(DNSDistTest):
         """
         Cache padding
         """
-        name = 'padding.cache-padding.tests.powerdns.com.'
+        name = "padding.cache-padding.tests.powerdns.com."
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -40,7 +36,7 @@ class TestCachePadding(DNSDistTest):
 
         # generate a new padding payload, with random bytes
         rpo = randompaddingoption.RandomPaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[rpo])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[rpo])
         response = dns.message.make_response(query)
         response.answer.append(rrset)
 
@@ -48,8 +44,8 @@ class TestCachePadding(DNSDistTest):
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, response)
 
-class TestCacheNotSkippingPadding(DNSDistTest):
 
+class TestCacheNotSkippingPadding(DNSDistTest):
     _config_template = """
     -- only skip EDNS cookies, not padding
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1, skipOptions={10}})
@@ -61,15 +57,11 @@ class TestCacheNotSkippingPadding(DNSDistTest):
         """
         Cache padding: not skipping the padding
         """
-        name = 'not-skipping-padding.cache-padding.tests.powerdns.com.'
+        name = "not-skipping-padding.cache-padding.tests.powerdns.com."
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -85,7 +77,7 @@ class TestCacheNotSkippingPadding(DNSDistTest):
 
         # generate a new padding payload, with random bytes
         rpo = randompaddingoption.RandomPaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[rpo])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[rpo])
         response = dns.message.make_response(query)
 
         # identical query except for the padding content which should NOT be skipped, should NOT be cached
index aebe8c7a27116e0cc5ec07cea68d921619aa85eb..112f129bb0a46c68fb2faf8aa7a49f9151cc8c88 100644 (file)
@@ -7,8 +7,8 @@ import cookiesoption
 import requests
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class TestCaching(DNSDistTest):
 
+class TestCaching(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
@@ -31,14 +31,10 @@ class TestCaching(DNSDistTest):
         the first one.
         """
         numberOfQueries = 10
-        name = 'cached.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cached.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -84,8 +80,8 @@ class TestCaching(DNSDistTest):
         """
         Cache: Empty TC=1 is not cached by default
         """
-        name = 'empty-tc.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "empty-tc.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
         response.flags |= dns.flags.TC
 
@@ -106,14 +102,10 @@ class TestCaching(DNSDistTest):
         the first one.
         """
         numberOfQueries = 10
-        name = 'cached-do.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, want_dnssec=True)
+        name = "cached-do.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, want_dnssec=True)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -162,15 +154,11 @@ class TestCaching(DNSDistTest):
         dnsdist is configured to not cache entries for nocache.cache.tests.powerdns.com.
          we are sending several requests and checking that the backend get them all.
         """
-        name = 'nocache.cache.tests.powerdns.com.'
+        name = "nocache.cache.tests.powerdns.com."
         numberOfQueries = 10
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         for _ in range(numberOfQueries):
@@ -194,15 +182,11 @@ class TestCaching(DNSDistTest):
         dnsdist is configured to not cache entries for nocachevialua.cache.tests.powerdns.com.
          we are sending several requests and checking that the backend get them all.
         """
-        name = 'nocachevialua.cache.tests.powerdns.com.'
+        name = "nocachevialua.cache.tests.powerdns.com."
         numberOfQueries = 10
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         for _ in range(numberOfQueries):
@@ -226,15 +210,11 @@ class TestCaching(DNSDistTest):
         dnsdist is configured to not cache entries for answer matching nocache-response.cache.tests.powerdns.com.
          we are sending several requests and checking that the backend get them all.
         """
-        name = 'nocache-response.cache.tests.powerdns.com.'
+        name = "nocache-response.cache.tests.powerdns.com."
         numberOfQueries = 10
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         for _ in range(numberOfQueries):
@@ -257,20 +237,18 @@ class TestCaching(DNSDistTest):
 
         dnsdist should not cache responses to AXFR queries.
         """
-        name = 'axfr.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AXFR', 'IN')
+        name = "axfr.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AXFR", "IN")
         response = dns.message.make_response(query)
-        soa = dns.rrset.from_text(name,
-                                  60,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
         response.answer.append(soa)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '192.0.2.1'))
+        response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
         response.answer.append(soa)
         numberOfQueries = 5
 
@@ -294,20 +272,18 @@ class TestCaching(DNSDistTest):
 
         dnsdist should not cache responses to IXFR queries.
         """
-        name = 'ixfr.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'IXFR', 'IN')
+        name = "ixfr.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "IXFR", "IN")
         response = dns.message.make_response(query)
-        soa = dns.rrset.from_text(name,
-                                  60,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
         response.answer.append(soa)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   60,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '192.0.2.1'))
+        response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
         response.answer.append(soa)
         numberOfQueries = 5
 
@@ -336,14 +312,10 @@ class TestCaching(DNSDistTest):
         """
         ttl = 2
         misses = 0
-        name = 'cacheexpiration.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cacheexpiration.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -393,20 +365,24 @@ class TestCaching(DNSDistTest):
         """
         ttl = 2
         misses = 0
-        name = 'cacheexpirationdifferentsets.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cacheexpirationdifferentsets.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'cname.cacheexpirationdifferentsets.cache.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name,
+            ttl,
+            dns.rdataclass.IN,
+            dns.rdatatype.CNAME,
+            "cname.cacheexpirationdifferentsets.cache.tests.powerdns.com.",
+        )
         response.answer.append(rrset)
-        rrset = dns.rrset.from_text('cname.cacheexpirationdifferentsets.cache.tests.powerdns.com.',
-                                    ttl + 3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.2.0.1')
+        rrset = dns.rrset.from_text(
+            "cname.cacheexpirationdifferentsets.cache.tests.powerdns.com.",
+            ttl + 3600,
+            dns.rdataclass.IN,
+            dns.rdatatype.A,
+            "192.2.0.1",
+        )
         response.additional.append(rrset)
 
         # first query to fill the cache
@@ -453,14 +429,10 @@ class TestCaching(DNSDistTest):
         """
         ttl = 600
         misses = 0
-        name = 'cachedecreasettl.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cachedecreasettl.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -502,17 +474,13 @@ class TestCaching(DNSDistTest):
         matches.
         """
         ttl = 600
-        name = 'cachedifferentcase.cache.tests.powerdns.com.'
-        differentCaseName = 'CacheDifferentCASE.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
-        differentCaseQuery = dns.message.make_query(differentCaseName, 'AAAA', 'IN')
+        name = "cachedifferentcase.cache.tests.powerdns.com."
+        differentCaseName = "CacheDifferentCASE.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
+        differentCaseQuery = dns.message.make_query(differentCaseName, "AAAA", "IN")
         response = dns.message.make_response(query)
         differentCaseResponse = dns.message.make_response(differentCaseQuery)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
         differentCaseResponse.answer.append(rrset)
 
@@ -535,23 +503,19 @@ class TestCaching(DNSDistTest):
         We should be able to get answers as large as 4096 bytes
         """
         numberOfQueries = 10
-        name = 'large-answer.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'TXT', 'IN', payload=4096)
+        name = "large-answer.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "TXT", "IN", payload=4096)
         response = dns.message.make_response(query)
         # we prepare a large answer
         content = ""
         for i in range(44):
             if len(content) > 0:
-                content = content + ', '
-            content = content + (str(i)*50)
+                content = content + ", "
+            content = content + (str(i) * 50)
         # pad up to 4096 (less 11 for EDNS)
-        content = content + 'A'*31
+        content = content + "A" * 31
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    content)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, content)
         response.answer.append(rrset)
         self.assertEqual(len(response.to_wire()), 4096)
 
@@ -599,15 +563,11 @@ class TestCaching(DNSDistTest):
         Cache: The content of cookies should be ignored by the cache
         """
         ttl = 600
-        name = 'cache-different-cookies.cache.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, options=[eco])
+        name = "cache-different-cookies.cache.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, options=[eco])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -618,8 +578,8 @@ class TestCaching(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-        eco = cookiesoption.CookiesOption(b'badc0fee', b'badc0fee')
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, options=[eco])
+        eco = cookiesoption.CookiesOption(b"badc0fee", b"badc0fee")
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, options=[eco])
         # second query should be served from the cache
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         receivedResponse.id = response.id
@@ -630,15 +590,11 @@ class TestCaching(DNSDistTest):
         Cache: A query with a cookie should not match one without any cookie
         """
         ttl = 600
-        name = 'cache-cookie.cache.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco])
+        name = "cache-cookie.cache.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -649,13 +605,9 @@ class TestCaching(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[])
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         # second query should NOT be served from the cache
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -670,16 +622,12 @@ class TestCaching(DNSDistTest):
         Cache: The content of cookies should be ignored by the cache but not the ECS one
         """
         ttl = 600
-        name = 'cache-different-cookies-different-ecs.cache.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, options=[eco,ecso])
+        name = "cache-different-cookies-different-ecs.cache.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, options=[eco, ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -689,15 +637,11 @@ class TestCaching(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32)
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, options=[eco,ecso])
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.2", 32)
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, options=[eco, ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -707,8 +651,8 @@ class TestCaching(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-class TestCachingHashingOptions(DNSDistTest):
 
+class TestCachingHashingOptions(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1, cookieHashing=true, skipOptions={8}})
     getPool(""):setCache(pc)
@@ -720,16 +664,12 @@ class TestCachingHashingOptions(DNSDistTest):
         Cache: ECS should be ignored by the cache even if cookie is present
         """
         ttl = 600
-        name = 'cache-different-ecs.cache.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32)
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, options=[eco,ecso])
+        name = "cache-different-ecs.cache.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.2", 32)
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, options=[eco, ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -740,16 +680,16 @@ class TestCachingHashingOptions(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, options=[eco,ecso])
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, options=[eco, ecso])
         # second query should be served from the cache
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         receivedResponse.id = response.id
         self.assertEqual(receivedResponse, response)
 
-class TestCachingHashingCookies(DNSDistTest):
 
+class TestCachingHashingCookies(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1, cookieHashing=true})
     getPool(""):setCache(pc)
@@ -765,14 +705,10 @@ class TestCachingHashingCookies(DNSDistTest):
         the first one.
         """
         numberOfQueries = 10
-        name = 'cached.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cached.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -814,21 +750,16 @@ class TestCachingHashingCookies(DNSDistTest):
 
         self.assertEqual(total, 1)
 
-
     def testCacheDifferentCookies(self):
         """
         Cache: The content of cookies should NOT be ignored by the cache (cookieHashing is set)
         """
         ttl = 600
-        name = 'cache-different-cookies.cache-cookie-hashing.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, options=[eco])
+        name = "cache-different-cookies.cache-cookie-hashing.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, options=[eco])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -839,14 +770,10 @@ class TestCachingHashingCookies(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-        eco = cookiesoption.CookiesOption(b'badc0fee', b'badc0fee')
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, options=[eco])
+        eco = cookiesoption.CookiesOption(b"badc0fee", b"badc0fee")
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, options=[eco])
         differentResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         differentResponse.answer.append(rrset)
         # second query should NOT be served from the cache
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, differentResponse)
@@ -862,15 +789,11 @@ class TestCachingHashingCookies(DNSDistTest):
         Cache: A query with a cookie should not match one without any cookie (cookieHashing=true)
         """
         ttl = 600
-        name = 'cache-cookie.cache-cookie-hashing.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco])
+        name = "cache-cookie.cache-cookie-hashing.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -881,13 +804,9 @@ class TestCachingHashingCookies(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[])
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         # second query should NOT be served from the cache
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -902,16 +821,12 @@ class TestCachingHashingCookies(DNSDistTest):
         Cache: The content of cookies should NOT be ignored by the cache (cookieHashing=true), even with ECS there
         """
         ttl = 600
-        name = 'cache-different-cookies-different-ecs.cache-cookie-hashing.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, options=[eco,ecso])
+        name = "cache-different-cookies-different-ecs.cache-cookie-hashing.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, options=[eco, ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -921,15 +836,11 @@ class TestCachingHashingCookies(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32)
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, options=[eco,ecso])
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.2", 32)
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, payload=4096, options=[eco, ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -939,8 +850,8 @@ class TestCachingHashingCookies(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-class TestTempFailureCacheTTLAction(DNSDistTest):
 
+class TestTempFailureCacheTTLAction(DNSDistTest):
     _extraStartupSleep = 1
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
@@ -958,8 +869,8 @@ class TestTempFailureCacheTTLAction(DNSDistTest):
         (cache miss) and verify that the cache is hit for the following query,
         but the TTL then expires before the larger "good" packetcache TTL.
         """
-        name = 'servfail.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "servfail.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.SERVFAIL)
 
@@ -985,13 +896,14 @@ class TestTempFailureCacheTTLAction(DNSDistTest):
         self.assertTrue(receivedResponse)
         self.assertEqual(receivedResponse, response)
 
-class TestCachingWithExistingEDNS(DNSDistTest):
 
+class TestCachingWithExistingEDNS(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
     newServer{address="127.0.0.1:%d"}
     """
+
     def testCacheWithEDNS(self):
         """
         Cache: Cache should not match different EDNS value
@@ -1001,14 +913,10 @@ class TestCachingWithExistingEDNS(DNSDistTest):
         Payload size is not served from the cache.
         """
         misses = 0
-        name = 'cachedifferentedns.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512)
+        name = "cachedifferentedns.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=512)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -1019,13 +927,9 @@ class TestCachingWithExistingEDNS(DNSDistTest):
         self.assertEqual(response, receivedResponse)
         misses += 1
 
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -1042,27 +946,24 @@ class TestCachingWithExistingEDNS(DNSDistTest):
 
         self.assertEqual(total, misses)
 
-class TestCachingCacheFull(DNSDistTest):
 
+class TestCachingCacheFull(DNSDistTest):
     _config_template = """
     pc = newPacketCache(1, {maxTTL=86400, minTTL=1, numberOfShards=1})
     getPool(""):setCache(pc)
     newServer{address="127.0.0.1:%d"}
     """
+
     def testCacheFull(self):
         """
         Cache: No new entries are cached when the cache is full
 
         """
         misses = 0
-        name = 'cachenotfullyet.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "cachenotfullyet.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # Miss
@@ -1079,14 +980,10 @@ class TestCachingCacheFull(DNSDistTest):
         self.assertEqual(receivedResponse, response)
 
         # ok, now the cache is full, send another query
-        name = 'cachefull.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cachefull.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # Miss
@@ -1113,11 +1010,11 @@ class TestCachingCacheFull(DNSDistTest):
 
         self.assertEqual(total, misses)
 
-class TestCachingNoStale(DNSDistTest):
 
+class TestCachingNoStale(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
@@ -1125,20 +1022,17 @@ class TestCachingNoStale(DNSDistTest):
     controlSocket("127.0.0.1:%d")
     newServer{address="127.0.0.1:%d"}
     """
+
     def testCacheNoStale(self):
         """
         Cache: Cache entry, set backend down, we should not get a stale entry
 
         """
         ttl = 2
-        name = 'nostale.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nostale.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # Miss
@@ -1164,11 +1058,10 @@ class TestCachingNoStale(DNSDistTest):
 
 
 class TestCachingStale(DNSDistTest):
-
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _staleCacheTTL = 60
-    _config_params = ['_staleCacheTTL', '_consoleKeyB64', '_consolePort', '_testServerPort', '_testServerPort']
+    _config_params = ["_staleCacheTTL", "_consoleKeyB64", "_consolePort", "_testServerPort", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=0, staleTTL=%d})
     getPool(""):setCache(pc)
@@ -1188,14 +1081,10 @@ class TestCachingStale(DNSDistTest):
         """
         misses = 0
         ttl = 2
-        name = 'stale.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "stale.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # Miss
@@ -1235,14 +1124,10 @@ class TestCachingStale(DNSDistTest):
         """
         misses = 0
         ttl = 2
-        name = 'stale-tcp-only.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "stale-tcp-only.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # Miss
@@ -1275,12 +1160,12 @@ class TestCachingStale(DNSDistTest):
 
         self.assertEqual(total, misses)
 
-class TestCachingStaleExpunged(DNSDistTest):
 
+class TestCachingStaleExpunged(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _staleCacheTTL = 60
-    _config_params = ['_staleCacheTTL', '_consoleKeyB64', '_consolePort', '_testServerPort']
+    _config_params = ["_staleCacheTTL", "_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=0, staleTTL=%d})
     getPool(""):setCache(pc)
@@ -1293,6 +1178,7 @@ class TestCachingStaleExpunged(DNSDistTest):
     controlSocket("127.0.0.1:%d")
     newServer{address="127.0.0.1:%d"}
     """
+
     def testCacheStale(self):
         """
         Cache: Cache entry, set backend down, wait for the cache cleaning to run and remove the entry, get no entry
@@ -1300,14 +1186,10 @@ class TestCachingStaleExpunged(DNSDistTest):
         misses = 0
         drops = 0
         ttl = 2
-        name = 'stale-but-expunged.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "stale-but-expunged.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # Miss
@@ -1318,14 +1200,16 @@ class TestCachingStaleExpunged(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(response, receivedResponse)
         misses += 1
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"misses\"]").strip("\n")), misses + drops)
+        self.assertEqual(
+            int(self.sendConsoleCommand('getPool(""):getCache():getStats()["misses"]').strip("\n")), misses + drops
+        )
 
         # next queries should hit the cache
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, response)
         # the cache should have one entry
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"entries\"]").strip("\n")), 1)
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"hits\"]").strip("\n")), 1)
+        self.assertEqual(int(self.sendConsoleCommand('getPool(""):getCache():getStats()["entries"]').strip("\n")), 1)
+        self.assertEqual(int(self.sendConsoleCommand('getPool(""):getCache():getStats()["hits"]').strip("\n")), 1)
 
         # ok, we mark the backend as down
         self.sendConsoleCommand("getServer(0):setDown()")
@@ -1334,15 +1218,17 @@ class TestCachingStaleExpunged(DNSDistTest):
         # wait a bit more to be sure that the cache cleaning algo has been run
         time.sleep(1)
         # the cache should be empty now
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"entries\"]").strip("\n")), 0)
+        self.assertEqual(int(self.sendConsoleCommand('getPool(""):getCache():getStats()["entries"]').strip("\n")), 0)
 
         # we should get a DROP (backend is down, nothing in the cache anymore)
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
         drops += 1
 
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"misses\"]").strip("\n")), misses + drops)
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"hits\"]").strip("\n")), 1)
+        self.assertEqual(
+            int(self.sendConsoleCommand('getPool(""):getCache():getStats()["misses"]').strip("\n")), misses + drops
+        )
+        self.assertEqual(int(self.sendConsoleCommand('getPool(""):getCache():getStats()["hits"]').strip("\n")), 1)
 
         total = 0
         for key in self._responsesCounter:
@@ -1350,11 +1236,11 @@ class TestCachingStaleExpunged(DNSDistTest):
 
         self.assertEqual(total, misses)
 
-class TestCachingStaleExpungePrevented(DNSDistTest):
 
+class TestCachingStaleExpungePrevented(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=0, staleTTL=60, dontAge=false, numberOfShards=1, deferrableInsertLock=true, maxNegativeTTL=3600, parseECS=false, keepStaleData=true})
     getPool(""):setCache(pc)
@@ -1367,20 +1253,17 @@ class TestCachingStaleExpungePrevented(DNSDistTest):
     controlSocket("127.0.0.1:%d")
     newServer{address="127.0.0.1:%d"}
     """
+
     def testCacheStale(self):
         """
         Cache: Cache entry, set backend down, wait for the cache cleaning to run and remove the entry, still get a cache HIT because the stale entry was not removed
         """
         misses = 0
         ttl = 2
-        name = 'stale-not-expunged.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "stale-not-expunged.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # Miss
@@ -1391,14 +1274,14 @@ class TestCachingStaleExpungePrevented(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(response, receivedResponse)
         misses += 1
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"misses\"]").strip("\n")), 1)
+        self.assertEqual(int(self.sendConsoleCommand('getPool(""):getCache():getStats()["misses"]').strip("\n")), 1)
 
         # next queries should hit the cache
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, response)
         # the cache should have one entry
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"entries\"]").strip("\n")), 1)
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"hits\"]").strip("\n")), 1)
+        self.assertEqual(int(self.sendConsoleCommand('getPool(""):getCache():getStats()["entries"]').strip("\n")), 1)
+        self.assertEqual(int(self.sendConsoleCommand('getPool(""):getCache():getStats()["hits"]').strip("\n")), 1)
 
         # ok, we mark the backend as down
         self.sendConsoleCommand("getServer(0):setDown()")
@@ -1408,14 +1291,14 @@ class TestCachingStaleExpungePrevented(DNSDistTest):
         time.sleep(1)
         # the cache should NOT be empty because the removal of the expired entry should have been prevented
         # since all backends for this pool are down
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"entries\"]").strip("\n")), 1)
+        self.assertEqual(int(self.sendConsoleCommand('getPool(""):getCache():getStats()["entries"]').strip("\n")), 1)
 
         # we should get a HIT
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, response)
 
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"misses\"]").strip("\n")), 1)
-        self.assertEqual(int(self.sendConsoleCommand("getPool(\"\"):getCache():getStats()[\"hits\"]").strip("\n")), 2)
+        self.assertEqual(int(self.sendConsoleCommand('getPool(""):getCache():getStats()["misses"]').strip("\n")), 1)
+        self.assertEqual(int(self.sendConsoleCommand('getPool(""):getCache():getStats()["hits"]').strip("\n")), 2)
 
         total = 0
         for key in self._responsesCounter:
@@ -1423,11 +1306,11 @@ class TestCachingStaleExpungePrevented(DNSDistTest):
 
         self.assertEqual(total, misses)
 
-class TestCacheManagement(DNSDistTest):
 
+class TestCacheManagement(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
@@ -1435,6 +1318,7 @@ class TestCacheManagement(DNSDistTest):
     controlSocket("127.0.0.1:%d")
     newServer{address="127.0.0.1:%d"}
     """
+
     def testCacheExpunge(self):
         """
         Cache: Expunge
@@ -1442,14 +1326,10 @@ class TestCacheManagement(DNSDistTest):
         """
         misses = 0
         ttl = 600
-        name = 'expunge.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "expunge.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # Miss
@@ -1466,7 +1346,7 @@ class TestCacheManagement(DNSDistTest):
         self.assertEqual(receivedResponse, response)
 
         # remove cached entries
-        self.sendConsoleCommand("getPool(\"\"):getCache():expunge(0)")
+        self.sendConsoleCommand('getPool(""):getCache():expunge(0)')
 
         # Miss
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -1494,24 +1374,16 @@ class TestCacheManagement(DNSDistTest):
         """
         misses = 0
         ttl = 600
-        name = 'expungebyname.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "expungebyname.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        name2 = 'expungebynameother.cache.tests.powerdns.com.'
-        query2 = dns.message.make_query(name2, 'A', 'IN')
+        name2 = "expungebynameother.cache.tests.powerdns.com."
+        query2 = dns.message.make_query(name2, "A", "IN")
         response2 = dns.message.make_response(query2)
-        rrset2 = dns.rrset.from_text(name2,
-                                     ttl,
-                                     dns.rdataclass.IN,
-                                     dns.rdatatype.A,
-                                     '127.0.0.1')
+        rrset2 = dns.rrset.from_text(name2, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response2.answer.append(rrset2)
 
         # Miss
@@ -1544,7 +1416,7 @@ class TestCacheManagement(DNSDistTest):
         self.assertEqual(receivedResponse, response2)
 
         # remove cached entries from name
-        self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"" + name + "\"))")
+        self.sendConsoleCommand('getPool(""):getCache():expungeByName(newDNSName("' + name + '"))')
 
         # Miss for name
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -1576,23 +1448,15 @@ class TestCacheManagement(DNSDistTest):
         """
         misses = 0
         ttl = 600
-        name = 'expungebynameandtype.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "expungebynameandtype.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        query2 = dns.message.make_query(name, 'AAAA', 'IN')
+        query2 = dns.message.make_query(name, "AAAA", "IN")
         response2 = dns.message.make_response(query2)
-        rrset2 = dns.rrset.from_text(name,
-                                     ttl,
-                                     dns.rdataclass.IN,
-                                     dns.rdatatype.AAAA,
-                                     '::1')
+        rrset2 = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response2.answer.append(rrset2)
 
         # Miss
@@ -1625,7 +1489,7 @@ class TestCacheManagement(DNSDistTest):
         self.assertEqual(receivedResponse, response2)
 
         # remove cached entries from name A
-        self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"" + name + "\"), DNSQType.A)")
+        self.sendConsoleCommand('getPool(""):getCache():expungeByName(newDNSName("' + name + '"), DNSQType.A)')
 
         # Miss for name A
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -1656,24 +1520,16 @@ class TestCacheManagement(DNSDistTest):
         """
         misses = 0
         ttl = 600
-        name = 'expungebyname.suffix.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "expungebyname.suffix.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        name2 = 'expungebyname.suffixother.cache.tests.powerdns.com.'
-        query2 = dns.message.make_query(name2, 'A', 'IN')
+        name2 = "expungebyname.suffixother.cache.tests.powerdns.com."
+        query2 = dns.message.make_query(name2, "A", "IN")
         response2 = dns.message.make_response(query2)
-        rrset2 = dns.rrset.from_text(name2,
-                                     ttl,
-                                     dns.rdataclass.IN,
-                                     dns.rdatatype.A,
-                                     '127.0.0.1')
+        rrset2 = dns.rrset.from_text(name2, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response2.answer.append(rrset2)
 
         # Miss
@@ -1706,7 +1562,9 @@ class TestCacheManagement(DNSDistTest):
         self.assertEqual(receivedResponse, response2)
 
         # remove cached entries from name
-        self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"suffix.cache.tests.powerdns.com.\"), DNSQType.ANY, true)")
+        self.sendConsoleCommand(
+            'getPool(""):getCache():expungeByName(newDNSName("suffix.cache.tests.powerdns.com."), DNSQType.ANY, true)'
+        )
 
         # Miss for name
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -1738,23 +1596,15 @@ class TestCacheManagement(DNSDistTest):
         """
         misses = 0
         ttl = 600
-        name = 'expungebynameandtype.suffixtype.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "expungebynameandtype.suffixtype.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        query2 = dns.message.make_query(name, 'AAAA', 'IN')
+        query2 = dns.message.make_query(name, "AAAA", "IN")
         response2 = dns.message.make_response(query2)
-        rrset2 = dns.rrset.from_text(name,
-                                     ttl,
-                                     dns.rdataclass.IN,
-                                     dns.rdatatype.AAAA,
-                                     '::1')
+        rrset2 = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response2.answer.append(rrset2)
 
         # Miss
@@ -1787,7 +1637,9 @@ class TestCacheManagement(DNSDistTest):
         self.assertEqual(receivedResponse, response2)
 
         # remove cached entries from name A
-        self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"suffixtype.cache.tests.powerdns.com.\"), DNSQType.A, true)")
+        self.sendConsoleCommand(
+            'getPool(""):getCache():expungeByName(newDNSName("suffixtype.cache.tests.powerdns.com."), DNSQType.A, true)'
+        )
 
         # Miss for name A
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -1811,16 +1663,17 @@ class TestCacheManagement(DNSDistTest):
             total += self._responsesCounter[key]
         self.assertEqual(total, misses)
 
-class TestCachingTTL(DNSDistTest):
 
+class TestCachingTTL(DNSDistTest):
     _maxCacheTTL = 86400
     _minCacheTTL = 600
-    _config_params = ['_maxCacheTTL', '_minCacheTTL', '_testServerPort']
+    _config_params = ["_maxCacheTTL", "_minCacheTTL", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(1000, {maxTTL=%d, minTTL=%d})
     getPool(""):setCache(pc)
     newServer{address="127.0.0.1:%d"}
     """
+
     def testCacheShortTTL(self):
         """
         Cache: Entries with a TTL shorter than minTTL
@@ -1828,14 +1681,10 @@ class TestCachingTTL(DNSDistTest):
         """
         misses = 0
         ttl = 60
-        name = 'ttltooshort.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "ttltooshort.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # Miss
@@ -1872,8 +1721,8 @@ class TestCachingTTL(DNSDistTest):
 
         """
         misses = 0
-        name = 'nxwithnorr.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nxwithnorr.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.NXDOMAIN)
 
@@ -1901,15 +1750,16 @@ class TestCachingTTL(DNSDistTest):
 
         self.assertEqual(total, misses)
 
-class TestCachingLongTTL(DNSDistTest):
 
+class TestCachingLongTTL(DNSDistTest):
     _maxCacheTTL = 2
-    _config_params = ['_maxCacheTTL', '_testServerPort']
+    _config_params = ["_maxCacheTTL", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(1000, {maxTTL=%d})
     getPool(""):setCache(pc)
     newServer{address="127.0.0.1:%d"}
     """
+
     def testCacheLongTTL(self):
         """
         Cache: Entries with a longer TTL than the maximum
@@ -1917,14 +1767,10 @@ class TestCachingLongTTL(DNSDistTest):
         """
         misses = 0
         ttl = 172800
-        name = 'longttl.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "longttl.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # Miss
@@ -1964,23 +1810,24 @@ class TestCachingLongTTL(DNSDistTest):
 
         self.assertEqual(total, misses)
 
-class TestCachingFailureTTL(DNSDistTest):
 
+class TestCachingFailureTTL(DNSDistTest):
     _failureCacheTTL = 2
-    _config_params = ['_failureCacheTTL', '_testServerPort']
+    _config_params = ["_failureCacheTTL", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(1000, {maxTTL=86400, minTTL=0, temporaryFailureTTL=%d, staleTTL=60})
     getPool(""):setCache(pc)
     newServer{address="127.0.0.1:%d"}
     """
+
     def testCacheServFailTTL(self):
         """
         Cache: ServFail TTL
 
         """
         misses = 0
-        name = 'servfail.failure.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "servfail.failure.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.SERVFAIL)
 
@@ -2021,8 +1868,8 @@ class TestCachingFailureTTL(DNSDistTest):
 
         """
         misses = 0
-        name = 'refused.failure.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "refused.failure.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.REFUSED)
 
@@ -2063,8 +1910,8 @@ class TestCachingFailureTTL(DNSDistTest):
 
         """
         misses = 0
-        name = 'header-only-refused.failure.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "header-only-refused.failure.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.REFUSED)
         response.question = []
@@ -2100,10 +1947,10 @@ class TestCachingFailureTTL(DNSDistTest):
 
         self.assertEqual(total, misses)
 
-class TestCachingNegativeTTL(DNSDistTest):
 
+class TestCachingNegativeTTL(DNSDistTest):
     _negCacheTTL = 2
-    _config_params = ['_negCacheTTL', '_testServerPort']
+    _config_params = ["_negCacheTTL", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(1000, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false, numberOfShards=1, deferrableInsertLock=true, maxNegativeTTL=%d})
     getPool(""):setCache(pc)
@@ -2116,15 +1963,17 @@ class TestCachingNegativeTTL(DNSDistTest):
 
         """
         misses = 0
-        name = 'nxdomain.negativettl.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nxdomain.negativettl.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.NXDOMAIN)
-        soa = dns.rrset.from_text(name,
-                                  60,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
         response.authority.append(soa)
 
         # Miss
@@ -2164,15 +2013,17 @@ class TestCachingNegativeTTL(DNSDistTest):
 
         """
         misses = 0
-        name = 'nodata.negativettl.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nodata.negativettl.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.NOERROR)
-        soa = dns.rrset.from_text(name,
-                                  60,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
         response.authority.append(soa)
 
         # Miss
@@ -2206,13 +2057,14 @@ class TestCachingNegativeTTL(DNSDistTest):
 
         self.assertEqual(total, misses)
 
-class TestCachingDontAge(DNSDistTest):
 
+class TestCachingDontAge(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=true})
     getPool(""):setCache(pc)
     newServer{address="127.0.0.1:%d"}
     """
+
     def testCacheDoesntDecreaseTTL(self):
         """
         Cache: Cache doesn't decrease TTL with 'don't age' set
@@ -2223,14 +2075,10 @@ class TestCachingDontAge(DNSDistTest):
         """
         ttl = 600
         misses = 0
-        name = 'cachedoesntdecreasettl.cache-dont-age.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cachedoesntdecreasettl.cache-dont-age.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -2263,11 +2111,11 @@ class TestCachingDontAge(DNSDistTest):
 
         self.assertEqual(total, misses)
 
-class TestCachingECSWithoutPoolECS(DNSDistTest):
 
+class TestCachingECSWithoutPoolECS(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
@@ -2285,14 +2133,10 @@ class TestCachingECSWithoutPoolECS(DNSDistTest):
         Cache: Cached entry with ECS is a miss when no backend are available
         """
         ttl = 600
-        name = 'cached.cache-ecs-without-pool-ecs.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cached.cache-ecs-without-pool-ecs.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -2321,11 +2165,11 @@ class TestCachingECSWithoutPoolECS(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, None)
 
-class TestCachingECSWithPoolECS(DNSDistTest):
 
+class TestCachingECSWithPoolECS(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
@@ -2340,14 +2184,10 @@ class TestCachingECSWithPoolECS(DNSDistTest):
         Cache: Cached entry with ECS is a hit when no backend are available
         """
         ttl = 600
-        name = 'cached.cache-ecs-with-pool-ecs.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cached.cache-ecs-with-pool-ecs.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -2376,8 +2216,8 @@ class TestCachingECSWithPoolECS(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, response)
 
-class TestCachingCollisionNoECSParsing(DNSDistTest):
 
+class TestCachingCollisionNoECSParsing(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
@@ -2388,16 +2228,12 @@ class TestCachingCollisionNoECSParsing(DNSDistTest):
         """
         Cache: Collision with no ECS parsing
         """
-        name = 'collision-no-ecs-parsing.cache.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('10.0.226.63', 32)
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "collision-no-ecs-parsing.cache.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("10.0.226.63", 32)
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso], payload=512)
         query.flags = dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query should to fill the cache
@@ -2411,15 +2247,15 @@ class TestCachingCollisionNoECSParsing(DNSDistTest):
         # second query will hash to the same key, triggering a collision which
         # will not be detected because the qname, qtype, qclass and flags will
         # match and EDNS Client Subnet parsing has not been enabled
-        ecso2 = clientsubnetoption.ClientSubnetOption('10.1.60.19', 32)
-        query2 = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso2], payload=512)
+        ecso2 = clientsubnetoption.ClientSubnetOption("10.1.60.19", 32)
+        query2 = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso2], payload=512)
         query2.flags = dns.flags.RD
         (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False)
         receivedResponse.id = response.id
         self.assertEqual(receivedResponse, response)
 
-class TestCachingCollisionWithECSParsing(DNSDistTest):
 
+class TestCachingCollisionWithECSParsing(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=60, staleTTL=60, dontAge=false, numberOfShards=1, deferrableInsertLock=true, maxNegativeTTL=3600, parseECS=true})
     getPool(""):setCache(pc)
@@ -2430,16 +2266,12 @@ class TestCachingCollisionWithECSParsing(DNSDistTest):
         """
         Cache: Collision with ECS parsing
         """
-        name = 'collision-with-ecs-parsing.cache.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('10.0.150.206', 32)
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "collision-with-ecs-parsing.cache.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("10.0.150.206", 32)
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso], payload=512)
         query.flags = dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query should to fill the cache
@@ -2453,27 +2285,23 @@ class TestCachingCollisionWithECSParsing(DNSDistTest):
         # second query will hash to the same key, triggering a collision which
         # _will_ be detected this time because the qname, qtype, qclass and flags will
         # match but EDNS Client Subnet parsing is now enabled and will detect the issue
-        ecso2 = clientsubnetoption.ClientSubnetOption('10.0.212.51', 32)
-        query2 = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso2], payload=512)
+        ecso2 = clientsubnetoption.ClientSubnetOption("10.0.212.51", 32)
+        query2 = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso2], payload=512)
         query2.flags = dns.flags.RD
         response2 = dns.message.make_response(query2)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         response2.answer.append(rrset)
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2)
         self.assertEqual(receivedResponse, response2)
 
-class TestCachingScopeZero(DNSDistTest):
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+class TestCachingScopeZero(DNSDistTest):
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     local backendPort = %d
     -- Be careful to enable ECS parsing in the packet cache, otherwise scope zero is disabled
@@ -2511,28 +2339,24 @@ class TestCachingScopeZero(DNSDistTest):
     -- test the DoH special case (query received over TCP, forwarded over UDP)
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, {library='nghttp2'})
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey"]
 
     def testScopeZero(self):
         """
         Cache: Test the scope-zero feature, backend returns a scope of zero
         """
         ttl = 600
-        name = 'scope-zero.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "scope-zero.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.flags &= ~dns.flags.RD
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
-        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.0", 24)
+        expectedQuery = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso], payload=512)
         expectedQuery.flags &= ~dns.flags.RD
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, 0)
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24, 0)
         expectedResponse = dns.message.make_response(query)
         scopedResponse = dns.message.make_response(query)
         scopedResponse.use_edns(edns=True, payload=4096, options=[ecsoResponse])
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         scopedResponse.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -2549,7 +2373,7 @@ class TestCachingScopeZero(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.checkMessageNoEDNS(receivedResponse, expectedResponse)
 
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.flags &= dns.flags.RD
         # next query FROM A DIFFERENT CLIENT since RD is now set should STILL hit the cache
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -2558,11 +2382,11 @@ class TestCachingScopeZero(DNSDistTest):
             receivedResponse.id = expectedResponse.id
             self.checkMessageNoEDNS(receivedResponse, expectedResponse)
 
-        name = 'scope-zero-with-ecs.cache.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "scope-zero-with-ecs.cache.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso], payload=512)
         query.flags &= ~dns.flags.RD
-        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        expectedQuery = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso], payload=512)
         expectedQuery.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=4096, options=[ecsoResponse])
@@ -2590,22 +2414,18 @@ class TestCachingScopeZero(DNSDistTest):
         Cache: Test the scope-zero feature, backend returns a scope of non-zero
         """
         ttl = 600
-        name = 'scope-not-zero.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "scope-not-zero.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.flags &= ~dns.flags.RD
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
-        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.0", 24)
+        expectedQuery = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso], payload=512)
         expectedQuery.flags &= ~dns.flags.RD
-        ecso2 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        expectedQuery2 = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso2], payload=512)
+        ecso2 = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        expectedQuery2 = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso2], payload=512)
         expectedQuery2.flags &= ~dns.flags.RD
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, 24)
-        ecsoResponse2 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32, 24)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24, 24)
+        ecsoResponse2 = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32, 24)
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
         scopedResponse = dns.message.make_response(query)
@@ -2628,7 +2448,7 @@ class TestCachingScopeZero(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.checkMessageNoEDNS(receivedResponse, expectedResponse)
 
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.flags &= dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
@@ -2645,20 +2465,16 @@ class TestCachingScopeZero(DNSDistTest):
         Cache: Test the scope-zero feature, backend returns no ECS at all
         """
         ttl = 600
-        name = 'scope-zero-no-ecs.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "scope-zero-no-ecs.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.flags &= ~dns.flags.RD
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
-        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.0", 24)
+        expectedQuery = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso], payload=512)
         expectedQuery.flags &= ~dns.flags.RD
-        ecso2 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        expectedQuery2 = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso2], payload=512)
+        ecso2 = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        expectedQuery2 = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso2], payload=512)
         expectedQuery2.flags &= ~dns.flags.RD
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response = dns.message.make_response(query)
         response.answer.append(rrset)
 
@@ -2675,7 +2491,7 @@ class TestCachingScopeZero(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.checkMessageNoEDNS(receivedResponse, response)
 
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.flags &= dns.flags.RD
         response = dns.message.make_response(query)
         response.answer.append(rrset)
@@ -2692,21 +2508,17 @@ class TestCachingScopeZero(DNSDistTest):
         Cache: Test the scope-zero feature with a query received over DoH, backend returns a scope of zero
         """
         ttl = 600
-        name = 'scope-zero-incoming-doh.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "scope-zero-incoming-doh.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.flags &= ~dns.flags.RD
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
-        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=4096)
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.0", 24)
+        expectedQuery = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso], payload=4096)
         expectedQuery.flags &= ~dns.flags.RD
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, 0)
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24, 0)
         expectedResponse = dns.message.make_response(query)
         scopedResponse = dns.message.make_response(query)
         scopedResponse.use_edns(edns=True, payload=4096, options=[ecsoResponse])
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         scopedResponse.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -2719,8 +2531,8 @@ class TestCachingScopeZero(DNSDistTest):
         (receivedQuery, receivedResponse) = self.sendDOHQueryWrapper(query, response=None, useQueue=False)
         self.checkMessageNoEDNS(receivedResponse, expectedResponse)
 
-class TestCachingScopeZeroButNoSubnetcheck(DNSDistTest):
 
+class TestCachingScopeZeroButNoSubnetcheck(DNSDistTest):
     _config_template = """
     -- We disable ECS parsing in the packet cache, meaning scope zero is disabled
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=60, staleTTL=60, dontAge=false, numberOfShards=1, deferrableInsertLock=true, maxNegativeTTL=3600, parseECS=false})
@@ -2738,24 +2550,20 @@ class TestCachingScopeZeroButNoSubnetcheck(DNSDistTest):
         Cache: Test that the scope-zero feature is disabled when ECS parsing is not enabled in the cache
         """
         ttl = 600
-        name = 'scope-zero-no-subnet.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "scope-zero-no-subnet.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.flags &= ~dns.flags.RD
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
-        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.0", 24)
+        expectedQuery = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso], payload=512)
         expectedQuery.flags &= ~dns.flags.RD
-        ecso2 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        expectedQuery2 = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso2], payload=512)
+        ecso2 = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        expectedQuery2 = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso2], payload=512)
         expectedQuery2.flags &= ~dns.flags.RD
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, 0)
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24, 0)
         expectedResponse = dns.message.make_response(query)
         scopedResponse = dns.message.make_response(query)
         scopedResponse.use_edns(edns=True, payload=4096, options=[ecsoResponse])
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         scopedResponse.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -2772,7 +2580,7 @@ class TestCachingScopeZeroButNoSubnetcheck(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.checkMessageNoEDNS(receivedResponse, expectedResponse)
 
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.flags &= dns.flags.RD
         response = dns.message.make_response(query)
         response.answer.append(rrset)
@@ -2784,8 +2592,8 @@ class TestCachingScopeZeroButNoSubnetcheck(DNSDistTest):
             self.checkMessageEDNSWithECS(expectedQuery2, receivedQuery)
             self.checkMessageNoEDNS(receivedResponse, response)
 
-class TestCachingAlteredHeader(DNSDistTest):
 
+class TestCachingAlteredHeader(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100)
     getPool(""):setCache(pc)
@@ -2797,28 +2605,20 @@ class TestCachingAlteredHeader(DNSDistTest):
         """
         Cache: The header has been altered via a rule
         """
-        name = 'cache-set-rd.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "cache-set-rd.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # the query reaching the backend will never have the RD flag set
-        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        expectedQuery = dns.message.make_query(name, "A", "IN")
         expectedQuery.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
         response.flags &= ~dns.flags.RD
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         # first query has RD=1
         query.flags |= dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -2840,11 +2640,7 @@ class TestCachingAlteredHeader(DNSDistTest):
         # same query with RD=0, should hit the cache as well
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -2853,8 +2649,8 @@ class TestCachingAlteredHeader(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestCachingBackendSettingRD(DNSDistTest):
 
+class TestCachingBackendSettingRD(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100)
     getPool(""):setCache(pc)
@@ -2865,27 +2661,19 @@ class TestCachingBackendSettingRD(DNSDistTest):
         """
         Cache: The backend sets RD=1 in the response even if the query had RD=0
         """
-        name = 'backend-sets-rd.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "backend-sets-rd.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
-        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        expectedQuery = dns.message.make_query(name, "A", "IN")
         expectedQuery.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
         response.flags |= dns.flags.RD
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.RD
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -2908,11 +2696,7 @@ class TestCachingBackendSettingRD(DNSDistTest):
         # same query with RD=1, should NOT hit the cache
         query.flags |= dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -2922,14 +2706,24 @@ class TestCachingBackendSettingRD(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(receivedResponse, expectedResponse)
 
+
 class TestAPICache(DNSDistTest):
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
-    _config_params = ['_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _webServerBasicAuthPassword = "secret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
+    _config_params = [
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     webserver("127.0.0.1:%d")
@@ -2944,16 +2738,12 @@ class TestAPICache(DNSDistTest):
         """
         Cache: Clear cache via API
         """
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/cache'
-        name = 'cache-api.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/cache"
+        name = "cache-api.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -2969,52 +2759,68 @@ class TestAPICache(DNSDistTest):
         self.assertEqual(receivedResponse, response)
 
         # GET should on the cache API should yield a 400
-        r = requests.get(url + '?pool=pool-without-cache&name=cache-api.cache.tests.powerdns.com.&type=AAAA', headers=headers, timeout=self._webTimeout)
+        r = requests.get(
+            url + "?pool=pool-without-cache&name=cache-api.cache.tests.powerdns.com.&type=AAAA",
+            headers=headers,
+            timeout=self._webTimeout,
+        )
         self.assertEqual(r.status_code, 400)
 
         # different pool
-        r = requests.delete(url + '?pool=pool-without-cache&name=cache-api.cache.tests.powerdns.com.&type=AAAA', headers=headers, timeout=self._webTimeout)
+        r = requests.delete(
+            url + "?pool=pool-without-cache&name=cache-api.cache.tests.powerdns.com.&type=AAAA",
+            headers=headers,
+            timeout=self._webTimeout,
+        )
         self.assertEqual(r.status_code, 404)
 
         # no 'pool'
-        r = requests.delete(url + '?name=cache-api.cache.tests.powerdns.com.&type=AAAA', headers=headers, timeout=self._webTimeout)
+        r = requests.delete(
+            url + "?name=cache-api.cache.tests.powerdns.com.&type=AAAA", headers=headers, timeout=self._webTimeout
+        )
         self.assertEqual(r.status_code, 400)
 
         # no 'name'
-        r = requests.delete(url + '?pool=pool-without-cache&type=AAAA', headers=headers, timeout=self._webTimeout)
+        r = requests.delete(url + "?pool=pool-without-cache&type=AAAA", headers=headers, timeout=self._webTimeout)
         self.assertEqual(r.status_code, 400)
 
         # invalid name (label is too long)
-        r = requests.delete(url + '?pool=&name=' + 'a'*65, headers=headers, timeout=self._webTimeout)
+        r = requests.delete(url + "?pool=&name=" + "a" * 65, headers=headers, timeout=self._webTimeout)
         self.assertEqual(r.status_code, 400)
 
         # different name
-        r = requests.delete(url + '?pool=&name=not-cache-api.cache.tests.powerdns.com.', headers=headers, timeout=self._webTimeout)
+        r = requests.delete(
+            url + "?pool=&name=not-cache-api.cache.tests.powerdns.com.", headers=headers, timeout=self._webTimeout
+        )
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         content = r.json()
-        self.assertIn('count', content)
-        self.assertEqual(int(content['count']), 0)
+        self.assertIn("count", content)
+        self.assertEqual(int(content["count"]), 0)
 
         # different type
-        r = requests.delete(url + '?pool=&name=cache-api.cache.tests.powerdns.com.&type=A', headers=headers, timeout=self._webTimeout)
+        r = requests.delete(
+            url + "?pool=&name=cache-api.cache.tests.powerdns.com.&type=A", headers=headers, timeout=self._webTimeout
+        )
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         content = r.json()
-        self.assertIn('count', content)
-        self.assertEqual(int(content['count']), 0)
+        self.assertIn("count", content)
+        self.assertEqual(int(content["count"]), 0)
 
         # should still be a hit
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, response)
 
         # remove
-        r = requests.delete(url + '?pool=&name=cache-api.cache.tests.powerdns.com.&type=AAAA', headers=headers, timeout=self._webTimeout)
+        r = requests.delete(
+            url + "?pool=&name=cache-api.cache.tests.powerdns.com.&type=AAAA", headers=headers, timeout=self._webTimeout
+        )
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         content = r.json()
-        self.assertIn('count', content)
-        self.assertEqual(int(content['count']), 1)
+        self.assertIn("count", content)
+        self.assertEqual(int(content["count"]), 1)
 
         # should be a miss
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -3025,12 +2831,14 @@ class TestAPICache(DNSDistTest):
         self.assertEqual(receivedResponse, response)
 
         # remove all types
-        r = requests.delete(url + '?pool=&name=cache-api.cache.tests.powerdns.com.', headers=headers, timeout=self._webTimeout)
+        r = requests.delete(
+            url + "?pool=&name=cache-api.cache.tests.powerdns.com.", headers=headers, timeout=self._webTimeout
+        )
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         content = r.json()
-        self.assertIn('count', content)
-        self.assertEqual(int(content['count']), 1)
+        self.assertIn("count", content)
+        self.assertEqual(int(content["count"]), 1)
 
         # should be a miss
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -3041,12 +2849,14 @@ class TestAPICache(DNSDistTest):
         self.assertEqual(receivedResponse, response)
 
         # suffix removal
-        r = requests.delete(url + '?pool=&name=cache.tests.powerdns.com.&suffix=true', headers=headers, timeout=self._webTimeout)
+        r = requests.delete(
+            url + "?pool=&name=cache.tests.powerdns.com.&suffix=true", headers=headers, timeout=self._webTimeout
+        )
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         content = r.json()
-        self.assertIn('count', content)
-        self.assertEqual(int(content['count']), 1)
+        self.assertIn("count", content)
+        self.assertEqual(int(content["count"]), 1)
 
         # should be a miss
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -3056,8 +2866,8 @@ class TestAPICache(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-class TestCachingOfVeryLargeAnswers(DNSDistTest):
 
+class TestCachingOfVeryLargeAnswers(DNSDistTest):
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1, maximumEntrySize=8192})
     getPool(""):setCache(pc)
@@ -3071,23 +2881,19 @@ class TestCachingOfVeryLargeAnswers(DNSDistTest):
         We should be able to get answers as large as 8192 bytes this time
         """
         numberOfQueries = 10
-        name = 'very-large-answer.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        name = "very-large-answer.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "TXT", "IN")
         response = dns.message.make_response(query)
         # we prepare a large answer
-        content = ''
+        content = ""
         for i in range(31):
             if len(content) > 0:
-                content = content + ' '
-            content = content + 'A' * 255
+                content = content + " "
+            content = content + "A" * 255
         # pad up to 8192
-        content = content + ' ' + 'B' * 183
+        content = content + " " + "B" * 183
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    content)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, content)
         response.answer.append(rrset)
         self.assertEqual(len(response.to_wire()), 8192)
 
@@ -3118,22 +2924,22 @@ class TestCachingOfVeryLargeAnswers(DNSDistTest):
         receivedQuery.id = query.id
         self.assertEqual(query, receivedQuery)
 
-class TestCacheEmptyTC(DNSDistTest):
 
+class TestCacheEmptyTC(DNSDistTest):
     _truncated_ttl = 42
     _config_template = """
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1, truncatedTTL=%d})
     getPool(""):setCache(pc)
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_truncated_ttl', '_testServerPort']
+    _config_params = ["_truncated_ttl", "_testServerPort"]
 
     def testEmptyTruncated(self):
         """
         Cache: Empty TC=1 should be cached
         """
-        name = 'cache-empty-tc.cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "cache-empty-tc.cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
         response.flags |= dns.flags.TC
 
@@ -3153,15 +2959,17 @@ class TestCacheEmptyTC(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, response)
 
-class TestCachingPayloadRanks(DNSDistTest):
 
+class TestCachingPayloadRanks(DNSDistTest):
     _verboseMode = True
     _testServerPort = pickAvailablePort()
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
-    _config_params = ['_webServerPort', '_webServerAPIKeyHashed', '_testServerPort']
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
+    _config_params = ["_webServerPort", "_webServerAPIKeyHashed", "_testServerPort"]
     _config_template = """
     webserver("127.0.0.1:%d")
     setWebserverConfig({apiKey="%s"})
@@ -3171,15 +2979,15 @@ class TestCachingPayloadRanks(DNSDistTest):
     """
 
     def getPoolMetric(self, poolID, metricName):
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        self.assertIn('pools', content)
-        pools = content['pools']
+        self.assertIn("pools", content)
+        pools = content["pools"]
         self.assertGreater(len(pools), poolID)
         pool = pools[poolID]
         return int(pool[metricName])
@@ -3190,22 +2998,18 @@ class TestCachingPayloadRanks(DNSDistTest):
 
         """
         # testing with and without EDNS0 payload size
-        name1 = 'cached.cache.tests.powerdns.com.'
-        query1 = dns.message.make_query(name1, 'AAAA', 'IN', payload=512)
-        query1_1 = dns.message.make_query(name1, 'AAAA', 'IN', payload=600)
+        name1 = "cached.cache.tests.powerdns.com."
+        query1 = dns.message.make_query(name1, "AAAA", "IN", payload=512)
+        query1_1 = dns.message.make_query(name1, "AAAA", "IN", payload=600)
         response1 = dns.message.make_response(query1)
-        rrset1 = dns.rrset.from_text(name1,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset1 = dns.rrset.from_text(name1, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response1.answer.append(rrset1)
 
         # first query to fill the cache
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query1, response1)
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
-        self.assertEqual(self.getPoolMetric(0, 'cacheHits'), 0)
+        self.assertEqual(self.getPoolMetric(0, "cacheHits"), 0)
         receivedQuery.id = query1.id
         self.assertEqual(query1, receivedQuery)
         self.assertEqual(receivedResponse, response1)
@@ -3213,37 +3017,33 @@ class TestCachingPayloadRanks(DNSDistTest):
         # same query shall hit cache
         (_, receivedResponse) = self.sendUDPQuery(query1, response=None, useQueue=False)
         self.assertTrue(receivedResponse)
-        self.assertEqual(self.getPoolMetric(0, 'cacheHits'), 1)
+        self.assertEqual(self.getPoolMetric(0, "cacheHits"), 1)
         self.assertEqual(receivedResponse, response1)
 
         # query1_1 shall also hit cache since 600 round down to 512
         (_, receivedResponse) = self.sendUDPQuery(query1_1, response=None, useQueue=False)
         self.assertTrue(receivedResponse)
-        self.assertEqual(self.getPoolMetric(0, 'cacheHits'), 2)
+        self.assertEqual(self.getPoolMetric(0, "cacheHits"), 2)
         self.assertEqual(len(receivedResponse.answer), 1)
         self.assertEqual(receivedResponse.answer[0], rrset1)
 
         # testing for large sized cache entry
-        name2 = 'bigcached.cache.tests.powerdns.com.'
-        query2 = dns.message.make_query(name2, 'AAAA', 'IN', payload=1279)
-        query2_1 = dns.message.make_query(name2, 'AAAA', 'IN', payload=1200)
-        query2_2 = dns.message.make_query(name2, 'AAAA', 'IN', payload=1024)
+        name2 = "bigcached.cache.tests.powerdns.com."
+        query2 = dns.message.make_query(name2, "AAAA", "IN", payload=1279)
+        query2_1 = dns.message.make_query(name2, "AAAA", "IN", payload=1200)
+        query2_2 = dns.message.make_query(name2, "AAAA", "IN", payload=1024)
 
         response2 = dns.message.make_response(query2)
         v6addr_list = []
-        for i in range(1,41):
-            v6addr_list.append(f'fe80:fe80:fe80:fe80::{i}')
-        rrset2 = dns.rrset.from_text_list(name2,
-                                          3600,
-                                          dns.rdataclass.IN,
-                                          dns.rdatatype.AAAA,
-                                          v6addr_list)
-        response2.answer.append(rrset2) # response > 40x(16+10)=1040 bytes
+        for i in range(1, 41):
+            v6addr_list.append(f"fe80:fe80:fe80:fe80::{i}")
+        rrset2 = dns.rrset.from_text_list(name2, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, v6addr_list)
+        response2.answer.append(rrset2)  # response > 40x(16+10)=1040 bytes
 
         # first query to fill the cache
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2)
         self.assertTrue(receivedQuery)
-        self.assertEqual(self.getPoolMetric(0, 'cacheHits'), 2)
+        self.assertEqual(self.getPoolMetric(0, "cacheHits"), 2)
         self.assertTrue(receivedResponse)
         receivedQuery.id = query2.id
         self.assertEqual(query2, receivedQuery)
@@ -3252,19 +3052,19 @@ class TestCachingPayloadRanks(DNSDistTest):
         # same query shall hit cache
         (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False)
         self.assertTrue(receivedResponse)
-        self.assertEqual(self.getPoolMetric(0, 'cacheHits'), 3)
+        self.assertEqual(self.getPoolMetric(0, "cacheHits"), 3)
         self.assertEqual(receivedResponse, response2)
 
         # query2_1 shall hit cache
         (_, receivedResponse) = self.sendUDPQuery(query2_1, response=None, useQueue=False)
         self.assertTrue(receivedResponse)
-        self.assertEqual(self.getPoolMetric(0, 'cacheHits'), 4)
+        self.assertEqual(self.getPoolMetric(0, "cacheHits"), 4)
         self.assertEqual(len(receivedResponse.answer), 1)
         self.assertEqual(receivedResponse.answer[0], rrset2)
 
         # query2_2 shall hit cache but truncated since payload size is not enough
         (_, receivedResponse) = self.sendUDPQuery(query2_2, response=None, useQueue=False)
         self.assertTrue(receivedResponse)
-        self.assertEqual(self.getPoolMetric(0, 'cacheHits'), 5)
+        self.assertEqual(self.getPoolMetric(0, "cacheHits"), 5)
         self.assertEqual(len(receivedResponse.answer), 0)
         self.assertEqual(receivedResponse.flags & dns.flags.TC, dns.flags.TC)
index cb516cf933989f30ed796284cb1dc1b13b58ed63..9490bb2c23b0ce5d7324a2e14fcf876dab96abcc 100644 (file)
@@ -5,8 +5,8 @@ import sys
 import time
 from dnsdisttests import DNSDistTest, Queue, pickAvailablePort
 
-class TestCarbon(DNSDistTest):
 
+class TestCarbon(DNSDistTest):
     _carbonServer1Port = pickAvailablePort()
     _carbonServer1Name = "carbonname1"
     _carbonServer2Port = pickAvailablePort()
@@ -15,8 +15,14 @@ class TestCarbon(DNSDistTest):
     _carbonQueue2 = Queue()
     _carbonInterval = 2
     _carbonCounters = {}
-    _config_params = ['_carbonServer1Port', '_carbonServer1Name', '_carbonInterval',
-                      '_carbonServer2Port', '_carbonServer2Name', '_carbonInterval']
+    _config_params = [
+        "_carbonServer1Port",
+        "_carbonServer1Name",
+        "_carbonInterval",
+        "_carbonServer2Port",
+        "_carbonServer2Name",
+        "_carbonInterval",
+    ]
     _config_template = """
     s = newServer{address="127.0.0.1:5353"}
     s:setDown()
@@ -42,7 +48,7 @@ class TestCarbon(DNSDistTest):
         while True:
             (conn, _) = sock.accept()
             conn.settimeout(2.0)
-            lines = b''
+            lines = b""
             while True:
                 data = conn.recv(4096)
                 if not data:
@@ -62,11 +68,15 @@ class TestCarbon(DNSDistTest):
 
     @classmethod
     def startResponders(cls):
-        cls._CarbonResponder1 = threading.Thread(name='Carbon Responder 1', target=cls.CarbonResponder, args=[cls._carbonServer1Port])
+        cls._CarbonResponder1 = threading.Thread(
+            name="Carbon Responder 1", target=cls.CarbonResponder, args=[cls._carbonServer1Port]
+        )
         cls._CarbonResponder1.daemon = True
         cls._CarbonResponder1.start()
 
-        cls._CarbonResponder2 = threading.Thread(name='Carbon Responder 2', target=cls.CarbonResponder, args=[cls._carbonServer2Port])
+        cls._CarbonResponder2 = threading.Thread(
+            name="Carbon Responder 2", target=cls.CarbonResponder, args=[cls._carbonServer2Port]
+        )
         cls._CarbonResponder2.daemon = True
         cls._CarbonResponder2.start()
 
@@ -95,10 +105,10 @@ class TestCarbon(DNSDistTest):
 
         self.assertTrue(data1)
         self.assertGreater(len(data1.splitlines()), 1)
-        expectedStart = b"dnsdist.%s.main." % self._carbonServer1Name.encode('UTF-8')
+        expectedStart = b"dnsdist.%s.main." % self._carbonServer1Name.encode("UTF-8")
         for line in data1.splitlines():
             self.assertTrue(line.startswith(expectedStart))
-            parts = line.split(b' ')
+            parts = line.split(b" ")
             self.assertEqual(len(parts), 3)
             self.assertTrue(self.isfloat(parts[1]))
             self.assertTrue(parts[2].isdigit())
@@ -106,10 +116,10 @@ class TestCarbon(DNSDistTest):
 
         self.assertTrue(data2)
         self.assertGreater(len(data2.splitlines()), 1)
-        expectedStart = b"dnsdist.%s.main." % self._carbonServer2Name.encode('UTF-8')
+        expectedStart = b"dnsdist.%s.main." % self._carbonServer2Name.encode("UTF-8")
         for line in data2.splitlines():
             self.assertTrue(line.startswith(expectedStart))
-            parts = line.split(b' ')
+            parts = line.split(b" ")
             self.assertEqual(len(parts), 3)
             self.assertTrue(self.isfloat(parts[1]))
             self.assertTrue(parts[2].isdigit())
@@ -141,11 +151,11 @@ class TestCarbon(DNSDistTest):
         # configured in the class definition
         self.assertTrue(data1)
         self.assertGreater(len(data1.splitlines()), 1)
-        expectedStart = b"dnsdist.%s.main.pools._default_.servers" % self._carbonServer1Name.encode('UTF-8')
+        expectedStart = b"dnsdist.%s.main.pools._default_.servers" % self._carbonServer1Name.encode("UTF-8")
         for line in data1.splitlines():
             if expectedStart in line:
-                parts = line.split(b' ')
-                if b'servers-up' in line:
+                parts = line.split(b" ")
+                if b"servers-up" in line:
                     self.assertEqual(len(parts), 3)
                     self.assertTrue(parts[1].isdigit())
                     self.assertEqual(int(parts[1]), 2)
@@ -164,11 +174,11 @@ class TestCarbon(DNSDistTest):
         # the first carbon server
         self.assertTrue(data2)
         self.assertGreater(len(data2.splitlines()), 1)
-        expectedStart = b"dnsdist.%s.main.pools._default_.servers" % self._carbonServer2Name.encode('UTF-8')
+        expectedStart = b"dnsdist.%s.main.pools._default_.servers" % self._carbonServer2Name.encode("UTF-8")
         for line in data2.splitlines():
             if expectedStart in line:
-                parts = line.split(b' ')
-                if b'servers-up' in line:
+                parts = line.split(b" ")
+                if b"servers-up" in line:
                     self.assertEqual(len(parts), 3)
                     self.assertTrue(parts[1].isdigit())
                     self.assertEqual(int(parts[1]), 2)
index 20dd93c0e77b4683c2bbe55e6762e0071881d919..eeb62ae8c9ba3ee3a18e9238028c3c94a3b5df08 100644 (file)
@@ -4,17 +4,17 @@ import os
 import subprocess
 import time
 
-class TestCheckConfig(unittest.TestCase):
 
+class TestCheckConfig(unittest.TestCase):
     def tryDNSDist(self, configTemplate, shouldBeSuccessful=True, delay=1):
-        conffile = 'dnsdist_test.conf'
-        with open(conffile, 'w') as conf:
+        conffile = "dnsdist_test.conf"
+        with open(conffile, "w") as conf:
             conf.write("-- Autogenerated by dnsdisttests.py\n")
             conf.write(configTemplate)
 
-        dnsdistcmd = [os.environ['DNSDISTBIN'], '-C', conffile, '--check-config']
+        dnsdistcmd = [os.environ["DNSDISTBIN"], "-C", conffile, "--check-config"]
 
-        with open(os.devnull, 'w') as fdDevNull:
+        with open(os.devnull, "w") as fdDevNull:
             dnsdist = subprocess.Popen(dnsdistcmd, close_fds=True, stdout=fdDevNull)
 
         if dnsdist.poll() is None:
index 56c6ccb03801e24929edd1aed69c62adcd638870..e40726afbac1718d9d41ee1a8aba73c597f32d18 100644 (file)
@@ -5,6 +5,7 @@ import time
 from dnsdisttests import DNSDistTest, pickAvailablePort
 import extendederrors
 
+
 class TestConfigurationUpdates(DNSDistTest):
     _yaml_config_template = """---
 logging:
@@ -73,43 +74,59 @@ query_rules:
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
     _doqServerPort = pickAvailablePort()
     _doh3ServerPort = pickAvailablePort()
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _dohWithNGHTTP2BaseURL = ("https://%s:%d/" % (_serverName, _dohWithNGHTTP2ServerPort))
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _dohWithNGHTTP2BaseURL = "https://%s:%d/" % (_serverName, _dohWithNGHTTP2ServerPort)
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doh3ServerPort)
+    _caCert = "ca.pem"
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _consolePort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_consolePort', '_consoleKeyB64', '_dnsDistPort', '_tlsServerPort', '_serverCert', '_serverKey', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey', '_doqServerPort','_serverCert', '_serverKey', '_doh3ServerPort', '_serverCert', '_serverKey', '_testServerPort', '_testServerPort']
+    _yaml_config_params = [
+        "_consolePort",
+        "_consoleKeyB64",
+        "_dnsDistPort",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_dohWithNGHTTP2ServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doh3ServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_testServerPort",
+        "_testServerPort",
+    ]
     _config_params = []
-    _checkConfigExpectedOutput = b"DNS over HTTPS configured\nConfiguration 'configs/dnsdist_TestConfigurationUpdates.yml' OK!\n"
+    _checkConfigExpectedOutput = (
+        b"DNS over HTTPS configured\nConfiguration 'configs/dnsdist_TestConfigurationUpdates.yml' OK!\n"
+    )
 
     def testRegular(self):
         """
         Configuration updates: regular
         """
-        for protocol in ['UDP', 'TCP', 'DOT', 'DOH', 'DOQ', 'DOH3']:
-            name = f'regular-{protocol}.config-updates.test.powerdns.com.'
-            query = dns.message.make_query(name, 'A', 'IN')
+        for protocol in ["UDP", "TCP", "DOT", "DOH", "DOQ", "DOH3"]:
+            name = f"regular-{protocol}.config-updates.test.powerdns.com."
+            query = dns.message.make_query(name, "A", "IN")
             query.flags &= ~dns.flags.RD
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(name,
-                                        60,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.A,
-                                       '127.0.0.1')
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
             response.answer.append(rrset)
 
-            method = f'send{protocol}Query'
-            if not protocol in ['UDP', 'TCP']:
-                if protocol == 'DOH':
-                    method = 'sendDOHWithNGHTTP2QueryWrapper'
+            method = f"send{protocol}Query"
+            if not protocol in ["UDP", "TCP"]:
+                if protocol == "DOH":
+                    method = "sendDOHWithNGHTTP2QueryWrapper"
                 else:
-                    method += 'Wrapper'
+                    method += "Wrapper"
             sender = getattr(self, method)
 
             (receivedQuery, receivedResponse) = sender(query, response=response)
@@ -129,20 +146,16 @@ query_rules:
         """
         Configuration updates: response
         """
-        for protocol in ['UDP', 'TCP']:
-            name = f'{protocol}-response.config-updates.test.powerdns.com.'
-            query = dns.message.make_query(name, 'A', 'IN')
+        for protocol in ["UDP", "TCP"]:
+            name = f"{protocol}-response.config-updates.test.powerdns.com."
+            query = dns.message.make_query(name, "A", "IN")
             query.flags &= ~dns.flags.RD
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(name,
-                                        60,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.A,
-                                       '127.0.0.1')
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
             response.answer.append(rrset)
 
-            method = f'send{protocol}Query'
+            method = f"send{protocol}Query"
             sender = getattr(self, method)
 
             (receivedQuery, receivedResponse) = sender(query, response=response)
@@ -151,17 +164,18 @@ query_rules:
             self.assertEqual(receivedResponse, response)
 
             self.sendConsoleCommand(f'addResponseAction(QNameRule("{name}"), SetExtendedDNSErrorResponseAction(15))')
-            if protocol == 'TCP':
+            if protocol == "TCP":
                 time.sleep(1)
 
             # the configuration should have been updated
             expectedResponse = dns.message.make_response(query)
-            ede = extendederrors.ExtendedErrorOption(15, b'')
+            ede = extendederrors.ExtendedErrorOption(15, b"")
             expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
             expectedResponse.answer.append(rrset)
             (_, receivedResponse) = sender(query, response=response)
             self.assertEqual(receivedResponse, expectedResponse)
 
+
 class TestConfigurationUpdatesRecvMMSG(DNSDistTest):
     _yaml_config_template = """---
 console:
@@ -184,25 +198,21 @@ tuning:
 """
     _dnsDistPort = pickAvailablePort()
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _consolePort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_consolePort', '_consoleKeyB64', '_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_consolePort", "_consoleKeyB64", "_dnsDistPort", "_testServerPort"]
     _config_params = []
 
     def testRecvMMSGUDP(self):
         """
         Configuration updates: recvmmsg UDP
         """
-        name = 'recvmmsg-udp.config-updates.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "recvmmsg-udp.config-updates.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
@@ -223,15 +233,11 @@ tuning:
         """
         Configuration updates: UDP response
         """
-        name = 'recvmmsg-udp-response.config-updates.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "recvmmsg-udp-response.config-updates.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
@@ -244,7 +250,7 @@ tuning:
 
         # the configuration should have been updated
         expectedResponse = dns.message.make_response(query)
-        ede = extendederrors.ExtendedErrorOption(15, b'')
+        ede = extendederrors.ExtendedErrorOption(15, b"")
         expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
         expectedResponse.answer.append(rrset)
         (_, receivedResponse) = self.sendUDPQuery(query, response=response)
index 2e1ce067e11b8e98255abd5524823de6d51af75e..8b7daaca9b9e20833ed40a9d62f8766d724bbd33 100644 (file)
@@ -8,12 +8,12 @@ import subprocess
 import time
 from dnsdisttests import DNSDistTest
 
-class TestConsoleAllowed(DNSDistTest):
 
+class TestConsoleAllowed(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -24,15 +24,15 @@ class TestConsoleAllowed(DNSDistTest):
         """
         Console: Allowed
         """
-        version = self.sendConsoleCommand('showVersion()')
-        self.assertTrue(version.startswith('dnsdist '))
+        version = self.sendConsoleCommand("showVersion()")
+        self.assertTrue(version.startswith("dnsdist "))
 
-class TestConsoleAllowedV6(DNSDistTest):
 
+class TestConsoleAllowedV6(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     setKey("%s")
     controlSocket("[::1]:%d")
@@ -43,17 +43,17 @@ class TestConsoleAllowedV6(DNSDistTest):
         """
         Console: Allowed IPv6
         """
-        if 'SKIP_IPV6_TESTS' in os.environ:
-            raise unittest.SkipTest('IPv6 tests are disabled')
-        version = self.sendConsoleCommand('showVersion()', IPv6=True)
-        self.assertTrue(version.startswith('dnsdist '))
+        if "SKIP_IPV6_TESTS" in os.environ:
+            raise unittest.SkipTest("IPv6 tests are disabled")
+        version = self.sendConsoleCommand("showVersion()", IPv6=True)
+        self.assertTrue(version.startswith("dnsdist "))
 
-class TestConsoleNotAllowed(DNSDistTest):
 
+class TestConsoleNotAllowed(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -65,14 +65,14 @@ class TestConsoleNotAllowed(DNSDistTest):
         """
         Console: Not allowed by the ACL
         """
-        self.assertRaises(socket.error, self.sendConsoleCommand, 'showVersion()')
+        self.assertRaises(socket.error, self.sendConsoleCommand, "showVersion()")
 
-class TestConsoleNoKey(DNSDistTest):
 
+class TestConsoleNoKey(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _config_params = ['_consolePort', '_testServerPort']
+    _config_params = ["_consolePort", "_testServerPort"]
     _config_template = """
     controlSocket("127.0.0.1:%d")
     newServer{address="127.0.0.1:%d"}
@@ -82,15 +82,15 @@ class TestConsoleNoKey(DNSDistTest):
         """
         Console: No key, the connection should not be allowed
         """
-        self.assertRaises(socket.error, self.sendConsoleCommand, 'showVersion()')
+        self.assertRaises(socket.error, self.sendConsoleCommand, "showVersion()")
 
-class TestConsoleConcurrentConnections(DNSDistTest):
 
+class TestConsoleConcurrentConnections(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _maxConns = 2
 
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_maxConns']
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort", "_maxConns"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -110,7 +110,7 @@ class TestConsoleConcurrentConnections(DNSDistTest):
             conns.append(conn)
 
         # we now hold all the slots, let's try to establish a new connection
-        self.assertRaises(socket.error, self.sendConsoleCommand, 'showVersion()')
+        self.assertRaises(socket.error, self.sendConsoleCommand, "showVersion()")
 
         # free one slot
         conns[0].close()
@@ -118,25 +118,26 @@ class TestConsoleConcurrentConnections(DNSDistTest):
         time.sleep(1)
 
         # this should work
-        version = self.sendConsoleCommand('showVersion()')
-        self.assertTrue(version.startswith('dnsdist '))
+        version = self.sendConsoleCommand("showVersion()")
+        self.assertTrue(version.startswith("dnsdist "))
+
 
 def writeCDB(fname, variant=1):
-    cdb = cdbx.CDB.make(fname+'.tmp')
-    cdb.add(socket.inet_aton(f'127.0.0.{variant}'), b'this is the value of the source address tag')
-    cdb.add(b'\x05qname\x03cdb\x05tests\x08powerdns\x03com\x00', b'this is the value of the qname tag')
-    cdb.add(b'\x06suffix\x03cdb\x05tests\x08powerdns\x03com\x00', b'this is the value of the suffix tag')
-    cdb.add(b'this is the value of the qname tag', b'this is the value of the second tag')
+    cdb = cdbx.CDB.make(fname + ".tmp")
+    cdb.add(socket.inet_aton(f"127.0.0.{variant}"), b"this is the value of the source address tag")
+    cdb.add(b"\x05qname\x03cdb\x05tests\x08powerdns\x03com\x00", b"this is the value of the qname tag")
+    cdb.add(b"\x06suffix\x03cdb\x05tests\x08powerdns\x03com\x00", b"this is the value of the suffix tag")
+    cdb.add(b"this is the value of the qname tag", b"this is the value of the second tag")
     cdb.commit().close()
-    os.rename(fname+'.tmp', fname)
+    os.rename(fname + ".tmp", fname)
     cdb.close()
 
-class TestConsoleAccessObjectsFromYAML(DNSDistTest):
 
+class TestConsoleAccessObjectsFromYAML(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _cdbFileName = '/tmp/test-cdb-db'
+    _cdbFileName = "/tmp/test-cdb-db"
 
     _yaml_config_template = """
 console:
@@ -150,7 +151,7 @@ key_value_stores:
       file_name: "%s"
       refresh_delay: 1
 """
-    _yaml_config_params = ['_consoleKeyB64', '_consolePort', '_cdbFileName']
+    _yaml_config_params = ["_consoleKeyB64", "_consolePort", "_cdbFileName"]
     _config_params = []
 
     @classmethod
@@ -170,16 +171,22 @@ key_value_stores:
         Console: Check that we can access Yaml-defined objects
         """
         cdb = self.sendConsoleCommand("getObjectFromYAMLConfiguration('cdb-kvs')")
-        self.assertTrue(cdb.startswith('Command returned an object we can\'t print: Trying to cast a lua variable from "userdata" to'))
-        got = self.sendConsoleCommand("if getObjectFromYAMLConfiguration('cdb-kvs'):reload() then return 'reloading worked' else return 'reloading failed' end")
-        self.assertEqual(got, 'reloading worked\n')
+        self.assertTrue(
+            cdb.startswith(
+                'Command returned an object we can\'t print: Trying to cast a lua variable from "userdata" to'
+            )
+        )
+        got = self.sendConsoleCommand(
+            "if getObjectFromYAMLConfiguration('cdb-kvs'):reload() then return 'reloading worked' else return 'reloading failed' end"
+        )
+        self.assertEqual(got, "reloading worked\n")
 
-class TestConsoleRings(DNSDistTest):
 
+class TestConsoleRings(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -191,17 +198,13 @@ class TestConsoleRings(DNSDistTest):
         Console: Ring entries
         """
         # check that the ring is empty first
-        numberOfEntries = self.sendConsoleCommand('#getRingEntries()')
+        numberOfEntries = self.sendConsoleCommand("#getRingEntries()")
         self.assertEqual(int(numberOfEntries), 0)
 
-        name = 'a.console-ring.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "a.console-ring.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -214,43 +217,43 @@ class TestConsoleRings(DNSDistTest):
             self.assertEqual(response, receivedResponse)
 
         # we should now have 4 entries in the ring
-        numberOfEntries = self.sendConsoleCommand('#getRingEntries()')
+        numberOfEntries = self.sendConsoleCommand("#getRingEntries()")
         self.assertEqual(int(numberOfEntries), 4)
 
         # check the first query
         index = 1
-        qname = self.sendConsoleCommand(f'getRingEntries()[{index}].qname:toString()').rstrip()
+        qname = self.sendConsoleCommand(f"getRingEntries()[{index}].qname:toString()").rstrip()
         self.assertEqual(qname, name)
-        qtype = self.sendConsoleCommand(f'getRingEntries()[{index}].qtype').rstrip()
+        qtype = self.sendConsoleCommand(f"getRingEntries()[{index}].qtype").rstrip()
         self.assertEqual(int(qtype), 1)
-        protocol = self.sendConsoleCommand(f'getRingEntries()[{index}].protocol').rstrip()
+        protocol = self.sendConsoleCommand(f"getRingEntries()[{index}].protocol").rstrip()
         self.assertEqual(protocol, "DoUDP")
-        requestor = self.sendConsoleCommand(f'getRingEntries()[{index}].requestor:toString()').rstrip()
+        requestor = self.sendConsoleCommand(f"getRingEntries()[{index}].requestor:toString()").rstrip()
         self.assertEqual(requestor, "127.0.0.1")
-        isResponse = self.sendConsoleCommand(f'tostring(getRingEntries()[{index}].isResponse)').rstrip()
+        isResponse = self.sendConsoleCommand(f"tostring(getRingEntries()[{index}].isResponse)").rstrip()
         self.assertEqual(isResponse, "false")
 
         # check the first response
         index = 2
-        qname = self.sendConsoleCommand(f'getRingEntries()[{index}].qname:toString()').rstrip()
+        qname = self.sendConsoleCommand(f"getRingEntries()[{index}].qname:toString()").rstrip()
         self.assertEqual(qname, name)
-        qtype = self.sendConsoleCommand(f'getRingEntries()[{index}].qtype').rstrip()
+        qtype = self.sendConsoleCommand(f"getRingEntries()[{index}].qtype").rstrip()
         self.assertEqual(int(qtype), 1)
-        protocol = self.sendConsoleCommand(f'getRingEntries()[{index}].protocol').rstrip()
+        protocol = self.sendConsoleCommand(f"getRingEntries()[{index}].protocol").rstrip()
         self.assertEqual(protocol, "DoUDP")
-        requestor = self.sendConsoleCommand(f'getRingEntries()[{index}].requestor:toString()').rstrip()
+        requestor = self.sendConsoleCommand(f"getRingEntries()[{index}].requestor:toString()").rstrip()
         self.assertEqual(requestor, "127.0.0.1")
-        backend = self.sendConsoleCommand(f'getRingEntries()[{index}].backend:toStringWithPort()').rstrip()
+        backend = self.sendConsoleCommand(f"getRingEntries()[{index}].backend:toStringWithPort()").rstrip()
         self.assertEqual(backend, f"127.0.0.1:{self._testServerPort}")
-        isResponse = self.sendConsoleCommand(f'tostring(getRingEntries()[{index}].isResponse)').rstrip()
+        isResponse = self.sendConsoleCommand(f"tostring(getRingEntries()[{index}].isResponse)").rstrip()
         self.assertEqual(isResponse, "true")
 
-class TestConsoleViaBuiltInClient(DNSDistTest):
 
+class TestConsoleViaBuiltInClient(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -263,14 +266,16 @@ class TestConsoleViaBuiltInClient(DNSDistTest):
         """
         output = None
         try:
-            confFile = os.path.join('configs', 'dnsdist_%s.conf' % (self.__class__.__name__))
-            testcmd = [os.environ['DNSDISTBIN'], '--client', '-C', confFile ]
-            process = subprocess.Popen(testcmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
-            output = process.communicate(input=b'showVersion()\n')
+            confFile = os.path.join("configs", "dnsdist_%s.conf" % (self.__class__.__name__))
+            testcmd = [os.environ["DNSDISTBIN"], "--client", "-C", confFile]
+            process = subprocess.Popen(
+                testcmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True
+            )
+            output = process.communicate(input=b"showVersion()\n")
         except subprocess.CalledProcessError as exc:
-            raise AssertionError('%s failed (%d): %s' % (testcmd, process.returncode, process.output))
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, process.output))
 
         if process.returncode != 0:
-          raise AssertionError('%s failed (%d): %s' % (testcmd, process.returncode, output))
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, output))
 
-        self.assertTrue(output[0].startswith(b'dnsdist '))
+        self.assertTrue(output[0].startswith(b"dnsdist "))
index 7286527524159d95d18af6c1a425bae8e2da7079..be55ae8977f8720a421dc74a5dd14c093d533e74 100644 (file)
@@ -7,6 +7,7 @@ import dns.message
 from dnsdisttests import DNSDistTest, pickAvailablePort
 import dnscrypt
 
+
 class DNSCryptTest(DNSDistTest):
     """
     dnsdist is configured to accept DNSCrypt queries on 127.0.0.1:_dnsDistPortDNSCrypt.
@@ -18,9 +19,9 @@ class DNSCryptTest(DNSDistTest):
     _dnsDistPortDNSCrypt = pickAvailablePort()
 
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _providerFingerprint = 'E1D7:2108:9A59:BF8D:F101:16FA:ED5E:EA6A:9F6C:C78F:7F91:AF6B:027E:62F4:69C3:B1AA'
+    _providerFingerprint = "E1D7:2108:9A59:BF8D:F101:16FA:ED5E:EA6A:9F6C:C78F:7F91:AF6B:027E:62F4:69C3:B1AA"
     _providerName = "2.provider.name"
     _resolverCertificateSerial = 42
 
@@ -69,21 +70,28 @@ class TestDNSCrypt(DNSCryptTest):
     addAction("tcp.protocols.dnscrypt.tests.powerdns.com.", LuaAction(checkDNSCryptTCP))
     """
 
-    _config_params = ['_consoleKeyB64', '_consolePort', '_resolverCertificateSerial', '_resolverCertificateValidFrom', '_resolverCertificateValidUntil', '_dnsDistPortDNSCrypt', '_providerName', '_testServerPort']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_resolverCertificateSerial",
+        "_resolverCertificateValidFrom",
+        "_resolverCertificateValidUntil",
+        "_dnsDistPortDNSCrypt",
+        "_providerName",
+        "_testServerPort",
+    ]
 
     def testSimpleA(self):
         """
         DNSCrypt: encrypted A query
         """
-        client = dnscrypt.DNSCryptClient(self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt)
-        name = 'a.dnscrypt.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        client = dnscrypt.DNSCryptClient(
+            self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt
+        )
+        name = "a.dnscrypt.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.2.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.2.0.1")
         response.answer.append(rrset)
 
         self.doDNSCryptQuery(client, query, response, False)
@@ -97,15 +105,13 @@ class TestDNSCrypt(DNSCryptTest):
         the padding into account) and check that the response
         is truncated.
         """
-        client = dnscrypt.DNSCryptClient(self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt)
-        name = 'smallquerylargeresponse.dnscrypt.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096)
+        client = dnscrypt.DNSCryptClient(
+            self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt
+        )
+        name = "smallquerylargeresponse.dnscrypt.tests.powerdns.com."
+        query = dns.message.make_query(name, "TXT", "IN", use_edns=True, payload=4096)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'A'*255)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, "A" * 255)
         response.answer.append(rrset)
 
         self._toResponderQueue.put(response)
@@ -129,30 +135,36 @@ class TestDNSCrypt(DNSCryptTest):
         """
         DNSCrypt: certificate rotation
         """
-        client = dnscrypt.DNSCryptClient(self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt)
+        client = dnscrypt.DNSCryptClient(
+            self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt
+        )
         client.refreshResolverCertificates()
 
         cert = client.getResolverCertificate()
         self.assertTrue(cert)
         self.assertEqual(cert.serial, self._resolverCertificateSerial)
 
-        name = 'rotation.dnscrypt.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "rotation.dnscrypt.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.2.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.2.0.1")
         response.answer.append(rrset)
 
         self.doDNSCryptQuery(client, query, response, False)
         self.doDNSCryptQuery(client, query, response, True)
 
         # generate a new certificate
-        self.sendConsoleCommand("generateDNSCryptCertificate('DNSCryptProviderPrivate.key', 'DNSCryptResolver.cert.2', 'DNSCryptResolver.key.2', {!s}, {:.0f}, {:.0f})".format(self._resolverCertificateSerial + 1, self._resolverCertificateValidFrom, self._resolverCertificateValidUntil))
+        self.sendConsoleCommand(
+            "generateDNSCryptCertificate('DNSCryptProviderPrivate.key', 'DNSCryptResolver.cert.2', 'DNSCryptResolver.key.2', {!s}, {:.0f}, {:.0f})".format(
+                self._resolverCertificateSerial + 1,
+                self._resolverCertificateValidFrom,
+                self._resolverCertificateValidUntil,
+            )
+        )
         # add that new certificate
-        self.sendConsoleCommand("getDNSCryptBind(0):loadNewCertificate('DNSCryptResolver.cert.2', 'DNSCryptResolver.key.2')")
+        self.sendConsoleCommand(
+            "getDNSCryptBind(0):loadNewCertificate('DNSCryptResolver.cert.2', 'DNSCryptResolver.key.2')"
+        )
 
         oldSerial = self.sendConsoleCommand("getDNSCryptBind(0):getCertificate(0):getSerial()")
         self.assertEqual(int(oldSerial), self._resolverCertificateSerial)
@@ -182,7 +194,13 @@ class TestDNSCrypt(DNSCryptTest):
         self.assertEqual(certs[1].serial, self._resolverCertificateSerial + 1)
 
         # generate a third certificate, this time in memory
-        self.sendConsoleCommand("getDNSCryptBind(0):generateAndLoadInMemoryCertificate('DNSCryptProviderPrivate.key', {!s}, {:.0f}, {:.0f})".format(self._resolverCertificateSerial + 2, self._resolverCertificateValidFrom, self._resolverCertificateValidUntil))
+        self.sendConsoleCommand(
+            "getDNSCryptBind(0):generateAndLoadInMemoryCertificate('DNSCryptProviderPrivate.key', {!s}, {:.0f}, {:.0f})".format(
+                self._resolverCertificateSerial + 2,
+                self._resolverCertificateValidFrom,
+                self._resolverCertificateValidUntil,
+            )
+        )
 
         # we should still be able to send queries with the previous certificate
         self.doDNSCryptQuery(client, query, response, False)
@@ -204,7 +222,13 @@ class TestDNSCrypt(DNSCryptTest):
         self.assertEqual(certs[2].serial, self._resolverCertificateSerial + 2)
 
         # generate a fourth certificate, still in memory
-        self.sendConsoleCommand("getDNSCryptBind(0):generateAndLoadInMemoryCertificate('DNSCryptProviderPrivate.key', {!s}, {:.0f}, {:.0f})".format(self._resolverCertificateSerial + 3, self._resolverCertificateValidFrom, self._resolverCertificateValidUntil))
+        self.sendConsoleCommand(
+            "getDNSCryptBind(0):generateAndLoadInMemoryCertificate('DNSCryptProviderPrivate.key', {!s}, {:.0f}, {:.0f})".format(
+                self._resolverCertificateSerial + 3,
+                self._resolverCertificateValidFrom,
+                self._resolverCertificateValidUntil,
+            )
+        )
 
         # mark the old ones as inactive
         self.sendConsoleCommand("getDNSCryptBind(0):markInactive({!s})".format(self._resolverCertificateSerial))
@@ -217,9 +241,15 @@ class TestDNSCrypt(DNSCryptTest):
         self.assertTrue(cert)
         self.assertEqual(cert.serial, self._resolverCertificateSerial + 2)
         # now remove them
-        self.sendConsoleCommand("getDNSCryptBind(0):removeInactiveCertificate({!s})".format(self._resolverCertificateSerial))
-        self.sendConsoleCommand("getDNSCryptBind(0):removeInactiveCertificate({!s})".format(self._resolverCertificateSerial + 1))
-        self.sendConsoleCommand("getDNSCryptBind(0):removeInactiveCertificate({!s})".format(self._resolverCertificateSerial + 2))
+        self.sendConsoleCommand(
+            "getDNSCryptBind(0):removeInactiveCertificate({!s})".format(self._resolverCertificateSerial)
+        )
+        self.sendConsoleCommand(
+            "getDNSCryptBind(0):removeInactiveCertificate({!s})".format(self._resolverCertificateSerial + 1)
+        )
+        self.sendConsoleCommand(
+            "getDNSCryptBind(0):removeInactiveCertificate({!s})".format(self._resolverCertificateSerial + 2)
+        )
 
         # we should not be able to send with the old ones anymore
         try:
@@ -247,9 +277,11 @@ class TestDNSCrypt(DNSCryptTest):
         """
         DNSCrypt: Test DNSQuestion.Protocol over UDP
         """
-        client = dnscrypt.DNSCryptClient(self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt)
-        name = 'udp.protocols.dnscrypt.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        client = dnscrypt.DNSCryptClient(
+            self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt
+        )
+        name = "udp.protocols.dnscrypt.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         self.doDNSCryptQuery(client, query, response, False)
@@ -258,13 +290,16 @@ class TestDNSCrypt(DNSCryptTest):
         """
         DNSCrypt: Test DNSQuestion.Protocol over TCP
         """
-        client = dnscrypt.DNSCryptClient(self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt)
-        name = 'tcp.protocols.dnscrypt.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        client = dnscrypt.DNSCryptClient(
+            self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt
+        )
+        name = "tcp.protocols.dnscrypt.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         self.doDNSCryptQuery(client, query, response, True)
 
+
 class TestDNSCryptYaml(TestDNSCrypt):
     _config_template = """
     function checkDNSCryptUDP(dq)
@@ -313,11 +348,18 @@ query_rules:
       function_name: "checkDNSCryptTCP"
 """
     _config_params = []
-    _yaml_config_params = ['_consoleKeyB64', '_consolePort', '_dnsDistPortDNSCrypt', '_providerName', '_testServerPort']
+    _yaml_config_params = ["_consoleKeyB64", "_consolePort", "_dnsDistPortDNSCrypt", "_providerName", "_testServerPort"]
 
-class TestDNSCryptWithCache(DNSCryptTest):
 
-    _config_params = ['_resolverCertificateSerial', '_resolverCertificateValidFrom', '_resolverCertificateValidUntil', '_dnsDistPortDNSCrypt', '_providerName', '_testServerPort']
+class TestDNSCryptWithCache(DNSCryptTest):
+    _config_params = [
+        "_resolverCertificateSerial",
+        "_resolverCertificateValidFrom",
+        "_resolverCertificateValidUntil",
+        "_dnsDistPortDNSCrypt",
+        "_providerName",
+        "_testServerPort",
+    ]
     _config_template = """
     generateDNSCryptCertificate("DNSCryptProviderPrivate.key", "DNSCryptResolver.cert", "DNSCryptResolver.key", %d, %d, %d)
     addDNSCryptBind("127.0.0.1:%d", "%s", "DNSCryptResolver.cert", "DNSCryptResolver.key")
@@ -331,15 +373,13 @@ class TestDNSCryptWithCache(DNSCryptTest):
         DNSCrypt: encrypted A query served from cache
         """
         misses = 0
-        client = dnscrypt.DNSCryptClient(self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt)
-        name = 'cacheda.dnscrypt.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        client = dnscrypt.DNSCryptClient(
+            self._providerName, self._providerFingerprint, "127.0.0.1", self._dnsDistPortDNSCrypt
+        )
+        name = "cacheda.dnscrypt.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.2.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.2.0.1")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -372,6 +412,7 @@ class TestDNSCryptWithCache(DNSCryptTest):
             total += self._responsesCounter[key]
         self.assertEqual(total, misses)
 
+
 class TestDNSCryptAutomaticRotation(DNSCryptTest):
     _config_template = """
     setKey("%s")
@@ -403,7 +444,19 @@ class TestDNSCryptAutomaticRotation(DNSCryptTest):
     """
 
     _dnsDistPortDNSCrypt2 = pickAvailablePort()
-    _config_params = ['_consoleKeyB64', '_consolePort', '_resolverCertificateSerial', '_resolverCertificateValidFrom', '_resolverCertificateValidUntil', '_dnsDistPortDNSCrypt', '_providerName', '_dnsDistPortDNSCrypt2', '_providerName', '_testServerPort', '_resolverCertificateSerial']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_resolverCertificateSerial",
+        "_resolverCertificateValidFrom",
+        "_resolverCertificateValidUntil",
+        "_dnsDistPortDNSCrypt",
+        "_providerName",
+        "_dnsDistPortDNSCrypt2",
+        "_providerName",
+        "_testServerPort",
+        "_resolverCertificateSerial",
+    ]
 
     def testCertRotation(self):
         """
@@ -429,14 +482,10 @@ class TestDNSCryptAutomaticRotation(DNSCryptTest):
             self.assertTrue(cert)
             self.assertGreater(cert.serial, serials[client])
 
-        name = 'automatic-rotation.dnscrypt.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "automatic-rotation.dnscrypt.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.2.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.2.0.1")
         response.answer.append(rrset)
 
         for client in clients:
index 6ef94bf28da33d665c12fb4e6b96fe41da0463c0..877e7a7931cb7936d3b5d3e1203513983cd04b69 100644 (file)
@@ -2,8 +2,8 @@
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestDNSParser(DNSDistTest):
 
+class TestDNSParser(DNSDistTest):
     _verboseMode = True
     _config_template = """
   function checkQueryPacket(dq)
@@ -124,14 +124,10 @@ class TestDNSParser(DNSDistTest):
         """
         DNS Parser: basic checks
         """
-        name = 'powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -146,7 +142,6 @@ class TestDNSParser(DNSDistTest):
 
 
 class TestDNSRecordParser(DNSDistTest):
-
     _verboseMode = True
     _config_template = """
   function checkResponsePacket(dq)
@@ -218,26 +213,14 @@ class TestDNSRecordParser(DNSDistTest):
         """
         DNS Parser: parsers checks
         """
-        name = 'powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    'ff:db8::ffff')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "ff:db8::ffff")
         response.answer.append(rrset)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'not-powerdns.com.')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, "not-powerdns.com.")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index e38e410c84c3d3de1a69794a262ca9dad95437fa..844397a003dab76c1c2b2a8f8e344178a08d56b3 100644 (file)
@@ -14,17 +14,18 @@ from dnsdisttests import DNSDistTest, pickAvailablePort
 import pycurl
 from io import BytesIO
 
+
 class DOHTests(object):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _customResponseHeader1 = 'access-control-allow-origin: *'
-    _customResponseHeader2 = 'user-agent: derp'
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _customResponseHeader1 = "access-control-allow-origin: *"
+    _customResponseHeader2 = "user-agent: derp"
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -64,58 +65,64 @@ class DOHTests(object):
     dohFE = getDOHFrontend(0)
     dohFE:setResponsesMap({newDOHResponseMapEntry('^/coffee$', 418, 'C0FFEE', {['FoO']='bar'})})
     """
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_serverName', '_dohServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_serverName",
+        "_dohServerPort",
+        "_dohServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_dohLibrary",
+    ]
     _verboseMode = True
 
     def testDOHSimple(self):
         """
         DOH: Simple query
         """
-        name = 'simple.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
         self.assertEqual(expectedQuery, receivedQuery)
         self.assertIn(self._customResponseHeader1, self._response_headers.decode())
         self.assertIn(self._customResponseHeader2, self._response_headers.decode())
-        self.assertNotIn('UPPERCASE: VaLuE', self._response_headers.decode())
-        self.assertIn('uppercase: VaLuE', self._response_headers.decode())
-        self.assertIn('cache-control: max-age=3600', self._response_headers.decode())
+        self.assertNotIn("UPPERCASE: VaLuE", self._response_headers.decode())
+        self.assertIn("uppercase: VaLuE", self._response_headers.decode())
+        self.assertIn("cache-control: max-age=3600", self._response_headers.decode())
         self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
         self.assertEqual(response, receivedResponse)
-        self.checkHasHeader('cache-control', 'max-age=3600')
+        self.checkHasHeader("cache-control", "max-age=3600")
 
     def testDOHTransactionID(self):
         """
         DOH: Simple query with ID != 0
         """
-        name = 'simple-with-non-zero-id.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple-with-non-zero-id.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 42
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -129,20 +136,18 @@ class DOHTests(object):
         """
         DOH: Simple POST query
         """
-        name = 'simple-post.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple-post.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHPostQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -154,18 +159,16 @@ class DOHTests(object):
         """
         DOH: Existing EDNS
         """
-        name = 'existing-edns.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=8192)
+        name = "existing-edns.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=8192)
         query.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = query.id
@@ -178,22 +181,20 @@ class DOHTests(object):
         """
         DOH: Existing EDNS Client Subnet
         """
-        name = 'existing-ecs.doh.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4')
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[ecso], want_dnssec=True)
+        name = "existing-ecs.doh.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.4")
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=512, options=[ecso], want_dnssec=True)
         query.id = 0
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
         response.want_dnssec(True)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = query.id
@@ -206,42 +207,62 @@ class DOHTests(object):
         """
         DOH: Dropped query
         """
-        name = 'drop.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False)
+        name = "drop.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+        )
         self.assertEqual(receivedResponse, None)
 
     def testRefused(self):
         """
         DOH: Refused
         """
-        name = 'refused.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "refused.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
 
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
     def testSpoof(self):
         """
         DOH: Spoofed
         """
-        name = 'spoof.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "spoof.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.4')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4")
         expectedResponse.answer.append(rrset)
 
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
     def testDOHWithoutQuery(self):
@@ -269,14 +290,22 @@ class DOHTests(object):
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NOTIMP)
 
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
     def testDOHShortPath(self):
         """
         DOH: Short path in GET query
         """
-        url = self._dohBaseURL + '/AA'
+        url = self._dohBaseURL + "/AA"
         conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0)
         conn.setopt(pycurl.URL, url)
         conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
@@ -291,11 +320,11 @@ class DOHTests(object):
         """
         DOH: No parameter GET query
         """
-        name = 'no-parameter-get.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "no-parameter-get.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         wire = query.to_wire()
-        b64 = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
-        url = self._dohBaseURL + '?not-dns=' + b64
+        b64 = base64.urlsafe_b64encode(wire).decode("UTF8").rstrip("=")
+        url = self._dohBaseURL + "?not-dns=" + b64
         conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0)
         conn.setopt(pycurl.URL, url)
         conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
@@ -310,9 +339,9 @@ class DOHTests(object):
         """
         DOH: Invalid Base64 GET query
         """
-        name = 'invalid-b64-get.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
-        url = self._dohBaseURL + '?dns=' + '_-~~~~-_'
+        name = "invalid-b64-get.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
+        url = self._dohBaseURL + "?dns=" + "_-~~~~-_"
         conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0)
         conn.setopt(pycurl.URL, url)
         conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
@@ -327,12 +356,12 @@ class DOHTests(object):
         """
         DOH: Invalid DNS headers
         """
-        name = 'invalid-dns-headers.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "invalid-dns-headers.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.flags |= dns.flags.QR
         wire = query.to_wire()
-        b64 = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
-        url = self._dohBaseURL + '?dns=' + b64
+        b64 = base64.urlsafe_b64encode(wire).decode("UTF8").rstrip("=")
+        url = self._dohBaseURL + "?dns=" + b64
         conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0)
         conn.setopt(pycurl.URL, url)
         conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
@@ -347,18 +376,18 @@ class DOHTests(object):
         """
         DOH: Invalid method
         """
-        name = 'invalid-method.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "invalid-method.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         wire = query.to_wire()
-        b64 = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
-        url = self._dohBaseURL + '?dns=' + b64
+        b64 = base64.urlsafe_b64encode(wire).decode("UTF8").rstrip("=")
+        url = self._dohBaseURL + "?dns=" + b64
         conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2)
         conn.setopt(pycurl.URL, url)
         conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
         conn.setopt(pycurl.SSL_VERIFYPEER, 1)
         conn.setopt(pycurl.SSL_VERIFYHOST, 2)
         conn.setopt(pycurl.CAINFO, self._caCert)
-        conn.setopt(pycurl.CUSTOMREQUEST, 'PATCH')
+        conn.setopt(pycurl.CUSTOMREQUEST, "PATCH")
         conn.perform_rb()
         rcode = conn.getinfo(pycurl.RESPONSE_CODE)
         self.assertEqual(rcode, 400)
@@ -367,19 +396,19 @@ class DOHTests(object):
         """
         DOH: Invalid ALPN
         """
-        alpn = ['bogus-alpn']
+        alpn = ["bogus-alpn"]
         conn = self.openTLSConnection(self._dohServerPort, self._serverName, self._caCert, alpn=alpn)
         try:
-            conn.send('AAAA')
+            conn.send("AAAA")
             response = conn.recv(65535)
             self.assertFalse(response)
         except Exception:
             pass
 
     metricMap = {
-        'connects': 2,
-        'http/1.1': 3,
-        'http/2': 4,
+        "connects": 2,
+        "http/1.1": 3,
+        "http/2": 4,
     }
 
     def getHTTPCounter(self, name):
@@ -393,19 +422,18 @@ class DOHTests(object):
         """
         DOH: HTTP/1.1
         """
-        httpConnections = self.getHTTPCounter('connects')
-        http1 = self.getHTTPCounter('http/1.1')
-        http2 = self.getHTTPCounter('http/2')
-        name = 'http11.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        httpConnections = self.getHTTPCounter("connects")
+        http1 = self.getHTTPCounter("http/1.1")
+        http2 = self.getHTTPCounter("http/2")
+        name = "http11.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         wire = query.to_wire()
-        b64 = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
-        url = self._dohBaseURL + '?dns=' + b64
+        b64 = base64.urlsafe_b64encode(wire).decode("UTF8").rstrip("=")
+        url = self._dohBaseURL + "?dns=" + b64
         responseHeaders = BytesIO()
         conn = pycurl.Curl()
         conn.setopt(pycurl.HTTP_VERSION, pycurl.CURL_HTTP_VERSION_1_1)
-        conn.setopt(pycurl.HTTPHEADER, ["Content-type: application/dns-message",
-                                         "Accept: application/dns-message"])
+        conn.setopt(pycurl.HTTPHEADER, ["Content-type: application/dns-message", "Accept: application/dns-message"])
         conn.setopt(pycurl.URL, url)
         conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
         conn.setopt(pycurl.SSL_VERIFYPEER, 1)
@@ -416,16 +444,19 @@ class DOHTests(object):
         rcode = conn.getinfo(pycurl.RESPONSE_CODE)
         responseHeaders = responseHeaders.getvalue()
         self.assertEqual(rcode, 400)
-        self.assertEqual(data, b'<html><body>This server implements RFC 8484 - DNS Queries over HTTP, and requires HTTP/2 in accordance with section 5.2 of the RFC.</body></html>\r\n')
-        self.assertEqual(self.getHTTPCounter('connects'), httpConnections + 1)
-        self.assertEqual(self.getHTTPCounter('http/1.1'), http1 + 1)
-        self.assertEqual(self.getHTTPCounter('http/2'), http2)
+        self.assertEqual(
+            data,
+            b"<html><body>This server implements RFC 8484 - DNS Queries over HTTP, and requires HTTP/2 in accordance with section 5.2 of the RFC.</body></html>\r\n",
+        )
+        self.assertEqual(self.getHTTPCounter("connects"), httpConnections + 1)
+        self.assertEqual(self.getHTTPCounter("http/1.1"), http1 + 1)
+        self.assertEqual(self.getHTTPCounter("http/2"), http2)
 
         dateFound = False
         for header in responseHeaders.decode().splitlines(False):
-            values = header.split(':')
+            values = header.split(":")
             key = values[0]
-            if key.lower() == 'date':
+            if key.lower() == "date":
                 dateFound = True
                 break
         self.assertTrue(dateFound)
@@ -434,38 +465,47 @@ class DOHTests(object):
         """
         DOH: Check that HTTP/1.1 is not selected over H2 when offered in the wrong order by the client
         """
-        alpn = ['http/1.1', 'h2']
+        alpn = ["http/1.1", "h2"]
         conn = self.openTLSConnection(self._dohServerPort, self._serverName, self._caCert, alpn=alpn)
-        if not hasattr(conn, 'selected_alpn_protocol'):
-            raise unittest.SkipTest('Unable to check the selected ALPN, Python version is too old to support selected_alpn_protocol')
-        self.assertEqual(conn.selected_alpn_protocol(), 'h2')
+        if not hasattr(conn, "selected_alpn_protocol"):
+            raise unittest.SkipTest(
+                "Unable to check the selected ALPN, Python version is too old to support selected_alpn_protocol"
+            )
+        self.assertEqual(conn.selected_alpn_protocol(), "h2")
 
     def testDOHInvalid(self):
         """
         DOH: Invalid DNS query
         """
-        name = 'invalid.doh.tests.powerdns.com.'
-        invalidQuery = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "invalid.doh.tests.powerdns.com."
+        invalidQuery = dns.message.make_query(name, "A", "IN", use_edns=False)
         invalidQuery.id = 0
         # first an invalid query
         invalidQuery = invalidQuery.to_wire()
         invalidQuery = invalidQuery[:-5]
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=invalidQuery, response=None, useQueue=False, rawQuery=True)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            caFile=self._caCert,
+            query=invalidQuery,
+            response=None,
+            useQueue=False,
+            rawQuery=True,
+        )
         self.assertEqual(receivedResponse, None)
 
         # and now a valid one
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -477,22 +517,26 @@ class DOHTests(object):
         """
         DOH: Invalid HTTP header name query
         """
-        name = 'invalid-header-name.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "invalid-header-name.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         # this header is invalid, see rfc9113 section 8.2.1. Field Validity
-        customHeaders = ['{}: test']
+        customHeaders = ["{}: test"]
         try:
-            (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, customHeaders=customHeaders)
+            (receivedQuery, receivedResponse) = self.sendDOHQuery(
+                self._dohServerPort,
+                self._serverName,
+                self._dohBaseURL,
+                query,
+                response=response,
+                caFile=self._caCert,
+                customHeaders=customHeaders,
+            )
             self.assertFalse(receivedQuery)
             self.assertFalse(receivedResponse)
         except pycurl.error:
@@ -502,11 +546,11 @@ class DOHTests(object):
         """
         DOH: No backend
         """
-        name = 'no-backend.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "no-backend.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         wire = query.to_wire()
-        b64 = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
-        url = self._dohBaseURL + '?dns=' + b64
+        b64 = base64.urlsafe_b64encode(wire).decode("UTF8").rstrip("=")
+        url = self._dohBaseURL + "?dns=" + b64
         conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2)
         conn.setopt(pycurl.URL, url)
         conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
@@ -521,24 +565,30 @@ class DOHTests(object):
         """
         DOH: Empty POST query
         """
-        name = 'empty-post.doh.tests.powerdns.com.'
-
-        (_, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query="", rawQuery=True, response=None, caFile=self._caCert)
+        name = "empty-post.doh.tests.powerdns.com."
+
+        (_, receivedResponse) = self.sendDOHPostQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            query="",
+            rawQuery=True,
+            response=None,
+            caFile=self._caCert,
+        )
         self.assertEqual(receivedResponse, None)
 
         # and now a valid one
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
-        (receivedQuery, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHPostQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -550,35 +600,44 @@ class DOHTests(object):
         """
         DOH: HeaderRule
         """
-        name = 'header-rule.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "header-rule.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '2.3.4.5')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "2.3.4.5")
         expectedResponse.answer.append(rrset)
 
         # this header should match
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False, customHeaders=['x-powerdnS: aaaaa'])
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+            customHeaders=["x-powerdnS: aaaaa"],
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.flags &= ~dns.flags.RD
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # this content of the header should NOT match
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, customHeaders=['x-powerdnS: bbbbb'])
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            customHeaders=["x-powerdnS: bbbbb"],
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -590,35 +649,42 @@ class DOHTests(object):
         """
         DOH: HTTPPath
         """
-        name = 'http-path.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "http-path.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '3.4.5.6')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "3.4.5.6")
         expectedResponse.answer.append(rrset)
 
         # this path should match
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + 'PowerDNS', caFile=self._caCert, query=query, response=None, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL + "PowerDNS",
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         expectedQuery.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # this path should NOT match
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + "PowerDNS2", query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL + "PowerDNS2",
+            query,
+            response=response,
+            caFile=self._caCert,
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -627,44 +693,59 @@ class DOHTests(object):
         self.assertEqual(response, receivedResponse)
 
         # this path is not in the URLs map and should lead to a 404
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + "PowerDNS/something", query, caFile=self._caCert, useQueue=False, rawResponse=True)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL + "PowerDNS/something",
+            query,
+            caFile=self._caCert,
+            useQueue=False,
+            rawResponse=True,
+        )
         self.assertTrue(receivedResponse)
-        self.assertEqual(receivedResponse, b'there is no endpoint configured for this path')
+        self.assertEqual(receivedResponse, b"there is no endpoint configured for this path")
         self.assertEqual(self._rcode, 404)
 
     def testHTTPPathRegex(self):
         """
         DOH: HTTPPathRegex
         """
-        name = 'http-path-regex.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "http-path-regex.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '6.7.8.9')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "6.7.8.9")
         expectedResponse.answer.append(rrset)
 
         # this path should match
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + 'PowerDNS-999', caFile=self._caCert, query=query, response=None, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL + "PowerDNS-999",
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         expectedQuery.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # this path should NOT match
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + "PowerDNS2", query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL + "PowerDNS2",
+            query,
+            response=response,
+            caFile=self._caCert,
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -676,49 +757,73 @@ class DOHTests(object):
         """
         DOH: HTTPStatusAction 200 OK
         """
-        name = 'http-status-action.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "http-status-action.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
 
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, rawResponse=True)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            query,
+            caFile=self._caCert,
+            useQueue=False,
+            rawResponse=True,
+        )
         self.assertTrue(receivedResponse)
-        self.assertEqual(receivedResponse, b'Plaintext answer')
+        self.assertEqual(receivedResponse, b"Plaintext answer")
         self.assertEqual(self._rcode, 200)
-        self.assertIn('content-type: text/plain', self._response_headers.decode())
+        self.assertIn("content-type: text/plain", self._response_headers.decode())
 
     def testHTTPStatusAction307(self):
         """
         DOH: HTTPStatusAction 307
         """
-        name = 'http-status-action-redirect.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "http-status-action-redirect.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
 
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, rawResponse=True)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            query,
+            caFile=self._caCert,
+            useQueue=False,
+            rawResponse=True,
+        )
         self.assertTrue(receivedResponse)
         self.assertEqual(self._rcode, 307)
-        self.assertIn('location: https://doh.powerdns.org', self._response_headers.decode())
+        self.assertIn("location: https://doh.powerdns.org", self._response_headers.decode())
 
     def testHTTPLuaResponse(self):
         """
         DOH: Lua HTTP Response
         """
-        name = 'http-lua.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "http-lua.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
 
-        (_, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, rawResponse=True)
+        (_, receivedResponse) = self.sendDOHPostQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            query,
+            caFile=self._caCert,
+            useQueue=False,
+            rawResponse=True,
+        )
         self.assertTrue(receivedResponse)
-        self.assertEqual(receivedResponse, b'It works!')
+        self.assertEqual(receivedResponse, b"It works!")
         self.assertEqual(self._rcode, 200)
-        self.assertIn('content-type: text/plain', self._response_headers.decode())
+        self.assertIn("content-type: text/plain", self._response_headers.decode())
 
     def testHTTPEarlyResponse(self):
         """
         DOH: HTTP Early Response
         """
         response_headers = BytesIO()
-        url = self._dohBaseURL + 'coffee'
+        url = self._dohBaseURL + "coffee"
         conn = self.openDOHConnection(self._dohServerPort, caFile=self._caCert, timeout=2.0)
         conn.setopt(pycurl.URL, url)
         conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
@@ -731,8 +836,8 @@ class DOHTests(object):
         headers = response_headers.getvalue().decode()
 
         self.assertEqual(rcode, 418)
-        self.assertEqual(data, b'C0FFEE')
-        self.assertIn('foo: bar', headers)
+        self.assertEqual(data, b"C0FFEE")
+        self.assertIn("foo: bar", headers)
         self.assertNotIn(self._customResponseHeader2, headers)
 
         response_headers = BytesIO()
@@ -744,15 +849,15 @@ class DOHTests(object):
         conn.setopt(pycurl.CAINFO, self._caCert)
         conn.setopt(pycurl.HEADERFUNCTION, response_headers.write)
         conn.setopt(pycurl.POST, True)
-        data = ''
+        data = ""
         conn.setopt(pycurl.POSTFIELDS, data)
 
         data = conn.perform_rb()
         rcode = conn.getinfo(pycurl.RESPONSE_CODE)
         headers = response_headers.getvalue().decode()
         self.assertEqual(rcode, 418)
-        self.assertEqual(data, b'C0FFEE')
-        self.assertIn('foo: bar', headers)
+        self.assertEqual(data, b"C0FFEE")
+        self.assertIn("foo: bar", headers)
         self.assertNotIn(self._customResponseHeader2, headers)
 
     def testFrontendAccessViaBuiltInClient(self):
@@ -764,23 +869,27 @@ class DOHTests(object):
 
         output = None
         try:
-            confFile = os.path.join('configs', 'dnsdist_%s.conf' % (self.__class__.__name__))
-            testcmd = [os.environ['DNSDISTBIN'], '--client', '-C', confFile ]
-            process = subprocess.Popen(testcmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
-            output = process.communicate(input=b'showVersion()\n')
+            confFile = os.path.join("configs", "dnsdist_%s.conf" % (self.__class__.__name__))
+            testcmd = [os.environ["DNSDISTBIN"], "--client", "-C", confFile]
+            process = subprocess.Popen(
+                testcmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True
+            )
+            output = process.communicate(input=b"showVersion()\n")
         except subprocess.CalledProcessError as exc:
-            raise AssertionError('%s failed (%d): %s' % (testcmd, process.returncode, process.output))
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, process.output))
 
         if process.returncode != 0:
-          raise AssertionError('%s failed (%d): %s' % (testcmd, process.returncode, output))
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, output))
+
+        self.assertTrue(output[0].startswith(b"dnsdist "))
 
-        self.assertTrue(output[0].startswith(b'dnsdist '))
 
 class TestDoHNGHTTP2(DOHTests, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
+
 
 class TestDoHNGHTTP2Yaml(DOHTests, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
     _yaml_config_template = """---
 console:
   key: "%s"
@@ -900,7 +1009,15 @@ query_rules:
       type: "Lua"
       function_name: "dohHandler"
 """
-    _yaml_config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _yaml_config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_dohServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_dohLibrary",
+    ]
     _config_template = """
     function dohHandler(dq)
       if dq:getHTTPScheme() == 'https' and dq:getHTTPHost() == '%s:%d' and dq:getHTTPPath() == '/' and dq:getHTTPQueryString() == '' then
@@ -920,15 +1037,16 @@ query_rules:
       return DNSAction.None
     end
     """
-    _config_params = ['_serverName', '_dohServerPort']
+    _config_params = ["_serverName", "_dohServerPort"]
+
 
 class DOHSubPathsTests(object):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -936,85 +1054,100 @@ class DOHSubPathsTests(object):
 
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/PowerDNS" }, {exactPathMatching=false, library='%s'})
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey", "_dohLibrary"]
 
     def testSubPath(self):
         """
         DOH: sub-path
         """
-        name = 'sub-path.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "sub-path.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '3.4.5.6')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "3.4.5.6")
         expectedResponse.answer.append(rrset)
 
         # this path should match
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + 'PowerDNS', caFile=self._caCert, query=query, response=None, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL + "PowerDNS",
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         expectedQuery.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # this path is not in the URLs map and should lead to a 404
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + "NotPowerDNS", query, caFile=self._caCert, useQueue=False, rawResponse=True)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL + "NotPowerDNS",
+            query,
+            caFile=self._caCert,
+            useQueue=False,
+            rawResponse=True,
+        )
         self.assertTrue(receivedResponse)
-        self.assertIn(receivedResponse, [b'there is no endpoint configured for this path', b'not found'])
+        self.assertIn(receivedResponse, [b"there is no endpoint configured for this path", b"not found"])
         self.assertEqual(self._rcode, 404)
 
         # this path is below one in the URLs map and exactPathMatching is false, so we should be good
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + 'PowerDNS/something', caFile=self._caCert, query=query, response=None, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL + "PowerDNS/something",
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
+
 class TestDoHSubPathsNGHTTP2(DOHSubPathsTests, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
 
-class DOHAddingECSTests(object):
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+class DOHAddingECSTests(object):
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d", useClientSubnet=true}
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, {library='%s'})
     setECSOverride(true)
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey", "_dohLibrary"]
 
     def testDOHSimple(self):
         """
         DOH with ECS: Simple query
         """
-        name = 'simple.doh-ecs.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.doh-ecs.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso])
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.0", 24)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[rewrittenEcso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         expectedQuery.id = receivedQuery.id
@@ -1027,20 +1160,18 @@ class DOHAddingECSTests(object):
         """
         DOH with ECS: Existing EDNS
         """
-        name = 'existing-edns.doh-ecs.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=8192)
+        name = "existing-edns.doh-ecs.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=8192)
         query.id = 0
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=8192, options=[rewrittenEcso])
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.0", 24)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=8192, options=[rewrittenEcso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -1053,23 +1184,23 @@ class DOHAddingECSTests(object):
         """
         DOH with ECS: Existing EDNS Client Subnet
         """
-        name = 'existing-ecs.doh-ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4')
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[ecso], want_dnssec=True)
+        name = "existing-ecs.doh-ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.4")
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.0", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=512, options=[ecso], want_dnssec=True)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[rewrittenEcso], want_dnssec=True)
+        expectedQuery = dns.message.make_query(
+            name, "A", "IN", use_edns=True, payload=512, options=[rewrittenEcso], want_dnssec=True
+        )
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
         response.want_dnssec(True)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -1078,36 +1209,36 @@ class DOHAddingECSTests(object):
         self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
         self.checkResponseEDNSWithECS(response, receivedResponse)
 
+
 class TestDoHAddingECSNGHTTP2(DOHAddingECSTests, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
+
 
 class DOHOverHTTP(object):
     _dohServerPort = pickAvailablePort()
-    _serverName = 'tls.tests.dnsdist.org'
-    _dohBaseURL = ("http://%s:%d/dns-query" % (_serverName, _dohServerPort))
+    _serverName = "tls.tests.dnsdist.org"
+    _dohBaseURL = "http://%s:%d/dns-query" % (_serverName, _dohServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addDOHLocal("127.0.0.1:%d", nil, nil, '/dns-query', {library='%s'})
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_dohLibrary']
+    _config_params = ["_testServerPort", "_dohServerPort", "_dohLibrary"]
 
     def testDOHSimple(self):
         """
         DOH over HTTP: Simple query
         """
-        name = 'simple.doh-over-http.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.doh-over-http.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, useHTTPS=False)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, useHTTPS=False
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         expectedQuery.id = receivedQuery.id
@@ -1120,20 +1251,18 @@ class DOHOverHTTP(object):
         """
         DOH over HTTP: Simple POST query
         """
-        name = 'simple-post.doh-over-http.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple-post.doh-over-http.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, useHTTPS=False)
+        (receivedQuery, receivedResponse) = self.sendDOHPostQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, useHTTPS=False
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -1142,18 +1271,21 @@ class DOHOverHTTP(object):
         self.assertEqual(response, receivedResponse)
         self.checkResponseNoEDNS(response, receivedResponse)
 
+
 class TestDOHOverHTTPNGHTTP2(DOHOverHTTP, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
-    _checkConfigExpectedOutputPrefix = b'msg="No certificate provided for DoH frontend, running in DNS over HTTP mode instead of DNS over HTTPS"'
+    _dohLibrary = "nghttp2"
+    _checkConfigExpectedOutputPrefix = (
+        b'msg="No certificate provided for DoH frontend, running in DNS over HTTP mode instead of DNS over HTTPS"'
+    )
 
-class DOHWithCache(object):
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+class DOHWithCache(object):
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/dns-query" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/dns-query" % (_serverName, _dohServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -1162,71 +1294,69 @@ class DOHWithCache(object):
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey", "_dohLibrary"]
 
     def testDOHCacheLargeAnswer(self):
         """
         DOH with cache: Check that we can cache (and retrieve) large answers
         """
         numberOfQueries = 10
-        name = 'large.doh-with-cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "large.doh-with-cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
         # we prepare a large answer
         content = ""
         for i in range(44):
             if len(content) > 0:
-                content = content + ', '
-            content = content + (str(i)*50)
+                content = content + ", "
+            content = content + (str(i) * 50)
         # pad up to 4096
-        content = content + 'A'*40
+        content = content + "A" * 40
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    content)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, content)
         response.answer.append(rrset)
         self.assertEqual(len(response.to_wire()), 4096)
 
         # first query to fill the cache
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
         self.assertEqual(expectedQuery, receivedQuery)
         self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
         self.assertEqual(response, receivedResponse)
-        self.checkHasHeader('cache-control', 'max-age=3600')
+        self.checkHasHeader("cache-control", "max-age=3600")
 
         for _ in range(numberOfQueries):
-            (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False)
+            (_, receivedResponse) = self.sendDOHQuery(
+                self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False
+            )
             self.assertEqual(receivedResponse, response)
-            self.checkHasHeader('cache-control', 'max-age=' + str(receivedResponse.answer[0].ttl))
+            self.checkHasHeader("cache-control", "max-age=" + str(receivedResponse.answer[0].ttl))
 
         time.sleep(1)
 
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False
+        )
         self.assertEqual(receivedResponse, response)
-        self.checkHasHeader('cache-control', 'max-age=' + str(receivedResponse.answer[0].ttl))
+        self.checkHasHeader("cache-control", "max-age=" + str(receivedResponse.answer[0].ttl))
 
     def testDOHGetFromUDPCache(self):
         """
         DOH with cache: Check that we can retrieve an answer received for a UDP query
         """
-        name = 'doh-query-insert-udp.doh-with-cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        name = "doh-query-insert-udp.doh-with-cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.84')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.84")
         response.answer.append(rrset)
 
         # first query to fill the cache
@@ -1238,7 +1368,9 @@ class DOHWithCache(object):
         self.assertEqual(response, receivedResponse)
 
         # now we send the exact same query over DoH, we should get a cache hit
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False
+        )
         self.assertTrue(receivedResponse)
         self.assertEqual(response, receivedResponse)
 
@@ -1246,20 +1378,18 @@ class DOHWithCache(object):
         """
         DOH with cache: Check that we can retrieve an answer received for a DoH query from UDP
         """
-        name = 'udp-query-get-doh.doh-with-cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        name = "udp-query-get-doh.doh-with-cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.84')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.84")
         response.answer.append(rrset)
 
         # first query to fill the cache
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -1277,17 +1407,13 @@ class DOHWithCache(object):
         """
         # the query is first forwarded over UDP, leading to a TC=1 answer from the
         # backend, then over TCP
-        name = 'truncated-udp.doh-with-cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "truncated-udp.doh-with-cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 42
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 42
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # first response is a TC=1
@@ -1295,7 +1421,9 @@ class DOHWithCache(object):
         tcResponse.flags |= dns.flags.TC
         self._toResponderQueue.put(tcResponse, True, 2.0)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, response=response)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, response=response
+        )
         # first query, received by the responder over UDP
         self.assertTrue(receivedQuery)
         receivedQuery.id = expectedQuery.id
@@ -1314,7 +1442,9 @@ class DOHWithCache(object):
         self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
 
         # now check the cache for a DoH query
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False
+        )
         self.assertEqual(response, receivedResponse)
 
         # The TC=1 answer received over UDP will not be cached, because we currently do not cache answers with no records (no TTL)
@@ -1326,20 +1456,18 @@ class DOHWithCache(object):
         """
         DOH: Check that responses received over UDP are cached (with cache)
         """
-        name = 'cached-udp.doh-with-cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "cached-udp.doh-with-cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, response=response)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, response=response
+        )
         self.assertTrue(receivedQuery)
         receivedQuery.id = expectedQuery.id
         self.assertEqual(expectedQuery, receivedQuery)
@@ -1348,70 +1476,73 @@ class DOHWithCache(object):
         self.assertEqual(response, receivedResponse)
 
         # now check the cache for a DoH query
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False
+        )
         self.assertEqual(response, receivedResponse)
 
         # Check that the answer is usable for UDP queries as well
         (_, receivedResponse) = self.sendUDPQuery(expectedQuery, response=None, useQueue=False)
         self.assertEqual(response, receivedResponse)
 
+
 class TestDOHWithCacheNGHTTP2(DOHWithCache, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
     _verboseMode = True
 
-class DOHWithoutCacheControl(object):
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+class DOHWithoutCacheControl(object):
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, {sendCacheControlHeaders=false, library='%s'})
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey", "_dohLibrary"]
 
     def testDOHSimple(self):
         """
         DOH without cache-control
         """
-        name = 'simple.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
         self.assertEqual(expectedQuery, receivedQuery)
-        self.checkNoHeader('cache-control')
+        self.checkNoHeader("cache-control")
         self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
         self.assertEqual(response, receivedResponse)
 
+
 class TestDOHWithoutCacheControlNGHTTP2(DOHWithoutCacheControl, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
+
 
 class DOHFFI(object):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _customResponseHeader1 = 'access-control-allow-origin: *'
-    _customResponseHeader2 = 'user-agent: derp'
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _customResponseHeader1 = "access-control-allow-origin: *"
+    _customResponseHeader2 = "user-agent: derp"
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -1448,32 +1579,50 @@ class DOHFFI(object):
     end
     addAction("http-lua-ffi.doh.tests.powerdns.com.", LuaFFIAction(dohHandler))
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary', '_serverName', '_dohServerPort']
+    _config_params = [
+        "_testServerPort",
+        "_dohServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_dohLibrary",
+        "_serverName",
+        "_dohServerPort",
+    ]
 
     def testHTTPLuaFFIResponse(self):
         """
         DOH: Lua FFI HTTP Response
         """
-        name = 'http-lua-ffi.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "http-lua-ffi.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
 
-        (_, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, rawResponse=True)
+        (_, receivedResponse) = self.sendDOHPostQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            query,
+            caFile=self._caCert,
+            useQueue=False,
+            rawResponse=True,
+        )
         self.assertTrue(receivedResponse)
-        self.assertEqual(receivedResponse, b'It works!')
+        self.assertEqual(receivedResponse, b"It works!")
         self.assertEqual(self._rcode, 200)
-        self.assertIn('content-type: text/plain', self._response_headers.decode())
+        self.assertIn("content-type: text/plain", self._response_headers.decode())
+
 
 class TestDOHFFINGHTTP2(DOHFFI, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
+
 
 class DOHForwardedFor(object):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -1483,26 +1632,30 @@ class DOHForwardedFor(object):
     -- that code along with X-Forwarded-For support
     setMaxTCPConnectionsPerClient(2)
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey", "_dohLibrary"]
 
     def testDOHAllowedForwarded(self):
         """
         DOH with X-Forwarded-For allowed
         """
-        name = 'allowed.forwarded.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "allowed.forwarded.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, customHeaders=['x-forwarded-for: 127.0.0.1:42, 127.0.0.1, 192.0.2.1:4200'])
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            customHeaders=["x-forwarded-for: 127.0.0.1:42, 127.0.0.1, 192.0.2.1:4200"],
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -1514,94 +1667,115 @@ class DOHForwardedFor(object):
         """
         DOH with X-Forwarded-For not allowed
         """
-        name = 'not-allowed.forwarded.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "not-allowed.forwarded.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, useQueue=False, rawResponse=True, customHeaders=['x-forwarded-for: 127.0.0.1:42, 127.0.0.1'])
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            useQueue=False,
+            rawResponse=True,
+            customHeaders=["x-forwarded-for: 127.0.0.1:42, 127.0.0.1"],
+        )
 
         self.assertEqual(self._rcode, 403)
-        self.assertEqual(receivedResponse, b'DoH query not allowed because of ACL')
+        self.assertEqual(receivedResponse, b"DoH query not allowed because of ACL")
+
 
 class TestDOHForwardedForNGHTTP2(DOHForwardedFor, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
 
-class DOHForwardedForNoTrusted(object):
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+class DOHForwardedForNoTrusted(object):
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
     setACL('192.0.2.1/32')
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, {earlyACLDrop=true, library='%s'})
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey", "_dohLibrary"]
 
     def testDOHForwardedUntrusted(self):
         """
         DOH with X-Forwarded-For not trusted
         """
-        name = 'not-trusted.forwarded.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "not-trusted.forwarded.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         dropped = False
         try:
-            (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, useQueue=False, rawResponse=True, customHeaders=['x-forwarded-for: 192.0.2.1:4200'])
+            (receivedQuery, receivedResponse) = self.sendDOHQuery(
+                self._dohServerPort,
+                self._serverName,
+                self._dohBaseURL,
+                query,
+                response=response,
+                caFile=self._caCert,
+                useQueue=False,
+                rawResponse=True,
+                customHeaders=["x-forwarded-for: 192.0.2.1:4200"],
+            )
             self.assertEqual(self._rcode, 403)
-            self.assertEqual(receivedResponse, b'DoH query not allowed because of ACL')
+            self.assertEqual(receivedResponse, b"DoH query not allowed because of ACL")
         except pycurl.error as e:
             dropped = True
 
         self.assertTrue(dropped)
 
+
 class TestDOHForwardedForNoTrustedNGHTTP2(DOHForwardedForNoTrusted, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
 
-class DOHFrontendLimits(object):
 
+class DOHFrontendLimits(object):
     # this test suite uses a different responder port
     # because it uses a different health check configuration
     _testServerPort = pickAvailablePort()
     _answerUnexpected = True
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _skipListeningOnCL = True
     _maxTCPConnsPerDOHFrontend = 5
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, { maxConcurrentTCPConnections=%d, library='%s' })
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_maxTCPConnsPerDOHFrontend', '_dohLibrary']
-    _alternateListeningAddr = '127.0.0.1'
+    _config_params = [
+        "_testServerPort",
+        "_dohServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_maxTCPConnsPerDOHFrontend",
+        "_dohLibrary",
+    ]
+    _alternateListeningAddr = "127.0.0.1"
     _alternateListeningPort = _dohServerPort
 
     def testTCPConnsPerDOHFrontend(self):
@@ -1613,7 +1787,7 @@ class DOHFrontendLimits(object):
 
         for idx in range(self._maxTCPConnsPerDOHFrontend + 1):
             try:
-                alpn = ['h2']
+                alpn = ["h2"]
                 conns.append(self.openTLSConnection(self._dohServerPort, self._serverName, self._caCert, alpn=alpn))
             except Exception:
                 conns.append(None)
@@ -1647,18 +1821,20 @@ class DOHFrontendLimits(object):
         self.assertEqual(count, self._maxTCPConnsPerDOHFrontend)
         self.assertEqual(failed, 1)
 
+
 class TestDOHFrontendLimitsNGHTTP2(DOHFrontendLimits, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
+
 
 class Protocols(object):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _customResponseHeader1 = 'access-control-allow-origin: *'
-    _customResponseHeader2 = 'user-agent: derp'
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _customResponseHeader1 = "access-control-allow-origin: *"
+    _customResponseHeader2 = "user-agent: derp"
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     function checkDOH(dq)
       if dq:getProtocol() ~= "DNS over HTTPS" then
@@ -1671,19 +1847,21 @@ class Protocols(object):
     newServer{address="127.0.0.1:%d"}
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, {library='%s'})
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey", "_dohLibrary"]
 
     def testProtocolDOH(self):
         """
         DoH: Test DNSQuestion.Protocol
         """
-        name = 'protocols.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "protocols.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -1691,108 +1869,117 @@ class Protocols(object):
         self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
         self.assertEqual(response, receivedResponse)
 
+
 class TestProtocolsNGHTTP2(Protocols, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
+
 
 class DOHWithPKCS12Cert(object):
-    _serverCert = 'server.p12'
-    _pkcs12Password = 'passw0rd'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverCert = "server.p12"
+    _pkcs12Password = "passw0rd"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     cert=newTLSCertificate("%s", {password="%s"})
     addDOHLocal("127.0.0.1:%d", cert, "", { "/" }, {library='%s'})
     """
-    _config_params = ['_testServerPort', '_serverCert', '_pkcs12Password', '_dohServerPort', '_dohLibrary']
+    _config_params = ["_testServerPort", "_serverCert", "_pkcs12Password", "_dohServerPort", "_dohLibrary"]
 
     def testPKCS12DOH(self):
         """
         DoH: Test Simple DOH Query with a password protected PKCS12 file configured
         """
-        name = 'simple.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
         self.assertEqual(expectedQuery, receivedQuery)
 
+
 class TestDOHWithPKCS12CertNGHTTP2(DOHWithPKCS12Cert, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
+
 
 class DOHForwardedToTCPOnly(object):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d", tcpOnly=true}
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, {library='%s'})
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey", "_dohLibrary"]
 
     def testDOHTCPOnly(self):
         """
         DoH: Test a DoH query forwarded to a TCP-only server
         """
-        name = 'tcponly.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tcponly.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 42
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = query.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
 
+
 class TestDOHForwardedToTCPOnlyNGHTTP2(DOHForwardedToTCPOnly, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
+
 
 class DOHLimits(object):
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
     _maxTCPConnsPerClient = 3
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, {library='%s'})
     setMaxTCPConnectionsPerClient(%d)
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary', '_maxTCPConnsPerClient']
+    _config_params = [
+        "_testServerPort",
+        "_dohServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_dohLibrary",
+        "_maxTCPConnsPerClient",
+    ]
 
     def testConnsPerClient(self):
         """
         DoH Limits: Maximum number of conns per client
         """
-        name = 'maxconnsperclient.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "maxconnsperclient.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         url = self.getDOHGetURL(self._dohBaseURL, query)
         conns = []
 
@@ -1826,38 +2013,42 @@ class DOHLimits(object):
         self.assertEqual(count, self._maxTCPConnsPerClient)
         self.assertEqual(failed, 1)
 
+
 class TestDOHLimitsNGHTTP2(DOHLimits, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
+    _dohLibrary = "nghttp2"
+
 
 class DOHXFR(object):
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
     _maxTCPConnsPerClient = 3
     _config_template = """
     newServer{address="127.0.0.1:%d", tcpOnly=true}
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, {library='%s'})
     """
-    _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_params = ["_testServerPort", "_dohServerPort", "_serverCert", "_serverKey", "_dohLibrary"]
 
     def testXFR(self):
         """
         DoH XFR: Check that XFR requests over DoH are refused with NotImp
         """
-        name = 'xfr.doh.tests.powerdns.com.'
+        name = "xfr.doh.tests.powerdns.com."
         for xfrType in [dns.rdatatype.AXFR, dns.rdatatype.IXFR]:
-            query = dns.message.make_query(name, xfrType, 'IN')
+            query = dns.message.make_query(name, xfrType, "IN")
 
             expectedResponse = dns.message.make_response(query)
             expectedResponse.set_rcode(dns.rcode.NOTIMP)
 
-            (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False)
+            (_, receivedResponse) = self.sendDOHQuery(
+                self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False
+            )
 
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestDOHXFRNGHTTP2(DOHXFR, DNSDistDOHTest):
-    _dohLibrary = 'nghttp2'
 
+class TestDOHXFRNGHTTP2(DOHXFR, DNSDistDOHTest):
+    _dohLibrary = "nghttp2"
index 35aa9b0cc92608bec3015589309026ba008978d3..69ad612d574cdcf62ab453d2869f55d9382ef9b1 100644 (file)
@@ -5,20 +5,32 @@ from dnsdisttests import DNSDistTest
 from dnsdisttests import pickAvailablePort
 from quictests import QUICTests, QUICACLTests, QUICGetLocalAddressOnAnyBindTests, QUICXFRTests
 
+
 class DOH3Common(object):
     def getQUICConnection(self):
         return self.getDOQConnection(self._doqServerPort, self._caCert)
 
     def sendQUICQuery(self, query, response=None, useQueue=True, connection=None, passExceptions=False):
-        return self.sendDOH3Query(self._doqServerPort, self._dohBaseURL, query, response=response, caFile=self._caCert, useQueue=useQueue, serverName=self._serverName, connection=connection, passExceptions=passExceptions)
+        return self.sendDOH3Query(
+            self._doqServerPort,
+            self._dohBaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            useQueue=useQueue,
+            serverName=self._serverName,
+            connection=connection,
+            passExceptions=passExceptions,
+        )
+
 
 class TestDOH3(DOH3Common, QUICTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doqServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doqServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -53,42 +65,49 @@ class TestDOH3(DOH3Common, QUICTests, DNSDistTest):
 
     addDOH3Local("127.0.0.1:%d", "%s", "%s", {keyLogFile='/tmp/keys'})
     """
-    _config_params = ['_testServerPort',  '_serverName', '_doqServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_serverName", "_doqServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
     _verboseMode = True
 
     def testHeaderRule(self):
         """
         DOH3: HeaderRule
         """
-        name = 'header-rule.doh3.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "header-rule.doh3.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '2.3.4.5')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "2.3.4.5")
         expectedResponse.answer.append(rrset)
 
         # this header should match
-        (_, receivedResponse) = self.sendDOH3Query(self._doqServerPort, self._dohBaseURL, query=query, response=None, useQueue=False, caFile=self._caCert, customHeaders={'x-powerdnS': 'aaaaa'})
+        (_, receivedResponse) = self.sendDOH3Query(
+            self._doqServerPort,
+            self._dohBaseURL,
+            query=query,
+            response=None,
+            useQueue=False,
+            caFile=self._caCert,
+            customHeaders={"x-powerdnS": "aaaaa"},
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.flags &= ~dns.flags.RD
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # this content of the header should NOT match
-        (receivedQuery, receivedResponse) = self.sendDOH3Query(self._doqServerPort, self._dohBaseURL, query, response=response, caFile=self._caCert, customHeaders={'x-powerdnS': 'bbbbb'})
+        (receivedQuery, receivedResponse) = self.sendDOH3Query(
+            self._doqServerPort,
+            self._dohBaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            customHeaders={"x-powerdnS": "bbbbb"},
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -100,35 +119,36 @@ class TestDOH3(DOH3Common, QUICTests, DNSDistTest):
         """
         DOH3: HTTPPath
         """
-        name = 'http-path.doh3.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "http-path.doh3.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '3.4.5.6')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "3.4.5.6")
         expectedResponse.answer.append(rrset)
 
         # this path should match
-        (_, receivedResponse) = self.sendDOH3Query(self._doqServerPort, self._dohBaseURL + 'PowerDNS', caFile=self._caCert, query=query, response=None, useQueue=False)
+        (_, receivedResponse) = self.sendDOH3Query(
+            self._doqServerPort,
+            self._dohBaseURL + "PowerDNS",
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
-        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        expectedQuery = dns.message.make_query(name, "A", "IN")
         expectedQuery.id = 0
         expectedQuery.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # this path should NOT match
-        (receivedQuery, receivedResponse) = self.sendDOH3Query(self._doqServerPort, self._dohBaseURL + "PowerDNS2", query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOH3Query(
+            self._doqServerPort, self._dohBaseURL + "PowerDNS2", query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -140,35 +160,36 @@ class TestDOH3(DOH3Common, QUICTests, DNSDistTest):
         """
         DOH3: HTTPPathRegex
         """
-        name = 'http-path-regex.doh3.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "http-path-regex.doh3.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 0
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '6.7.8.9')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "6.7.8.9")
         expectedResponse.answer.append(rrset)
 
         # this path should match
-        (_, receivedResponse) = self.sendDOH3Query(self._doqServerPort, self._dohBaseURL + 'PowerDNS-999', caFile=self._caCert, query=query, response=None, useQueue=False)
+        (_, receivedResponse) = self.sendDOH3Query(
+            self._doqServerPort,
+            self._dohBaseURL + "PowerDNS-999",
+            caFile=self._caCert,
+            query=query,
+            response=None,
+            useQueue=False,
+        )
         self.assertEqual(receivedResponse, expectedResponse)
 
-        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        expectedQuery = dns.message.make_query(name, "A", "IN")
         expectedQuery.id = 0
         expectedQuery.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # this path should NOT match
-        (receivedQuery, receivedResponse) = self.sendDOH3Query(self._doqServerPort, self._dohBaseURL + "PowerDNS2", query, response=response, caFile=self._caCert)
+        (receivedQuery, receivedResponse) = self.sendDOH3Query(
+            self._doqServerPort, self._dohBaseURL + "PowerDNS2", query, response=response, caFile=self._caCert
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
@@ -180,56 +201,81 @@ class TestDOH3(DOH3Common, QUICTests, DNSDistTest):
         """
         DOH3: HTTPStatusAction 200 OK
         """
-        name = 'http-status-action.doh3.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "http-status-action.doh3.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
 
-        (receivedResponse, receivedHeaders) = self.sendDOH3Query(self._doqServerPort, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, post=True, rawResponse=True)
+        (receivedResponse, receivedHeaders) = self.sendDOH3Query(
+            self._doqServerPort,
+            self._dohBaseURL,
+            query,
+            caFile=self._caCert,
+            useQueue=False,
+            post=True,
+            rawResponse=True,
+        )
         self.assertTrue(receivedResponse)
-        self.assertEqual(receivedResponse, b'Plaintext answer')
-        self.assertIn(b':status', receivedHeaders)
-        self.assertEqual(receivedHeaders[b':status'], b'200')
-        self.assertIn(b'content-type', receivedHeaders)
-        self.assertEqual(receivedHeaders[b'content-type'], b'text/plain')
+        self.assertEqual(receivedResponse, b"Plaintext answer")
+        self.assertIn(b":status", receivedHeaders)
+        self.assertEqual(receivedHeaders[b":status"], b"200")
+        self.assertIn(b"content-type", receivedHeaders)
+        self.assertEqual(receivedHeaders[b"content-type"], b"text/plain")
 
     def testHTTPStatusAction307(self):
         """
         DOH3: HTTPStatusAction 307
         """
-        name = 'http-status-action-redirect.doh3.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "http-status-action-redirect.doh3.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
 
-        (receivedResponse, receivedHeaders) = self.sendDOH3Query(self._doqServerPort, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, post=True, rawResponse=True)
+        (receivedResponse, receivedHeaders) = self.sendDOH3Query(
+            self._doqServerPort,
+            self._dohBaseURL,
+            query,
+            caFile=self._caCert,
+            useQueue=False,
+            post=True,
+            rawResponse=True,
+        )
         self.assertTrue(receivedResponse)
-        self.assertIn(b':status', receivedHeaders)
-        self.assertEqual(receivedHeaders[b':status'], b'307')
-        self.assertIn(b'location', receivedHeaders)
-        self.assertEqual(receivedHeaders[b'location'], b'https://doh.powerdns.org')
+        self.assertIn(b":status", receivedHeaders)
+        self.assertEqual(receivedHeaders[b":status"], b"307")
+        self.assertIn(b"location", receivedHeaders)
+        self.assertEqual(receivedHeaders[b"location"], b"https://doh.powerdns.org")
 
     def testHTTPLuaBindings(self):
         """
         DOH3: Lua HTTP bindings
         """
-        name = 'http-lua.doh3.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "http-lua.doh3.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
 
-        (receivedResponse, receivedHeaders) = self.sendDOH3Query(self._doqServerPort, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, post=True, rawResponse=True)
+        (receivedResponse, receivedHeaders) = self.sendDOH3Query(
+            self._doqServerPort,
+            self._dohBaseURL,
+            query,
+            caFile=self._caCert,
+            useQueue=False,
+            post=True,
+            rawResponse=True,
+        )
         self.assertTrue(receivedResponse)
-        self.assertEqual(receivedResponse, b'It works!')
-        self.assertIn(b':status', receivedHeaders)
-        self.assertEqual(receivedHeaders[b':status'], b'200')
-        self.assertIn(b'content-type', receivedHeaders)
-        self.assertEqual(receivedHeaders[b'content-type'], b'text/plain')
+        self.assertEqual(receivedResponse, b"It works!")
+        self.assertIn(b":status", receivedHeaders)
+        self.assertEqual(receivedHeaders[b":status"], b"200")
+        self.assertIn(b"content-type", receivedHeaders)
+        self.assertEqual(receivedHeaders[b"content-type"], b"text/plain")
+
 
 class TestDOH3Yaml(DOH3Common, QUICTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doqServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doqServerPort)
     _config_template = ""
     _config_params = []
     _yaml_config_template = """---
@@ -274,69 +320,76 @@ query_rules:
       type: "Pool"
       pool_name: "this-pool-has-no-backend"
     """
-    _yaml_config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _yaml_config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
+
 
 class TestDOH3ACL(DOH3Common, QUICACLTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doqServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doqServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
     setACL("192.0.2.1/32")
     addDOH3Local("127.0.0.1:%d", "%s", "%s", {keyLogFile='/tmp/keys'})
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
     _verboseMode = True
 
+
 class TestDOH3Specifics(DOH3Common, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doqServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doqServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
     addDOH3Local("127.0.0.1:%d", "%s", "%s", {keyLogFile='/tmp/keys'})
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
     _verboseMode = True
 
     def testDOH3Post(self):
         """
         QUIC: Simple POST query
         """
-        name = 'simple.post.doq.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.post.doq.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
-        (receivedQuery, receivedResponse) = self.sendDOH3Query(self._doqServerPort, self._dohBaseURL, query, response=response, caFile=self._caCert, serverName=self._serverName, post=True)
+        (receivedQuery, receivedResponse) = self.sendDOH3Query(
+            self._doqServerPort,
+            self._dohBaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            serverName=self._serverName,
+            post=True,
+        )
         self.assertTrue(receivedQuery)
         self.assertTrue(receivedResponse)
         receivedQuery.id = expectedQuery.id
         self.assertEqual(expectedQuery, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
+
 class TestDOH3GetLocalAddressOnAnyBind(DOH3Common, QUICGetLocalAddressOnAnyBindTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doqServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doqServerPort)
     _config_template = """
     function answerBasedOnLocalAddress(dq)
       local dest = tostring(dq.localaddr)
@@ -350,21 +403,30 @@ class TestDOH3GetLocalAddressOnAnyBind(DOH3Common, QUICGetLocalAddressOnAnyBindT
     addDOH3Local("0.0.0.0:%d", "%s", "%s")
     addDOH3Local("[::]:%d", "%s", "%s")
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey', '_doqServerPort','_serverCert', '_serverKey']
-    _acl = ['127.0.0.1/32', '::1/128']
+    _config_params = [
+        "_testServerPort",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
+    _acl = ["127.0.0.1/32", "::1/128"]
     _skipListeningOnCL = True
 
+
 class TestDOH3XFR(DOH3Common, QUICXFRTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doqServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doqServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d", tcpOnly=true}
 
     addDOH3Local("127.0.0.1:%d", "%s", "%s")
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
     _verboseMode = True
index e0a2f01e860b805cad883e88cfe1461a065c7255..46439b5373dfedb4e2a33b4494749b0591d5253f 100644 (file)
@@ -7,47 +7,61 @@ from dnsdisttests import pickAvailablePort
 from quictests import QUICTests, QUICWithCacheTests, QUICACLTests, QUICGetLocalAddressOnAnyBindTests, QUICXFRTests
 import doqclient
 
+
 class TestDOQBogus(DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
     addDOQLocal("127.0.0.1:%d", "%s", "%s")
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
 
     def testDOQBogus(self):
         """
         DOQ: Test a bogus query (wrong packed length)
         """
-        name = 'bogus.doq.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "bogus.doq.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
 
         try:
-            doqclient.quic_bogus_query(query, '127.0.0.1', 2.0, self._doqServerPort, verify=self._caCert, server_hostname=self._serverName)
+            doqclient.quic_bogus_query(
+                query, "127.0.0.1", 2.0, self._doqServerPort, verify=self._caCert, server_hostname=self._serverName
+            )
             self.fail()
-        except doqclient.StreamResetError as e :
-            self.assertEqual(e.error, 2);
+        except doqclient.StreamResetError as e:
+            self.assertEqual(e.error, 2)
+
 
 class DOQCommon(object):
     def getQUICConnection(self):
         return self.getDOQConnection(self._doqServerPort, self._caCert)
 
     def sendQUICQuery(self, query, response=None, useQueue=True, connection=None, passExceptions=False):
-        return self.sendDOQQuery(self._doqServerPort, query, response=response, caFile=self._caCert, useQueue=useQueue, serverName=self._serverName, connection=connection, passExceptions=passExceptions)
+        return self.sendDOQQuery(
+            self._doqServerPort,
+            query,
+            response=response,
+            caFile=self._caCert,
+            useQueue=useQueue,
+            serverName=self._serverName,
+            connection=connection,
+            passExceptions=passExceptions,
+        )
+
 
 class TestDOQ(DOQCommon, QUICTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -59,13 +73,14 @@ class TestDOQ(DOQCommon, QUICTests, DNSDistTest):
 
     addDOQLocal("127.0.0.1:%d", "%s", "%s")
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
+
 
 class TestDOQYaml(DOQCommon, QUICTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = ""
     _config_params = []
@@ -111,13 +126,14 @@ query_rules:
       type: "Pool"
       pool_name: "this-pool-has-no-backend"
     """
-    _yaml_config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _yaml_config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
+
 
 class TestDOQWithCache(DOQCommon, QUICWithCacheTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -127,13 +143,14 @@ class TestDOQWithCache(DOQCommon, QUICWithCacheTests, DNSDistTest):
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
+
 
 class TestDOQWithCacheAndBBR(DOQCommon, QUICWithCacheTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -145,13 +162,14 @@ class TestDOQWithCacheAndBBR(DOQCommon, QUICWithCacheTests, DNSDistTest):
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
+
 
 class TestDOQWithACL(DOQCommon, QUICACLTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -159,29 +177,31 @@ class TestDOQWithACL(DOQCommon, QUICACLTests, DNSDistTest):
     setACL("192.0.2.1/32")
     addDOQLocal("127.0.0.1:%d", "%s", "%s")
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
+
 
 class TestDOQXFR(DOQCommon, QUICXFRTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = """
     newServer{address="127.0.0.1:%d", tcpOnly=True}
 
     addDOQLocal("127.0.0.1:%d", "%s", "%s")
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_doqServerPort", "_serverCert", "_serverKey"]
     _verboseMode = True
 
+
 class TestDOQCertificateReloading(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _serverKey = 'server-doq.key'
-    _serverCert = 'server-doq.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _serverKey = "server-doq.key"
+    _serverCert = "server-doq.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = """
     setKey("%s")
@@ -191,33 +211,45 @@ class TestDOQCertificateReloading(DNSDistTest):
 
     addDOQLocal("127.0.0.1:%d", "%s", "%s")
     """
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
 
     @classmethod
     def setUpClass(cls):
-        cls.generateNewCertificateAndKey('server-doq')
+        cls.generateNewCertificateAndKey("server-doq")
         cls.startResponders()
         cls.startDNSDist()
         cls.setUpSockets()
 
     def testCertificateReloaded(self):
-        name = 'certificate-reload.doq.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "certificate-reload.doq.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        (_, serial) = doqclient.quic_query(query, '127.0.0.1', 0.5, self._doqServerPort, verify=self._caCert, server_hostname=self._serverName)
+        (_, serial) = doqclient.quic_query(
+            query, "127.0.0.1", 0.5, self._doqServerPort, verify=self._caCert, server_hostname=self._serverName
+        )
 
-        self.generateNewCertificateAndKey('server-doq')
+        self.generateNewCertificateAndKey("server-doq")
         self.sendConsoleCommand("reloadAllCertificates()")
 
-        (_, secondSerial) = doqclient.quic_query(query, '127.0.0.1', 0.5, self._doqServerPort, verify=self._caCert, server_hostname=self._serverName)
+        (_, secondSerial) = doqclient.quic_query(
+            query, "127.0.0.1", 0.5, self._doqServerPort, verify=self._caCert, server_hostname=self._serverName
+        )
         # check that the serial is different
         self.assertNotEqual(serial, secondSerial)
 
+
 class TestDOQGetLocalAddressOnAnyBind(DOQCommon, QUICGetLocalAddressOnAnyBindTests, DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = """
     function answerBasedOnLocalAddress(dq)
@@ -232,6 +264,14 @@ class TestDOQGetLocalAddressOnAnyBind(DOQCommon, QUICGetLocalAddressOnAnyBindTes
     addDOQLocal("0.0.0.0:%d", "%s", "%s")
     addDOQLocal("[::]:%d", "%s", "%s")
     """
-    _config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey', '_doqServerPort','_serverCert', '_serverKey']
-    _acl = ['127.0.0.1/32', '::1/128']
+    _config_params = [
+        "_testServerPort",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
+    _acl = ["127.0.0.1/32", "::1/128"]
     _skipListeningOnCL = True
index adb0f65112a673cf7b0e4d0ad6393353ff55627b..23395ae926195b69068bbc0696ca1c60276f4b31 100644 (file)
@@ -2,8 +2,8 @@
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestDeprecatedMakeRule(DNSDistTest):
 
+class TestDeprecatedMakeRule(DNSDistTest):
     _config_template = """
     addAction(makeRule("make-rule-suffix.deprecated.tests.powerdns.com."), SpoofAction("192.0.2.1"))
     addAction("string-suffix.deprecated.tests.powerdns.com.", SpoofAction("192.0.2.2"))
@@ -16,16 +16,12 @@ class TestDeprecatedMakeRule(DNSDistTest):
         """
         Deprecated: makeRule
         """
-        name = 'prefix.make-rule-suffix.deprecated.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "prefix.make-rule-suffix.deprecated.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -38,16 +34,12 @@ class TestDeprecatedMakeRule(DNSDistTest):
         """
         Deprecated: addAction string suffix
         """
-        name = 'another.prefix.string-suffix.deprecated.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "another.prefix.string-suffix.deprecated.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -60,16 +52,12 @@ class TestDeprecatedMakeRule(DNSDistTest):
         """
         Deprecated: addAction list of string suffixes
         """
-        name = 'yet.another.prefix.list-of-string-suffixes.deprecated.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "yet.another.prefix.list-of-string-suffixes.deprecated.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.3')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.3")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index 910498b1b20c308f7dd8e58c6ad0aeb6aa593359..aabfd3d5b251d84ad3212dddf819511aa17eae68 100644 (file)
@@ -19,69 +19,72 @@ FSTRM_CONTROL_FINISH = 0x05
 
 def checkDnstapBase(testinstance, dnstap, protocol, initiator, response_port):
     testinstance.assertTrue(dnstap)
-    testinstance.assertTrue(dnstap.HasField('identity'))
-    testinstance.assertEqual(dnstap.identity, b'a.server')
-    testinstance.assertTrue(dnstap.HasField('version'))
-    testinstance.assertIn(b'dnsdist ', dnstap.version)
-    testinstance.assertTrue(dnstap.HasField('type'))
+    testinstance.assertTrue(dnstap.HasField("identity"))
+    testinstance.assertEqual(dnstap.identity, b"a.server")
+    testinstance.assertTrue(dnstap.HasField("version"))
+    testinstance.assertIn(b"dnsdist ", dnstap.version)
+    testinstance.assertTrue(dnstap.HasField("type"))
     testinstance.assertEqual(dnstap.type, dnstap.MESSAGE)
-    testinstance.assertTrue(dnstap.HasField('message'))
-    testinstance.assertTrue(dnstap.message.HasField('socket_protocol'))
+    testinstance.assertTrue(dnstap.HasField("message"))
+    testinstance.assertTrue(dnstap.message.HasField("socket_protocol"))
     testinstance.assertEqual(dnstap.message.socket_protocol, protocol)
-    testinstance.assertTrue(dnstap.message.HasField('socket_family'))
+    testinstance.assertTrue(dnstap.message.HasField("socket_family"))
     testinstance.assertEqual(dnstap.message.socket_family, dnstap_pb2.INET)
-    testinstance.assertTrue(dnstap.message.HasField('query_address'))
+    testinstance.assertTrue(dnstap.message.HasField("query_address"))
     testinstance.assertEqual(socket.inet_ntop(socket.AF_INET, dnstap.message.query_address), initiator)
-    testinstance.assertTrue(dnstap.message.HasField('response_address'))
+    testinstance.assertTrue(dnstap.message.HasField("response_address"))
     testinstance.assertEqual(socket.inet_ntop(socket.AF_INET, dnstap.message.response_address), initiator)
-    testinstance.assertTrue(dnstap.message.HasField('response_port'))
+    testinstance.assertTrue(dnstap.message.HasField("response_port"))
     testinstance.assertEqual(dnstap.message.response_port, response_port)
 
 
-def checkDnstapQuery(testinstance, dnstap, protocol, query, initiator='127.0.0.1', response_port=0, http_protocol=0):
+def checkDnstapQuery(testinstance, dnstap, protocol, query, initiator="127.0.0.1", response_port=0, http_protocol=0):
 
     testinstance.assertEqual(dnstap.message.type, dnstap_pb2.Message.CLIENT_QUERY)
-    if response_port == 0 :
+    if response_port == 0:
         response_port = testinstance._dnsDistPort
 
     checkDnstapBase(testinstance, dnstap, protocol, initiator, response_port)
 
-    testinstance.assertTrue(dnstap.message.HasField('query_time_sec'))
-    testinstance.assertTrue(dnstap.message.HasField('query_time_nsec'))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_sec"))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_nsec"))
 
-    if http_protocol != 0 :
-        testinstance.assertTrue(dnstap.message.HasField('http_protocol'))
+    if http_protocol != 0:
+        testinstance.assertTrue(dnstap.message.HasField("http_protocol"))
         testinstance.assertEqual(dnstap.message.http_protocol, http_protocol)
 
-    testinstance.assertTrue(dnstap.message.HasField('query_message'))
+    testinstance.assertTrue(dnstap.message.HasField("query_message"))
     wire_message = dns.message.from_wire(dnstap.message.query_message)
     testinstance.assertEqual(wire_message, query)
 
 
 def checkDnstapExtra(testinstance, dnstap, expected):
-    testinstance.assertTrue(dnstap.HasField('extra'))
+    testinstance.assertTrue(dnstap.HasField("extra"))
     testinstance.assertEqual(dnstap.extra, expected)
 
+
 def checkDnstapNoExtra(testinstance, dnstap):
-    testinstance.assertFalse(dnstap.HasField('extra'))
+    testinstance.assertFalse(dnstap.HasField("extra"))
 
 
-def checkDnstapResponse(testinstance, dnstap, protocol, response, initiator='127.0.0.1', response_port=0):
+def checkDnstapResponse(testinstance, dnstap, protocol, response, initiator="127.0.0.1", response_port=0):
     testinstance.assertEqual(dnstap.message.type, dnstap_pb2.Message.CLIENT_RESPONSE)
-    if response_port == 0 :
+    if response_port == 0:
         response_port = testinstance._dnsDistPort
     checkDnstapBase(testinstance, dnstap, protocol, initiator, response_port)
 
-    testinstance.assertTrue(dnstap.message.HasField('query_time_sec'))
-    testinstance.assertTrue(dnstap.message.HasField('query_time_nsec'))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_sec"))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_nsec"))
 
-    testinstance.assertTrue(dnstap.message.HasField('response_time_sec'))
-    testinstance.assertTrue(dnstap.message.HasField('response_time_nsec'))
+    testinstance.assertTrue(dnstap.message.HasField("response_time_sec"))
+    testinstance.assertTrue(dnstap.message.HasField("response_time_nsec"))
 
-    testinstance.assertTrue(dnstap.message.response_time_sec > dnstap.message.query_time_sec or \
-        dnstap.message.response_time_nsec > dnstap.message.query_time_nsec)
+    testinstance.assertTrue(
+        dnstap.message.response_time_sec > dnstap.message.query_time_sec
+        or dnstap.message.response_time_nsec > dnstap.message.query_time_nsec
+    )
 
-    testinstance.assertTrue(dnstap.message.HasField('response_message'))
+    testinstance.assertTrue(dnstap.message.HasField("response_message"))
     wire_message = dns.message.from_wire(dnstap.message.response_message)
     testinstance.assertEqual(wire_message, response)
 
@@ -109,11 +112,12 @@ def getFirstMatchingMessageFromQueue(queue, messageType=None):
 
     return selected
 
+
 class TestDnstapOverRemoteLogger(DNSDistTest):
     _remoteLoggerServerPort = pickAvailablePort()
     _remoteLoggerQueue = Queue()
     _remoteLoggerCounter = 0
-    _config_params = ['_testServerPort', '_remoteLoggerServerPort']
+    _config_params = ["_testServerPort", "_remoteLoggerServerPort"]
     _config_template = """
     extrasmn = newSuffixMatchNode()
     extrasmn:add(newDNSName('extra.dnstap.tests.powerdns.com.'))
@@ -181,7 +185,9 @@ class TestDnstapOverRemoteLogger(DNSDistTest):
     def startResponders(cls):
         DNSDistTest.startResponders()
 
-        cls._remoteLoggerListener = threading.Thread(name='RemoteLogger Listener', target=cls.RemoteLoggerListener, args=[cls._remoteLoggerServerPort])
+        cls._remoteLoggerListener = threading.Thread(
+            name="RemoteLogger Listener", target=cls.RemoteLoggerListener, args=[cls._remoteLoggerServerPort]
+        )
         cls._remoteLoggerListener.daemon = True
         cls._remoteLoggerListener.start()
 
@@ -192,24 +198,16 @@ class TestDnstapOverRemoteLogger(DNSDistTest):
         """
         Dnstap: Send query and responses packed in dnstap to a remotelogger server
         """
-        name = 'query.dnstap.tests.powerdns.com.'
+        name = "query.dnstap.tests.powerdns.com."
 
-        target = 'target.dnstap.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        target = "target.dnstap.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    target)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(target,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -258,24 +256,16 @@ class TestDnstapOverRemoteLogger(DNSDistTest):
         """
         DnstapExtra: Send query and responses packed in dnstap to a remotelogger server. Extra data is filled out.
         """
-        name = 'extra.dnstap.tests.powerdns.com.'
+        name = "extra.dnstap.tests.powerdns.com."
 
-        target = 'target.dnstap.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        target = "target.dnstap.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    target)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(target,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -318,12 +308,13 @@ class TestDnstapOverRemoteLogger(DNSDistTest):
         checkDnstapResponse(self, dnstap, dnstap_pb2.TCP, response)
         checkDnstapExtra(self, dnstap, b"Type,Response")
 
+
 class TestDnstapOverRemoteLoggerPool(DNSDistTest):
     _remoteLoggerServerPort = pickAvailablePort()
     _remoteLoggerQueue = Queue()
     _remoteLoggerCounter = 0
     _poolConnectionCount = 8
-    _config_params = ['_testServerPort', '_remoteLoggerServerPort', '_poolConnectionCount']
+    _config_params = ["_testServerPort", "_remoteLoggerServerPort", "_poolConnectionCount"]
     _config_template = """
     extrasmn = newSuffixMatchNode()
     extrasmn:add(newDNSName('extra.dnstap.tests.powerdns.com.'))
@@ -404,7 +395,9 @@ class TestDnstapOverRemoteLoggerPool(DNSDistTest):
     def startResponders(cls):
         DNSDistTest.startResponders()
 
-        cls._remoteLoggerListener = threading.Thread(name='RemoteLogger Listener', target=cls.RemoteLoggerListener, args=[cls._remoteLoggerServerPort])
+        cls._remoteLoggerListener = threading.Thread(
+            name="RemoteLogger Listener", target=cls.RemoteLoggerListener, args=[cls._remoteLoggerServerPort]
+        )
         cls._remoteLoggerListener.daemon = True
         cls._remoteLoggerListener.start()
 
@@ -415,24 +408,16 @@ class TestDnstapOverRemoteLoggerPool(DNSDistTest):
         """
         Dnstap: Send query and responses packed in dnstap to a remotelogger server
         """
-        name = 'query.dnstap.tests.powerdns.com.'
+        name = "query.dnstap.tests.powerdns.com."
 
-        target = 'target.dnstap.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        target = "target.dnstap.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    target)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(target,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -481,24 +466,16 @@ class TestDnstapOverRemoteLoggerPool(DNSDistTest):
         """
         DnstapExtra: Send query and responses packed in dnstap to a remotelogger server. Extra data is filled out.
         """
-        name = 'extra.dnstap.tests.powerdns.com.'
+        name = "extra.dnstap.tests.powerdns.com."
 
-        target = 'target.dnstap.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        target = "target.dnstap.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    target)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(target,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -542,7 +519,6 @@ class TestDnstapOverRemoteLoggerPool(DNSDistTest):
         checkDnstapExtra(self, dnstap, b"Type,Response")
 
 
-
 def fstrm_get_control_frame_type(data):
     (t,) = struct.unpack("!L", data[0:4])
     return t
@@ -551,21 +527,20 @@ def fstrm_get_control_frame_type(data):
 def fstrm_make_control_frame_reply(cft, data):
     if cft == FSTRM_CONTROL_READY:
         # Reply with ACCEPT frame and content-type
-        contenttype = b'protobuf:dnstap.Dnstap'
-        frame = struct.pack('!LLL', FSTRM_CONTROL_ACCEPT, 1,
-                            len(contenttype)) + contenttype
+        contenttype = b"protobuf:dnstap.Dnstap"
+        frame = struct.pack("!LLL", FSTRM_CONTROL_ACCEPT, 1, len(contenttype)) + contenttype
         buf = struct.pack("!LL", 0, len(frame)) + frame
         return buf
     elif cft == FSTRM_CONTROL_START:
         return None
     else:
-        raise Exception('unhandled control frame ' + cft)
+        raise Exception("unhandled control frame " + cft)
 
 
 def fstrm_read_and_dispatch_control_frame(conn):
     data = conn.recv(4)
     if not data:
-        raise Exception('length of control frame payload could not be read')
+        raise Exception("length of control frame payload could not be read")
     (datalen,) = struct.unpack("!L", data)
     data = conn.recv(datalen)
     cft = fstrm_get_control_frame_type(data)
@@ -597,19 +572,29 @@ def fstrm_handle_bidir_connection(conn, on_data, exit_early=False):
             if exit_early:
                 break
 
+
 class TestDnstapOverFrameStreamUnixLogger(DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
     _doh3ServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
 
-    _fstrmLoggerAddress = '/tmp/fslutest.sock'
+    _fstrmLoggerAddress = "/tmp/fslutest.sock"
     _fstrmLoggerQueue = Queue()
     _fstrmLoggerCounter = 0
-    _config_params = ['_testServerPort', '_fstrmLoggerAddress', '_dohServerPort', '_serverCert', '_serverKey', '_doh3ServerPort', '_serverCert', '_serverKey']
+    _config_params = [
+        "_testServerPort",
+        "_fstrmLoggerAddress",
+        "_dohServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doh3ServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
     _config_template = """
     newServer{address="127.0.0.1:%d", useClientSubnet=true}
     fslu = newFrameStreamUnixLogger('%s')
@@ -636,8 +621,7 @@ class TestDnstapOverFrameStreamUnixLogger(DNSDistTest):
         try:
             while True:
                 (conn, _) = sock.accept()
-                fstrm_handle_bidir_connection(conn, lambda data: \
-                    cls._fstrmLoggerQueue.put(data, True, timeout=2.0))
+                fstrm_handle_bidir_connection(conn, lambda data: cls._fstrmLoggerQueue.put(data, True, timeout=2.0))
                 conn.close()
         finally:
             sock.close()
@@ -646,7 +630,9 @@ class TestDnstapOverFrameStreamUnixLogger(DNSDistTest):
     def startResponders(cls):
         DNSDistTest.startResponders()
 
-        cls._fstrmLoggerListener = threading.Thread(name='FrameStreamUnixListener', target=cls.FrameStreamUnixListener, args=[cls._fstrmLoggerAddress])
+        cls._fstrmLoggerListener = threading.Thread(
+            name="FrameStreamUnixListener", target=cls.FrameStreamUnixListener, args=[cls._fstrmLoggerAddress]
+        )
         cls._fstrmLoggerListener.daemon = True
         cls._fstrmLoggerListener.start()
 
@@ -657,24 +643,16 @@ class TestDnstapOverFrameStreamUnixLogger(DNSDistTest):
         """
         Dnstap: Send query packed in dnstap to a unix socket fstrmlogger server
         """
-        name = 'query.dnstap.tests.powerdns.com.'
+        name = "query.dnstap.tests.powerdns.com."
 
-        target = 'target.dnstap.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        target = "target.dnstap.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    target)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(target,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -694,24 +672,28 @@ class TestDnstapOverFrameStreamUnixLogger(DNSDistTest):
         """
         DOH and DOH3: Make sure http protocol field is correctly set
         """
-        name = 'simple.doh.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.doh.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         protocols = [
-            {"method": "sendDOH3QueryWrapper", "port": self._doh3ServerPort, "expected_protocol": dnstap_pb2.HttpProtocol.HTTP3},
-            {"method": "sendDOHQueryWrapper",  "port": self._dohServerPort,  "expected_protocol": dnstap_pb2.HttpProtocol.HTTP2},
+            {
+                "method": "sendDOH3QueryWrapper",
+                "port": self._doh3ServerPort,
+                "expected_protocol": dnstap_pb2.HttpProtocol.HTTP3,
+            },
+            {
+                "method": "sendDOHQueryWrapper",
+                "port": self._dohServerPort,
+                "expected_protocol": dnstap_pb2.HttpProtocol.HTTP2,
+            },
         ]
-        for protocol in protocols :
+        for protocol in protocols:
             sender = getattr(self, protocol["method"])
             (receivedQuery, receivedResponse) = sender(query, response)
             receivedQuery.id = query.id
@@ -721,15 +703,18 @@ class TestDnstapOverFrameStreamUnixLogger(DNSDistTest):
             # check the dnstap message corresponding to the UDP query
             dnstap = self.getFirstDnstap()
 
-            checkDnstapQuery(self, dnstap, dnstap_pb2.DOH, query, '127.0.0.1', protocol["port"], protocol["expected_protocol"])
+            checkDnstapQuery(
+                self, dnstap, dnstap_pb2.DOH, query, "127.0.0.1", protocol["port"], protocol["expected_protocol"]
+            )
             checkDnstapNoExtra(self, dnstap)
 
+
 class TestDnstapOverRemotePoolUnixLogger(DNSDistTest):
-    _fstrmLoggerAddress = '/tmp/fslutest.sock'
+    _fstrmLoggerAddress = "/tmp/fslutest.sock"
     _fstrmLoggerQueue = Queue()
     _fstrmLoggerCounter = 0
     _poolConnectionCount = 5
-    _config_params = ['_testServerPort', '_fstrmLoggerAddress', '_poolConnectionCount']
+    _config_params = ["_testServerPort", "_fstrmLoggerAddress", "_poolConnectionCount"]
     _config_template = """
     newServer{address="127.0.0.1:%d", useClientSubnet=true}
     fslu = newFrameStreamUnixLogger('%s', { connectionCount = %d })
@@ -753,8 +738,9 @@ class TestDnstapOverRemotePoolUnixLogger(DNSDistTest):
         sock.listen(100)
 
         def handle_connection(conn):
-            fstrm_handle_bidir_connection(conn, lambda data: \
-                cls._fstrmLoggerQueue.put(data, True, timeout=2.0), exit_early=True)
+            fstrm_handle_bidir_connection(
+                conn, lambda data: cls._fstrmLoggerQueue.put(data, True, timeout=2.0), exit_early=True
+            )
             conn.close()
 
         threads = []
@@ -775,7 +761,9 @@ class TestDnstapOverRemotePoolUnixLogger(DNSDistTest):
     def startResponders(cls):
         DNSDistTest.startResponders()
 
-        cls._fstrmLoggerListener = threading.Thread(name='FrameStreamUnixListener', target=cls.FrameStreamUnixListener, args=[cls._fstrmLoggerAddress])
+        cls._fstrmLoggerListener = threading.Thread(
+            name="FrameStreamUnixListener", target=cls.FrameStreamUnixListener, args=[cls._fstrmLoggerAddress]
+        )
         cls._fstrmLoggerListener.daemon = True
         cls._fstrmLoggerListener.start()
 
@@ -787,24 +775,16 @@ class TestDnstapOverRemotePoolUnixLogger(DNSDistTest):
         Dnstap: Send query packed in dnstap to a unix socket fstrmlogger server
         """
         for i in range(self._poolConnectionCount):
-            name = 'query.dnstap.tests.powerdns.com.'
+            name = "query.dnstap.tests.powerdns.com."
 
-            target = 'target.dnstap.tests.powerdns.com.'
-            query = dns.message.make_query(name, 'A', 'IN')
+            target = "target.dnstap.tests.powerdns.com."
+            query = dns.message.make_query(name, "A", "IN")
             response = dns.message.make_response(query)
 
-            rrset = dns.rrset.from_text(name,
-                                        3600,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.CNAME,
-                                        target)
+            rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
             response.answer.append(rrset)
 
-            rrset = dns.rrset.from_text(target,
-                                        3600,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.A,
-                                        '127.0.0.1')
+            rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
             response.answer.append(rrset)
 
             (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -825,7 +805,7 @@ class TestDnstapOverFrameStreamTcpLogger(DNSDistTest):
     _fstrmLoggerPort = pickAvailablePort()
     _fstrmLoggerQueue = Queue()
     _fstrmLoggerCounter = 0
-    _config_params = ['_testServerPort', '_fstrmLoggerPort']
+    _config_params = ["_testServerPort", "_fstrmLoggerPort"]
     _config_template = """
     newServer{address="127.0.0.1:%d", useClientSubnet=true}
     fslu = newFrameStreamTcpLogger('127.0.0.1:%d')
@@ -847,8 +827,7 @@ class TestDnstapOverFrameStreamTcpLogger(DNSDistTest):
         try:
             while True:
                 (conn, _) = sock.accept()
-                fstrm_handle_bidir_connection(conn, lambda data: \
-                    cls._fstrmLoggerQueue.put(data, True, timeout=2.0))
+                fstrm_handle_bidir_connection(conn, lambda data: cls._fstrmLoggerQueue.put(data, True, timeout=2.0))
                 conn.close()
         finally:
             sock.close()
@@ -857,7 +836,9 @@ class TestDnstapOverFrameStreamTcpLogger(DNSDistTest):
     def startResponders(cls):
         DNSDistTest.startResponders()
 
-        cls._fstrmLoggerListener = threading.Thread(name='FrameStreamTcpListener', target=cls.FrameStreamTcpListener, args=[cls._fstrmLoggerPort])
+        cls._fstrmLoggerListener = threading.Thread(
+            name="FrameStreamTcpListener", target=cls.FrameStreamTcpListener, args=[cls._fstrmLoggerPort]
+        )
         cls._fstrmLoggerListener.daemon = True
         cls._fstrmLoggerListener.start()
 
@@ -868,24 +849,16 @@ class TestDnstapOverFrameStreamTcpLogger(DNSDistTest):
         """
         Dnstap: Send query packed in dnstap to a tcp socket fstrmlogger server
         """
-        name = 'query.dnstap.tests.powerdns.com.'
+        name = "query.dnstap.tests.powerdns.com."
 
-        target = 'target.dnstap.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        target = "target.dnstap.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    target)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(target,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -901,12 +874,13 @@ class TestDnstapOverFrameStreamTcpLogger(DNSDistTest):
         checkDnstapQuery(self, dnstap, dnstap_pb2.UDP, query)
         checkDnstapNoExtra(self, dnstap)
 
+
 class TestDnstapOverFrameStreamTcpLoggerYAML(DNSDistTest):
     _fstrmLoggerPort = pickAvailablePort()
     _fstrmLoggerQueue = Queue()
     _fstrmLoggerCounter = 0
     _config_params = []
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort', '_fstrmLoggerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort", "_fstrmLoggerPort"]
     _yaml_config_template = """
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -947,8 +921,7 @@ query_rules:
         try:
             while True:
                 (conn, _) = sock.accept()
-                fstrm_handle_bidir_connection(conn, lambda data: \
-                    cls._fstrmLoggerQueue.put(data, True, timeout=2.0))
+                fstrm_handle_bidir_connection(conn, lambda data: cls._fstrmLoggerQueue.put(data, True, timeout=2.0))
                 conn.close()
         finally:
             sock.close()
@@ -957,7 +930,9 @@ query_rules:
     def startResponders(cls):
         DNSDistTest.startResponders()
 
-        cls._fstrmLoggerListener = threading.Thread(name='FrameStreamTcpListener', target=cls.FrameStreamTcpListener, args=[cls._fstrmLoggerPort])
+        cls._fstrmLoggerListener = threading.Thread(
+            name="FrameStreamTcpListener", target=cls.FrameStreamTcpListener, args=[cls._fstrmLoggerPort]
+        )
         cls._fstrmLoggerListener.daemon = True
         cls._fstrmLoggerListener.start()
 
@@ -968,24 +943,16 @@ query_rules:
         """
         Dnstap: Send query packed in dnstap to a tcp socket fstrmlogger server
         """
-        name = 'query.dnstap-yaml.tests.powerdns.com.'
+        name = "query.dnstap-yaml.tests.powerdns.com."
 
-        target = 'target.dnstap-yaml.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        target = "target.dnstap-yaml.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    target)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(target,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -1001,12 +968,13 @@ query_rules:
         checkDnstapQuery(self, dnstap, dnstap_pb2.UDP, query)
         checkDnstapNoExtra(self, dnstap)
 
+
 class TestDnstapOverRemotePoolTcpLogger(DNSDistTest):
     _fstrmLoggerPort = pickAvailablePort()
     _fstrmLoggerQueue = Queue()
     _fstrmLoggerCounter = 0
     _poolConnectionCount = 5
-    _config_params = ['_testServerPort', '_fstrmLoggerPort', '_poolConnectionCount']
+    _config_params = ["_testServerPort", "_fstrmLoggerPort", "_poolConnectionCount"]
     _config_template = """
     newServer{address="127.0.0.1:%d", useClientSubnet=true}
     fslu = newFrameStreamTcpLogger('127.0.0.1:%d', { connectionCount = %d })
@@ -1026,8 +994,9 @@ class TestDnstapOverRemotePoolTcpLogger(DNSDistTest):
         sock.listen(100)
 
         def handle_connection(conn):
-            fstrm_handle_bidir_connection(conn, lambda data: \
-                cls._fstrmLoggerQueue.put(data, True, timeout=2.0), exit_early=True)
+            fstrm_handle_bidir_connection(
+                conn, lambda data: cls._fstrmLoggerQueue.put(data, True, timeout=2.0), exit_early=True
+            )
             conn.close()
 
         threads = []
@@ -1048,7 +1017,9 @@ class TestDnstapOverRemotePoolTcpLogger(DNSDistTest):
     def startResponders(cls):
         DNSDistTest.startResponders()
 
-        cls._fstrmLoggerListener = threading.Thread(name='FrameStreamTcpListener', target=cls.FrameStreamTcpListener, args=[cls._fstrmLoggerPort])
+        cls._fstrmLoggerListener = threading.Thread(
+            name="FrameStreamTcpListener", target=cls.FrameStreamTcpListener, args=[cls._fstrmLoggerPort]
+        )
         cls._fstrmLoggerListener.daemon = True
         cls._fstrmLoggerListener.start()
 
@@ -1060,24 +1031,16 @@ class TestDnstapOverRemotePoolTcpLogger(DNSDistTest):
         Dnstap: Send query packed in dnstap to a tcp socket fstrmlogger server
         """
         for i in range(self._poolConnectionCount):
-            name = 'query.dnstap.tests.powerdns.com.'
+            name = "query.dnstap.tests.powerdns.com."
 
-            target = 'target.dnstap.tests.powerdns.com.'
-            query = dns.message.make_query(name, 'A', 'IN')
+            target = "target.dnstap.tests.powerdns.com."
+            query = dns.message.make_query(name, "A", "IN")
             response = dns.message.make_response(query)
 
-            rrset = dns.rrset.from_text(name,
-                                        3600,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.CNAME,
-                                        target)
+            rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
             response.answer.append(rrset)
 
-            rrset = dns.rrset.from_text(target,
-                                        3600,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.A,
-                                        '127.0.0.1')
+            rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
             response.answer.append(rrset)
 
             (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
index 1361cb26137af6e876894c222ce847c40d5920d1..52c6d04c47448c18f9c70650066122b052bf6d30 100644 (file)
@@ -4,8 +4,8 @@ import dns
 from dnsdisttests import DNSDistTest
 from dnsdistDynBlockTests import DynBlocksTest, waitForMaintenanceToRun, _maintenanceWaitTime
 
-class TestDynBlockQPS(DynBlocksTest):
 
+class TestDynBlockQPS(DynBlocksTest):
     _config_template = """
     function maintenance()
            addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d)
@@ -14,17 +14,25 @@ class TestDynBlockQPS(DynBlocksTest):
     webserver("127.0.0.1:%d")
     setWebserverConfig({password="%s", apiKey="%s"})
     """
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_dynBlockQPS",
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
 
     def testDynBlocksQRate(self):
         """
         Dyn Blocks: QRate
         """
-        name = 'qrate.dynblocks.tests.powerdns.com.'
+        name = "qrate.dynblocks.tests.powerdns.com."
         self.doTestQRate(name)
 
-class TestDynBlockQPSRefused(DynBlocksTest):
 
+class TestDynBlockQPSRefused(DynBlocksTest):
     _config_template = """
     function maintenance()
            addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d)
@@ -37,11 +45,11 @@ class TestDynBlockQPSRefused(DynBlocksTest):
         """
         Dyn Blocks: QRate refused
         """
-        name = 'qraterefused.dynblocks.tests.powerdns.com.'
+        name = "qraterefused.dynblocks.tests.powerdns.com."
         self.doTestQRateRCode(name, dns.rcode.REFUSED)
 
-class TestDynBlockQPSActionRefused(DynBlocksTest):
 
+class TestDynBlockQPSActionRefused(DynBlocksTest):
     _config_template = """
     function maintenance()
            addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Refused)
@@ -54,11 +62,11 @@ class TestDynBlockQPSActionRefused(DynBlocksTest):
         """
         Dyn Blocks: QRate refused (action)
         """
-        name = 'qrateactionrefused.dynblocks.tests.powerdns.com.'
+        name = "qrateactionrefused.dynblocks.tests.powerdns.com."
         self.doTestQRateRCode(name, dns.rcode.REFUSED)
 
-class TestDynBlockQPSActionNXD(DynBlocksTest):
 
+class TestDynBlockQPSActionNXD(DynBlocksTest):
     _config_template = """
     function maintenance()
            addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Nxdomain)
@@ -71,16 +79,16 @@ class TestDynBlockQPSActionNXD(DynBlocksTest):
         """
         Dyn Blocks: QRate NXD (action)
         """
-        name = 'qrateactionnxd.dynblocks.tests.powerdns.com.'
+        name = "qrateactionnxd.dynblocks.tests.powerdns.com."
         self.doTestQRateRCode(name, dns.rcode.NXDOMAIN)
 
-class TestDynBlockQPSActionTruncated(DNSDistTest):
 
+class TestDynBlockQPSActionTruncated(DNSDistTest):
     _dynBlockQPS = 10
     _dynBlockPeriod = 2
     # this needs to be greater than maintenanceWaitTime
     _dynBlockDuration = _maintenanceWaitTime + 1
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _config_params = ["_dynBlockQPS", "_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
     _config_template = """
     function maintenance()
            addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Truncate)
@@ -93,16 +101,12 @@ class TestDynBlockQPSActionTruncated(DNSDistTest):
         """
         Dyn Blocks: QRate truncated (action)
         """
-        name = 'qrateactiontruncated.dynblocks.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "qrateactiontruncated.dynblocks.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         truncatedResponse = dns.message.make_response(query)
         truncatedResponse.flags |= dns.flags.TC
@@ -164,8 +168,8 @@ class TestDynBlockQPSActionTruncated(DNSDistTest):
 
         self.assertEqual(allowed, sent)
 
-class TestDynBlockAllowlist(DynBlocksTest):
 
+class TestDynBlockAllowlist(DynBlocksTest):
     _config_template = """
     allowlisted = false
     function maintenance()
@@ -196,14 +200,10 @@ class TestDynBlockAllowlist(DynBlocksTest):
         """
         Dyn Blocks: Allowlisted from the dynamic blocks
         """
-        name = 'allowlisted.dynblocks.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "allowlisted.dynblocks.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         allowed = 0
@@ -233,16 +233,12 @@ class TestDynBlockAllowlist(DynBlocksTest):
         self.assertEqual(receivedResponse, receivedResponse)
 
         # check that we would have been blocked without the allowlisting
-        name = 'allowlisted-test.dynblocks.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "allowlisted-test.dynblocks.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.42')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.42")
         expectedResponse.answer.append(rrset)
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, expectedResponse)
index bf23f33eddc7d1185621dc84a80ac6f153193442..261c40302feb176ad55e33661189973a69b47b21 100644 (file)
@@ -3,9 +3,9 @@ import os
 import unittest
 from dnsdistDynBlockTests import DynBlocksTest
 
-@unittest.skipUnless('ENABLE_SUDO_TESTS' in os.environ, "sudo is not available")
-class TestDynBlockEBPFQPS(DynBlocksTest):
 
+@unittest.skipUnless("ENABLE_SUDO_TESTS" in os.environ, "sudo is not available")
+class TestDynBlockEBPFQPS(DynBlocksTest):
     _config_template = """
     bpf = newBPFFilter({ipv4MaxItems=10, ipv6MaxItems=10, qnamesMaxItems=10})
     setDefaultBPFFilter(bpf)
@@ -29,12 +29,20 @@ class TestDynBlockEBPFQPS(DynBlocksTest):
     webserver("127.0.0.1:%d")
     setWebserverConfig({password="%s", apiKey="%s"})
     """
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_dynBlockQPS",
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _sudoMode = True
 
     def testDynBlocksQRate(self):
         """
         Dyn Blocks: QRate
         """
-        name = 'qrate.dynblocks.tests.powerdns.com.'
+        name = "qrate.dynblocks.tests.powerdns.com."
         self.doTestQRate(name, ebpf=True)
index 08c98388dc01670191556151506bb4ec65144f3b..95bd85cf73de8bd8a7e115d2d5f6d88e275fbb54 100644 (file)
@@ -5,8 +5,8 @@ import dns
 from dnsdisttests import DNSDistTest
 from dnsdistDynBlockTests import DynBlocksTest, waitForMaintenanceToRun, _maintenanceWaitTime
 
-class TestDynBlockGroupQPS(DynBlocksTest):
 
+class TestDynBlockGroupQPS(DynBlocksTest):
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
@@ -18,17 +18,25 @@ class TestDynBlockGroupQPS(DynBlocksTest):
     webserver("127.0.0.1:%s")
     setWebserverConfig({password="%s", apiKey="%s"})
     """
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_dynBlockQPS",
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
 
     def testDynBlocksQRate(self):
         """
         Dyn Blocks (Group): QRate
         """
-        name = 'qrate.group.dynblocks.tests.powerdns.com.'
+        name = "qrate.group.dynblocks.tests.powerdns.com."
         self.doTestQRate(name)
 
-class TestDynBlockGroupQTypeRate(DynBlocksTest):
 
+class TestDynBlockGroupQTypeRate(DynBlocksTest):
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setQTypeRate(DNSQType.ANY, %d, %d, "Exceeded qtype rate", %d)
@@ -39,17 +47,17 @@ class TestDynBlockGroupQTypeRate(DynBlocksTest):
     setDynBlocksAction(DNSAction.Refused)
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_dynBlockANYQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _config_params = ["_dynBlockANYQPS", "_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
 
     def testDynBlocksQTypeRate(self):
         """
         Dyn Blocks (Group): QType Rate
         """
-        name = 'qtype-rate.group.dynblocks.tests.powerdns.com.'
+        name = "qtype-rate.group.dynblocks.tests.powerdns.com."
         self.doTestQTypeRate(name)
 
-class TestDynBlockGroupQTypeRateYAML(DynBlocksTest):
 
+class TestDynBlockGroupQTypeRateYAML(DynBlocksTest):
     _yaml_config_template = """---
 dynamic_rules:
   - name: "Block client generating too many ANY queries"
@@ -67,17 +75,17 @@ backends:
     protocol: Do53
 """
     _config_params = []
-    _yaml_config_params = ['_dynBlockANYQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _yaml_config_params = ["_dynBlockANYQPS", "_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
 
     def testDynBlocksQTypeRate(self):
         """
         Dyn Blocks (Group / YAML): QType Rate
         """
-        name = 'qtype-rate-yaml.group.dynblocks.tests.powerdns.com.'
+        name = "qtype-rate-yaml.group.dynblocks.tests.powerdns.com."
         self.doTestQTypeRate(name)
 
-class TestDynBlockGroupQPSRefused(DynBlocksTest):
 
+class TestDynBlockGroupQPSRefused(DynBlocksTest):
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
@@ -93,11 +101,11 @@ class TestDynBlockGroupQPSRefused(DynBlocksTest):
         """
         Dyn Blocks (Group): QRate refused
         """
-        name = 'qraterefused.group.dynblocks.tests.powerdns.com.'
+        name = "qraterefused.group.dynblocks.tests.powerdns.com."
         self.doTestQRateRCode(name, dns.rcode.REFUSED)
 
-class TestDynBlockGroupQPSActionRefused(DynBlocksTest):
 
+class TestDynBlockGroupQPSActionRefused(DynBlocksTest):
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.Refused)
@@ -113,11 +121,11 @@ class TestDynBlockGroupQPSActionRefused(DynBlocksTest):
         """
         Dyn Blocks (group): QRate refused (action)
         """
-        name = 'qrateactionrefused.group.dynblocks.tests.powerdns.com.'
+        name = "qrateactionrefused.group.dynblocks.tests.powerdns.com."
         self.doTestQRateRCode(name, dns.rcode.REFUSED)
 
-class TestDynBlockGroupExcluded(DynBlocksTest):
 
+class TestDynBlockGroupExcluded(DynBlocksTest):
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
@@ -134,14 +142,10 @@ class TestDynBlockGroupExcluded(DynBlocksTest):
         """
         Dyn Blocks (group) : Excluded from the dynamic block rules
         """
-        name = 'excluded.group.dynblocks.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "excluded.group.dynblocks.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         allowed = 0
@@ -170,8 +174,8 @@ class TestDynBlockGroupExcluded(DynBlocksTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, receivedResponse)
 
-class TestDynBlockGroupExcludedViaNMG(DynBlocksTest):
 
+class TestDynBlockGroupExcludedViaNMG(DynBlocksTest):
     _config_template = """
     local nmg = newNMG()
     nmg:addMask("127.0.0.1/32")
@@ -191,14 +195,10 @@ class TestDynBlockGroupExcludedViaNMG(DynBlocksTest):
         """
         Dyn Blocks (group) : Excluded (via NMG) from the dynamic block rules
         """
-        name = 'excluded-nmg.group.dynblocks.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "excluded-nmg.group.dynblocks.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         allowed = 0
@@ -227,8 +227,8 @@ class TestDynBlockGroupExcludedViaNMG(DynBlocksTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, receivedResponse)
 
-class TestDynBlockGroupExcludedRange(DynBlocksTest):
 
+class TestDynBlockGroupExcludedRange(DynBlocksTest):
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
@@ -246,14 +246,10 @@ class TestDynBlockGroupExcludedRange(DynBlocksTest):
         """
         Dyn Blocks (group) : Excluded from the dynamic block rules (range)
         """
-        name = 'excluded.group.dynblocks.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "excluded.group.dynblocks.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         allowed = 0
@@ -282,8 +278,8 @@ class TestDynBlockGroupExcludedRange(DynBlocksTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, receivedResponse)
 
-class TestDynBlockGroupNoOp(DynBlocksTest):
 
+class TestDynBlockGroupNoOp(DynBlocksTest):
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.NoOp)
@@ -296,20 +292,24 @@ class TestDynBlockGroupNoOp(DynBlocksTest):
     webserver("127.0.0.1:%d")
     setWebserverConfig({password="%s", apiKey="%s"})
     """
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_dynBlockQPS",
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
 
     def testNoOp(self):
         """
         Dyn Blocks (group) : NoOp
         """
-        name = 'noop.group.dynblocks.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "noop.group.dynblocks.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         allowed = 0
@@ -339,10 +339,10 @@ class TestDynBlockGroupNoOp(DynBlocksTest):
         self.assertEqual(receivedResponse, receivedResponse)
 
         # check that the rule has been inserted
-        self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', 1, self._dynBlockDuration, 0, sent)
+        self.doTestDynBlockViaAPI("127.0.0.1/32", "Exceeded query rate", 1, self._dynBlockDuration, 0, sent)
 
-class TestDynBlockGroupWarning(DynBlocksTest):
 
+class TestDynBlockGroupWarning(DynBlocksTest):
     _dynBlockWarningQPS = 5
     _dynBlockQPS = 20
     _config_template = """
@@ -357,20 +357,25 @@ class TestDynBlockGroupWarning(DynBlocksTest):
     webserver("127.0.0.1:%d")
     setWebserverConfig({password="%s", apiKey="%s"})
     """
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_dynBlockWarningQPS', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_dynBlockQPS",
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_dynBlockWarningQPS",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
 
     def testWarning(self):
         """
         Dyn Blocks (group) : Warning
         """
-        name = 'warning.group.dynblocks.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "warning.group.dynblocks.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         allowed = 0
@@ -401,12 +406,12 @@ class TestDynBlockGroupWarning(DynBlocksTest):
         self.assertEqual(receivedResponse, receivedResponse)
 
         # check that the rule has been inserted
-        self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', 1, self._dynBlockDuration, 0, sent)
+        self.doTestDynBlockViaAPI("127.0.0.1/32", "Exceeded query rate", 1, self._dynBlockDuration, 0, sent)
 
         self.doTestQRate(name)
 
-class TestDynBlockGroupPort(DNSDistTest):
 
+class TestDynBlockGroupPort(DNSDistTest):
     _dynBlockQPS = 20
     _dynBlockPeriod = 2
     # this needs to be greater than maintenanceWaitTime
@@ -422,20 +427,16 @@ class TestDynBlockGroupPort(DNSDistTest):
     end
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _config_params = ["_dynBlockQPS", "_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
 
     def testPort(self):
         """
         Dyn Blocks (group): Exact port matching
         """
-        name = 'port.group.dynblocks.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "port.group.dynblocks.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         allowed = 0
@@ -478,8 +479,8 @@ class TestDynBlockGroupPort(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(response, receivedResponse)
 
-class TestDynBlockGroupQSuffixMatchYAML(DynBlocksTest):
 
+class TestDynBlockGroupQSuffixMatchYAML(DynBlocksTest):
     _yaml_config_template = """---
 dynamic_rules:
   - name: "Check Suffix Match visitor from YAML"
@@ -517,22 +518,18 @@ backends:
     protocol: Do53
 """
     _config_params = []
-    _yaml_config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _yaml_config_params = ["_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
 
     def testSuffixMatchVisitorCalled(self):
         """
         Dyn Blocks (Group / YAML): Visitor called
         """
-        name = 'check-visitor.group.dynblocks.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "check-visitor.group.dynblocks.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NOERROR)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         method = "sendUDPQuery"
index 7cdec2b1eeb6e42158342e28296c27711691ea4f..470c622eb2ac54a990f82be763c4064f567f33c9 100644 (file)
@@ -5,12 +5,12 @@ from dnsdistDynBlockTests import DynBlocksTest, waitForMaintenanceToRun
 from dnsdisttests import pickAvailablePort
 from proxyprotocol import ProxyProtocol
 
-class TestDynBlockGroupServFailsRatio(DynBlocksTest):
 
+class TestDynBlockGroupServFailsRatio(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 20 queries count!
     _dynBlockPeriod = 6
-    _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _config_params = ["_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setRCodeRatio(DNSRCode.SERVFAIL, 0.2, %d, "Exceeded rcode ratio", %d, 20)
@@ -26,11 +26,11 @@ class TestDynBlockGroupServFailsRatio(DynBlocksTest):
         """
         Dyn Blocks (group): Server Failure Ratio
         """
-        name = 'servfailratio.group.dynblocks.tests.powerdns.com.'
+        name = "servfailratio.group.dynblocks.tests.powerdns.com."
         self.doTestRCodeRatio(name, dns.rcode.SERVFAIL, 10, 10)
 
-class TestDynBlockGroupServFailsRatioYaml(DynBlocksTest):
 
+class TestDynBlockGroupServFailsRatioYaml(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 40 queries count!
     _dynBlockPeriod = 6
@@ -55,32 +55,37 @@ backends:
     protocol: Do53
 """
     _config_params = []
-    _yaml_config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _yaml_config_params = ["_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
 
     def testDynBlocksServFailRatio(self):
         """
         Dyn Blocks (group / YAML): Server Failure Ratio
         """
-        name = 'servfailratio-yaml.group.dynblocks.tests.powerdns.com.'
+        name = "servfailratio-yaml.group.dynblocks.tests.powerdns.com."
         # we need more queries because of the sampling rate!
         self.doTestRCodeRatio(name, dns.rcode.SERVFAIL, 20, 20)
 
+
 class TestDynBlockGroupServFailsRatioDoH(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 20 queries count!
     _dynBlockPeriod = 6
     _dnsDistListeningAddr = "127.0.0.2"
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
+    _webServerBasicAuthPassword = "secret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setRCodeRatio(DNSRCode.SERVFAIL, 0.2, %d, "Exceeded query rate", %d, 20)
@@ -97,14 +102,25 @@ class TestDynBlockGroupServFailsRatioDoH(DynBlocksTest):
     webserver("127.0.0.1:%d")
     setWebserverConfig({password="%s", apiKey="%s"})
     """
-    _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_dnsDistListeningAddr', '_dohServerPort', '_serverCert', '_serverKey', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_dnsDistListeningAddr",
+        "_dohServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
 
     def testDynBlocksServFailRatio(self):
         """
         Dyn Blocks (group): Server Failure Ratio via DoH
         """
-        name = 'rcode-servfailratio-doh.group.dynblocks.tests.powerdns.com.'
-        rcodeQuery = dns.message.make_query(name, 'A', 'IN')
+        name = "rcode-servfailratio-doh.group.dynblocks.tests.powerdns.com."
+        rcodeQuery = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(rcodeQuery)
         expectedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -112,7 +128,15 @@ class TestDynBlockGroupServFailsRatioDoH(DynBlocksTest):
         sent = 0
         allowed = 0
         for _ in range(rcodecount):
-            (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, rcodeQuery, response=expectedResponse, caFile=self._caCert, customHeaders=['x-forwarded-for: 192.0.2.1'])
+            (receivedQuery, receivedResponse) = self.sendDOHQuery(
+                self._dohServerPort,
+                self._serverName,
+                self._dohBaseURL,
+                rcodeQuery,
+                response=expectedResponse,
+                caFile=self._caCert,
+                customHeaders=["x-forwarded-for: 192.0.2.1"],
+            )
 
             sent = sent + 1
             if receivedQuery:
@@ -131,27 +155,50 @@ class TestDynBlockGroupServFailsRatioDoH(DynBlocksTest):
         waitForMaintenanceToRun()
 
         # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, rcodeQuery, response=None, caFile=self._caCert, customHeaders=['x-forwarded-for: 192.0.2.1'], useQueue=False, timeout=1)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            rcodeQuery,
+            response=None,
+            caFile=self._caCert,
+            customHeaders=["x-forwarded-for: 192.0.2.1"],
+            useQueue=False,
+            timeout=1,
+        )
         self.assertEqual(receivedResponse, None)
 
-        self.doTestDynBlockViaAPI('192.0.2.1/32', 'Exceeded query rate', 1, self._dynBlockDuration, (sent-allowed)+1, (sent-allowed)+1, False)
+        self.doTestDynBlockViaAPI(
+            "192.0.2.1/32",
+            "Exceeded query rate",
+            1,
+            self._dynBlockDuration,
+            (sent - allowed) + 1,
+            (sent - allowed) + 1,
+            False,
+        )
+
 
 class TestDynBlockGroupServFailsRatioDoHCacheHit(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 20 queries count!
     _dynBlockPeriod = 6
     _dnsDistListeningAddr = "127.0.0.2"
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
+    _webServerBasicAuthPassword = "secret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setRCodeRatio(DNSRCode.SERVFAIL, 0.2, %d, "Exceeded query rate", %d, 20)
@@ -171,14 +218,25 @@ class TestDynBlockGroupServFailsRatioDoHCacheHit(DynBlocksTest):
     webserver("127.0.0.1:%d")
     setWebserverConfig({password="%s", apiKey="%s"})
     """
-    _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_dnsDistListeningAddr', '_dohServerPort', '_serverCert', '_serverKey', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_dnsDistListeningAddr",
+        "_dohServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
 
     def testDynBlocksServFailRatio(self):
         """
         Dyn Blocks (group): Server Failure Ratio via DoH (cache hits)
         """
-        name = 'rcode-servfailratio-doh-cache-hits.group.dynblocks.tests.powerdns.com.'
-        rcodeQuery = dns.message.make_query(name, 'A', 'IN')
+        name = "rcode-servfailratio-doh-cache-hits.group.dynblocks.tests.powerdns.com."
+        rcodeQuery = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(rcodeQuery)
         expectedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -188,10 +246,27 @@ class TestDynBlockGroupServFailsRatioDoHCacheHit(DynBlocksTest):
         firstQuery = True
         for _ in range(rcodecount):
             if firstQuery:
-                (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, rcodeQuery, response=expectedResponse, caFile=self._caCert, customHeaders=['x-forwarded-for: 192.0.2.1'])
+                (receivedQuery, receivedResponse) = self.sendDOHQuery(
+                    self._dohServerPort,
+                    self._serverName,
+                    self._dohBaseURL,
+                    rcodeQuery,
+                    response=expectedResponse,
+                    caFile=self._caCert,
+                    customHeaders=["x-forwarded-for: 192.0.2.1"],
+                )
                 firstQuery = False
             else:
-                (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, rcodeQuery, response=None, caFile=self._caCert, customHeaders=['x-forwarded-for: 192.0.2.1'], useQueue=False)
+                (_, receivedResponse) = self.sendDOHQuery(
+                    self._dohServerPort,
+                    self._serverName,
+                    self._dohBaseURL,
+                    rcodeQuery,
+                    response=None,
+                    caFile=self._caCert,
+                    customHeaders=["x-forwarded-for: 192.0.2.1"],
+                    useQueue=False,
+                )
 
             sent = sent + 1
             if receivedQuery:
@@ -211,21 +286,39 @@ class TestDynBlockGroupServFailsRatioDoHCacheHit(DynBlocksTest):
         waitForMaintenanceToRun()
 
         # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
-        (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, rcodeQuery, response=None, caFile=self._caCert, customHeaders=['x-forwarded-for: 192.0.2.1'], useQueue=False, timeout=1)
+        (_, receivedResponse) = self.sendDOHQuery(
+            self._dohServerPort,
+            self._serverName,
+            self._dohBaseURL,
+            rcodeQuery,
+            response=None,
+            caFile=self._caCert,
+            customHeaders=["x-forwarded-for: 192.0.2.1"],
+            useQueue=False,
+            timeout=1,
+        )
         self.assertEqual(receivedResponse, None)
 
-        self.doTestDynBlockViaAPI('192.0.2.1/32', 'Exceeded query rate', 1, self._dynBlockDuration, (sent-allowed)+1, (sent-allowed)+1, False)
+        self.doTestDynBlockViaAPI(
+            "192.0.2.1/32",
+            "Exceeded query rate",
+            1,
+            self._dynBlockDuration,
+            (sent - allowed) + 1,
+            (sent - allowed) + 1,
+            False,
+        )
 
-class TestDynBlockGroupServFailsRatioDoQ(DynBlocksTest):
 
+class TestDynBlockGroupServFailsRatioDoQ(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 20 queries count!
     _dynBlockPeriod = 6
     _dnsDistListeningAddr = "127.0.0.2"
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = """
     local dbr = dynBlockRulesGroup()
@@ -238,25 +331,33 @@ class TestDynBlockGroupServFailsRatioDoQ(DynBlocksTest):
     addDOQLocal("%s:%d", "%s", "%s")
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_dnsDistListeningAddr', '_doqServerPort', '_serverCert', '_serverKey', '_testServerPort']
+    _config_params = [
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_dnsDistListeningAddr",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_testServerPort",
+    ]
 
     def testDynBlocksServFailRatio(self):
         """
         Dyn Blocks (group): Server Failure Ratio via DoQ
         """
-        name = 'servfailratio-doq.group.dynblocks.tests.powerdns.com.'
+        name = "servfailratio-doq.group.dynblocks.tests.powerdns.com."
         self.doTestRCodeRatioViaProtocol(name, dns.rcode.SERVFAIL, 10, 10, "sendDOQQueryWrapper")
 
-class TestDynBlockGroupServFailsRatioDoQCacheHit(DynBlocksTest):
 
+class TestDynBlockGroupServFailsRatioDoQCacheHit(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 20 queries count!
     _dynBlockPeriod = 6
     _dnsDistListeningAddr = "127.0.0.2"
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _config_template = """
     local dbr = dynBlockRulesGroup()
@@ -272,27 +373,35 @@ class TestDynBlockGroupServFailsRatioDoQCacheHit(DynBlocksTest):
     addDOQLocal("%s:%d", "%s", "%s")
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_dnsDistListeningAddr', '_doqServerPort', '_serverCert', '_serverKey', '_testServerPort']
+    _config_params = [
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_dnsDistListeningAddr",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_testServerPort",
+    ]
 
     def testDynBlocksServFailRatio(self):
         """
         Dyn Blocks (group): Server Failure Ratio via DoQ (cache hits)
         """
-        name = 'servfailratio-doq-hits.group.dynblocks.tests.powerdns.com.'
+        name = "servfailratio-doq-hits.group.dynblocks.tests.powerdns.com."
         self.doTestRCodeRatioViaProtocol(name, dns.rcode.SERVFAIL, 10, 10, "sendDOQQueryWrapper", cached=True)
 
-class TestDynBlockGroupServFailsRatioDoH3(DynBlocksTest):
 
+class TestDynBlockGroupServFailsRatioDoH3(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 20 queries count!
     _dynBlockPeriod = 6
     _dnsDistListeningAddr = "127.0.0.2"
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doh3ServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doh3ServerPort)
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setRCodeRatio(DNSRCode.SERVFAIL, 0.2, %d, "Exceeded query rate", %d, 20)
@@ -304,27 +413,35 @@ class TestDynBlockGroupServFailsRatioDoH3(DynBlocksTest):
     addDOH3Local("%s:%d", "%s", "%s")
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_dnsDistListeningAddr', '_doh3ServerPort', '_serverCert', '_serverKey', '_testServerPort']
+    _config_params = [
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_dnsDistListeningAddr",
+        "_doh3ServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_testServerPort",
+    ]
 
     def testDynBlocksServFailRatio(self):
         """
         Dyn Blocks (group): Server Failure Ratio via DoH3
         """
-        name = 'servfailratio-doh3.group.dynblocks.tests.powerdns.com.'
+        name = "servfailratio-doh3.group.dynblocks.tests.powerdns.com."
         self.doTestRCodeRatioViaProtocol(name, dns.rcode.SERVFAIL, 10, 10, "sendDOH3QueryWrapper")
 
-class TestDynBlockGroupServFailsRatioDoH3CacheHit(DynBlocksTest):
 
+class TestDynBlockGroupServFailsRatioDoH3CacheHit(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 20 queries count!
     _dynBlockPeriod = 6
     _dnsDistListeningAddr = "127.0.0.2"
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doh3ServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doh3ServerPort)
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setRCodeRatio(DNSRCode.SERVFAIL, 0.2, %d, "Exceeded query rate", %d, 20)
@@ -339,17 +456,25 @@ class TestDynBlockGroupServFailsRatioDoH3CacheHit(DynBlocksTest):
     addDOH3Local("%s:%d", "%s", "%s")
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_dnsDistListeningAddr', '_doh3ServerPort', '_serverCert', '_serverKey', '_testServerPort']
+    _config_params = [
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_dnsDistListeningAddr",
+        "_doh3ServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_testServerPort",
+    ]
 
     def testDynBlocksServFailRatio(self):
         """
         Dyn Blocks (group): Server Failure Ratio via DoH3 (cache hits)
         """
-        name = 'servfailratio-doh3-hits.group.dynblocks.tests.powerdns.com.'
+        name = "servfailratio-doh3-hits.group.dynblocks.tests.powerdns.com."
         self.doTestRCodeRatioViaProtocol(name, dns.rcode.SERVFAIL, 10, 10, "sendDOH3QueryWrapper", cached=True)
 
-class TestDynBlockGroupAllowedRCodesRatioYaml(DynBlocksTest):
 
+class TestDynBlockGroupAllowedRCodesRatioYaml(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 40 queries count!
     _dynBlockPeriod = 6
@@ -371,13 +496,13 @@ backends:
     protocol: Do53
 """
     _config_params = []
-    _yaml_config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _yaml_config_params = ["_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
 
     def testDynBlocksAllowedRCodesRatio(self):
         """
         Dyn Blocks (group / YAML): Allowed rcodes ratio
         """
-        name = 'allowed-rcodes-ratio-yaml.group.dynblocks.tests.powerdns.com.'
+        name = "allowed-rcodes-ratio-yaml.group.dynblocks.tests.powerdns.com."
         # we need more queries because of the sampling rate!
         self.doTestRCodeRatio(name, dns.rcode.SERVFAIL, 20, 20)
 
@@ -399,11 +524,10 @@ class TestDynBlockGroupAllowedRCodesRatioLua(TestDynBlockGroupAllowedRCodesRatio
 
 
 class TestDynBlockGroupCacheMissRatio(DynBlocksTest):
-
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 20 queries count!
     _dynBlockPeriod = 6
-    _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _config_params = ["_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setCacheMissRatio(0.8, %d, "Exceeded cache miss ratio", %d, 20, 0.0)
@@ -421,15 +545,15 @@ class TestDynBlockGroupCacheMissRatio(DynBlocksTest):
         """
         Dyn Blocks (group): Cache miss ratio
         """
-        name = 'cachemissratio.group.dynblocks.tests.powerdns.com.'
+        name = "cachemissratio.group.dynblocks.tests.powerdns.com."
         self.doTestCacheMissRatio(name, 3, 17)
 
-class TestDynBlockGroupCacheMissRatioSetTag(DynBlocksTest):
 
+class TestDynBlockGroupCacheMissRatioSetTag(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 20 queries count!
     _dynBlockPeriod = 6
-    _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _config_params = ["_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setCacheMissRatio(0.8, %d, "Exceeded cache miss ratio", %d, 20, 0.0, DNSAction.SetTag, 0.0, { tagName='dyn-miss-ratio', tagValue='hit' })
@@ -453,17 +577,13 @@ class TestDynBlockGroupCacheMissRatioSetTag(DynBlocksTest):
         """
         Dyn Blocks (group): Cache miss ratio with SetTag
         """
-        name = 'cachemissratio-settag.group.dynblocks.tests.powerdns.com.'
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        name = "cachemissratio-settag.group.dynblocks.tests.powerdns.com."
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
 
         cacheHits = 3
         cacheMisses = 17
         for idx in range(cacheMisses):
-            query = dns.message.make_query(str(idx) + '.' + name, 'A', 'IN')
+            query = dns.message.make_query(str(idx) + "." + name, "A", "IN")
             response = dns.message.make_response(query)
             response.answer.append(rrset)
             (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -476,7 +596,7 @@ class TestDynBlockGroupCacheMissRatioSetTag(DynBlocksTest):
                 # let's clear the response queue
                 self.clearToResponderQueue()
 
-        query = dns.message.make_query('0.' + name, 'A', 'IN')
+        query = dns.message.make_query("0." + name, "A", "IN")
         response = dns.message.make_response(query)
         response.answer.append(rrset)
         for _ in range(cacheHits):
@@ -487,7 +607,7 @@ class TestDynBlockGroupCacheMissRatioSetTag(DynBlocksTest):
         # we should now get REFUSED for cache misses for up to self._dynBlockDuration + self._dynBlockPeriod
 
         # cache miss
-        query = dns.message.make_query(str(cacheMisses + 1) + '.' + name, 'A', 'IN')
+        query = dns.message.make_query(str(cacheMisses + 1) + "." + name, "A", "IN")
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
@@ -496,7 +616,7 @@ class TestDynBlockGroupCacheMissRatioSetTag(DynBlocksTest):
         self.assertEqual(receivedResponse, expectedResponse)
 
         # but a cache hit should be OK
-        query = dns.message.make_query('0.' + name, 'A', 'IN')
+        query = dns.message.make_query("0." + name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False, timeout=0.5)
@@ -504,15 +624,13 @@ class TestDynBlockGroupCacheMissRatioSetTag(DynBlocksTest):
 
         # this specific query will match the query rules before triggering a cache miss
         # so we can check that the tag is correctly set for query rules as well
-        query = dns.message.make_query('test-query-rules.' + name, 'A', 'IN')
+        query = dns.message.make_query("test-query-rules." + name, "A", "IN")
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        queryRulesRRset = dns.rrset.from_text('test-query-rules.' + name,
-                                                60,
-                                                dns.rdataclass.IN,
-                                                dns.rdatatype.A,
-                                                '192.0.2.2')
+        queryRulesRRset = dns.rrset.from_text(
+            "test-query-rules." + name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2"
+        )
         expectedResponse.answer.append(queryRulesRRset)
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False, timeout=0.5)
         self.assertEqual(receivedResponse, expectedResponse)
@@ -521,7 +639,7 @@ class TestDynBlockGroupCacheMissRatioSetTag(DynBlocksTest):
         time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
 
         # this one should succeed
-        query = dns.message.make_query(str(cacheMisses + 2) + '.' + name, 'A', 'IN')
+        query = dns.message.make_query(str(cacheMisses + 2) + "." + name, "A", "IN")
         response = dns.message.make_response(query)
         response.answer.append(rrset)
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -529,16 +647,21 @@ class TestDynBlockGroupCacheMissRatioSetTag(DynBlocksTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(response, receivedResponse)
 
+
 class TestDynBlockGroupServFailsRatioProxyProtocol(DynBlocksTest):
     # we need this period to be quite long because we request the valid
     # queries to be still looked at to reach the 20 queries count!
     _dynBlockPeriod = 6
     _dnsDistListeningAddr = "127.0.0.2"
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
+    _webServerBasicAuthPassword = "secret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setRCodeRatio(DNSRCode.SERVFAIL, 0.2, %d, "Exceeded query rate", %d, 20)
@@ -555,14 +678,21 @@ class TestDynBlockGroupServFailsRatioProxyProtocol(DynBlocksTest):
     webserver("127.0.0.1:%d")
     setWebserverConfig({password="%s", apiKey="%s"})
     """
-    _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
 
     def testDynBlocksServFailRatio(self):
         """
         Dyn Blocks (group): Server Failure Ratio with incoming proxy protocol
         """
-        name = 'rcode-servfailratio-incoming-proxyprotocol.group.dynblocks.tests.powerdns.com.'
-        rcodeQuery = dns.message.make_query(name, 'A', 'IN')
+        name = "rcode-servfailratio-incoming-proxyprotocol.group.dynblocks.tests.powerdns.com."
+        rcodeQuery = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(rcodeQuery)
         expectedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -577,7 +707,9 @@ class TestDynBlockGroupServFailsRatioProxyProtocol(DynBlocksTest):
         udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [])
 
         for _ in range(rcodecount):
-            (receivedQuery, receivedResponse) = self.sendUDPQuery(udpPayload + rcodeQuery.to_wire(), response=expectedResponse, rawQuery=True)
+            (receivedQuery, receivedResponse) = self.sendUDPQuery(
+                udpPayload + rcodeQuery.to_wire(), response=expectedResponse, rawQuery=True
+            )
 
             sent = sent + 1
             if receivedQuery:
@@ -596,10 +728,20 @@ class TestDynBlockGroupServFailsRatioProxyProtocol(DynBlocksTest):
         waitForMaintenanceToRun()
 
         # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
-        (_, receivedResponse) = self.sendUDPQuery(udpPayload + rcodeQuery.to_wire(), response=None, useQueue=False, rawQuery=True)
+        (_, receivedResponse) = self.sendUDPQuery(
+            udpPayload + rcodeQuery.to_wire(), response=None, useQueue=False, rawQuery=True
+        )
         self.assertEqual(receivedResponse, None)
 
-        self.doTestDynBlockViaAPI(f'{srcAddr}/128', 'Exceeded query rate', 1, self._dynBlockDuration, (sent-allowed)+1, (sent-allowed)+1, False)
+        self.doTestDynBlockViaAPI(
+            f"{srcAddr}/128",
+            "Exceeded query rate",
+            1,
+            self._dynBlockDuration,
+            (sent - allowed) + 1,
+            (sent - allowed) + 1,
+            False,
+        )
 
         # TCP now (with different addresses!)
         sent = 0
@@ -612,7 +754,9 @@ class TestDynBlockGroupServFailsRatioProxyProtocol(DynBlocksTest):
         tcpPayload = ProxyProtocol.getPayload(False, True, False, srcAddr, destAddr, srcPort, destPort, [])
 
         for _ in range(rcodecount):
-            (receivedQuery, receivedResponse) = self.sendTCPQuery(rcodeQuery, response=expectedResponse, prependPayload=tcpPayload)
+            (receivedQuery, receivedResponse) = self.sendTCPQuery(
+                rcodeQuery, response=expectedResponse, prependPayload=tcpPayload
+            )
 
             sent = sent + 1
             if receivedQuery:
@@ -634,4 +778,12 @@ class TestDynBlockGroupServFailsRatioProxyProtocol(DynBlocksTest):
         (_, receivedResponse) = self.sendTCPQuery(rcodeQuery, response=None, useQueue=False, prependPayload=tcpPayload)
         self.assertEqual(receivedResponse, None)
 
-        self.doTestDynBlockViaAPI(f'{srcAddr}/32', 'Exceeded query rate', 1, self._dynBlockDuration, (sent-allowed)+1, (sent-allowed)+1, False)
+        self.doTestDynBlockViaAPI(
+            f"{srcAddr}/32",
+            "Exceeded query rate",
+            1,
+            self._dynBlockDuration,
+            (sent - allowed) + 1,
+            (sent - allowed) + 1,
+            False,
+        )
index 69cd956cac95e5d74ec9d9a7a695e87114d92b6b..6abeb0352df649f9c008441ad7c9b3fb1e29d469 100644 (file)
@@ -3,12 +3,19 @@ import base64
 from dnsdisttests import DNSDistTest
 from dnsdistDynBlockTests import DynBlocksTest
 
-class TestDynBlockResponseBytes(DynBlocksTest):
 
+class TestDynBlockResponseBytes(DynBlocksTest):
     _dynBlockBytesPerSecond = 200
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_dynBlockBytesPerSecond', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_dynBlockBytesPerSecond",
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_testServerPort",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -22,15 +29,22 @@ class TestDynBlockResponseBytes(DynBlocksTest):
         """
         Dyn Blocks: Response Byte Rate
         """
-        name = 'responsebyterate.dynblocks.tests.powerdns.com.'
+        name = "responsebyterate.dynblocks.tests.powerdns.com."
         self.doTestResponseByteRate(name, self._dynBlockBytesPerSecond)
 
-class TestDynBlockGroupResponseBytes(DynBlocksTest):
 
+class TestDynBlockGroupResponseBytes(DynBlocksTest):
     _dynBlockBytesPerSecond = 200
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_dynBlockBytesPerSecond', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_dynBlockBytesPerSecond",
+        "_dynBlockPeriod",
+        "_dynBlockDuration",
+        "_testServerPort",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -48,5 +62,5 @@ class TestDynBlockGroupResponseBytes(DynBlocksTest):
         """
         Dyn Blocks (group) : Response Byte Rate
         """
-        name = 'responsebyterate.group.dynblocks.tests.powerdns.com.'
+        name = "responsebyterate.group.dynblocks.tests.powerdns.com."
         self.doTestResponseByteRate(name, self._dynBlockBytesPerSecond)
index e016b2985109480fe328cb4cd05ed27b4b38e81a..f87e1d13a4c3d7edd688a95b5f68fb34ee4e2e88 100644 (file)
@@ -3,8 +3,8 @@ import time
 import dns
 from dnsdistDynBlockTests import DynBlocksTest, waitForMaintenanceToRun
 
-class TestDynBlockServFails(DynBlocksTest):
 
+class TestDynBlockServFails(DynBlocksTest):
     _config_template = """
     function maintenance()
            addDynBlocks(exceedServFails(%d, %d), "Exceeded servfail rate", %d)
@@ -16,11 +16,11 @@ class TestDynBlockServFails(DynBlocksTest):
         """
         Dyn Blocks: Server Failure Rate
         """
-        name = 'servfailrate.dynblocks.tests.powerdns.com.'
+        name = "servfailrate.dynblocks.tests.powerdns.com."
         self.doTestRCodeRate(name, dns.rcode.SERVFAIL)
 
-class TestDynBlockServFailsCached(DynBlocksTest):
 
+class TestDynBlockServFailsCached(DynBlocksTest):
     _config_template = """
     pc = newPacketCache(10000, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false})
     getPool(""):setCache(pc)
@@ -34,20 +34,15 @@ class TestDynBlockServFailsCached(DynBlocksTest):
         """
         Dyn Blocks: Make sure cache hit responses also gets inserted into rings
         """
-        name = 'servfailrate.dynblocks.tests.powerdns.com.'
+        name = "servfailrate.dynblocks.tests.powerdns.com."
         rcode = dns.rcode.SERVFAIL
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(rcode)
 
-
         for method in ("sendUDPQuery", "sendTCPQuery"):
             print(method, "()")
             sender = getattr(self, method)
@@ -90,8 +85,8 @@ class TestDynBlockServFailsCached(DynBlocksTest):
             (receivedQuery, receivedResponse) = sender(query, response=None)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestDynBlockGroupServFails(DynBlocksTest):
 
+class TestDynBlockGroupServFails(DynBlocksTest):
     _config_template = """
     local dbr = dynBlockRulesGroup()
     dbr:setRCodeRate(DNSRCode.SERVFAIL, %d, %d, "Exceeded query rate", %d)
@@ -107,11 +102,11 @@ class TestDynBlockGroupServFails(DynBlocksTest):
         """
         Dyn Blocks (group): Server Failure Rate
         """
-        name = 'servfailrate.group.dynblocks.tests.powerdns.com.'
+        name = "servfailrate.group.dynblocks.tests.powerdns.com."
         self.doTestRCodeRate(name, dns.rcode.SERVFAIL)
 
-class TestDynBlockGroupServFailsYAML(DynBlocksTest):
 
+class TestDynBlockGroupServFailsYAML(DynBlocksTest):
     _yaml_config_template = """---
 dynamic_rules:
   - name: "Block client generating too many ServFails"
@@ -138,11 +133,11 @@ backends:
     protocol: Do53
 """
     _config_params = []
-    _yaml_config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
+    _yaml_config_params = ["_dynBlockQPS", "_dynBlockPeriod", "_dynBlockDuration", "_testServerPort"]
 
     def testDynBlocksServFailRate(self):
         """
         Dyn Blocks (group / YAML): Server Failure Rate
         """
-        name = 'servfailrate.group.dynblocks.tests.powerdns.com.'
+        name = "servfailrate.group.dynblocks.tests.powerdns.com."
         self.doTestRCodeRate(name, dns.rcode.SERVFAIL)
index 33b00fa28aebb2a2135e5b26bdd9d052387e160e..762f2853504b4f9ad8c590dd98cdb34e5976731f 100644 (file)
@@ -7,22 +7,22 @@ import pycurl
 
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-@unittest.skipUnless('ENABLE_SUDO_TESTS' in os.environ, "sudo is not available")
-class TestSimpleEBPF(DNSDistTest):
 
+@unittest.skipUnless("ENABLE_SUDO_TESTS" in os.environ, "sudo is not available")
+class TestSimpleEBPF(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
     _doqServerPort = pickAvailablePort()
     _doh3ServerPort = pickAvailablePort()
-    _dohWithNGHTTP2BaseURL = ("https://%s:%d/" % (_serverName, _dohWithNGHTTP2ServerPort))
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
+    _dohWithNGHTTP2BaseURL = "https://%s:%d/" % (_serverName, _dohWithNGHTTP2ServerPort)
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doh3ServerPort)
 
     _config_template = """
     setKey("%s")
@@ -40,28 +40,47 @@ class TestSimpleEBPF(DNSDistTest):
     addDOH3Local("127.0.0.1:%d", "%s", "%s")
 
     """
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey', '_doqServerPort', '_serverCert', '_serverKey', '_doh3ServerPort', '_serverCert', '_serverKey']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_dohWithNGHTTP2ServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doh3ServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
     _sudoMode = True
 
     def testNotBlocked(self):
         # unblock 127.0.0.1, just in case
         self.sendConsoleCommand('bpf:unblock(newCA("127.0.0.1"))')
 
-        name = 'simplea.ebpf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simplea.ebpf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
-        for method in ["sendUDPQuery", "sendTCPQuery", "sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper", "sendDOQQueryWrapper", "sendDOH3QueryWrapper"]:
+        for method in [
+            "sendUDPQuery",
+            "sendTCPQuery",
+            "sendDOTQueryWrapper",
+            "sendDOHWithNGHTTP2QueryWrapper",
+            "sendDOQQueryWrapper",
+            "sendDOH3QueryWrapper",
+        ]:
             sender = getattr(self, method)
             (receivedQuery, receivedResponse) = sender(query, response, timeout=1)
             receivedQuery.id = query.id
             self.assertEqual(query, receivedQuery)
-            if method == 'sendDOQQueryWrapper':
+            if method == "sendDOQQueryWrapper":
                 # dnspython sets the ID to 0
                 receivedResponse.id = response.id
             self.assertEqual(response, receivedResponse)
@@ -70,14 +89,10 @@ class TestSimpleEBPF(DNSDistTest):
         # unblock 127.0.0.1, just in case
         self.sendConsoleCommand('bpf:unblock(newCA("127.0.0.1"))')
 
-        name = 'blocked.ebpf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "blocked.ebpf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         # should be blocked over Do53 UDP
         for method in ["sendUDPQuery"]:
@@ -86,12 +101,18 @@ class TestSimpleEBPF(DNSDistTest):
             self.assertEqual(receivedResponse, None)
 
         # not over other protocols
-        for method in ["sendTCPQuery", "sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper", "sendDOQQueryWrapper", "sendDOH3QueryWrapper"]:
+        for method in [
+            "sendTCPQuery",
+            "sendDOTQueryWrapper",
+            "sendDOHWithNGHTTP2QueryWrapper",
+            "sendDOQQueryWrapper",
+            "sendDOH3QueryWrapper",
+        ]:
             sender = getattr(self, method)
             (receivedQuery, receivedResponse) = sender(query, response, timeout=1)
             receivedQuery.id = query.id
             self.assertEqual(query, receivedQuery)
-            if method == 'sendDOQQueryWrapper':
+            if method == "sendDOQQueryWrapper":
                 # dnspython sets the ID to 0
                 receivedResponse.id = response.id
             self.assertEqual(response, receivedResponse)
@@ -100,8 +121,8 @@ class TestSimpleEBPF(DNSDistTest):
         # unblock 127.0.0.1, just in case
         self.sendConsoleCommand('bpf:unblock(newCA("127.0.0.1"))')
 
-        name = 'blocked-any-only.ebpf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'ANY', 'IN', use_edns=False)
+        name = "blocked-any-only.ebpf.tests.powerdns.com."
+        query = dns.message.make_query(name, "ANY", "IN", use_edns=False)
 
         # ANY should be blocked over Do53 UDP
         for method in ["sendUDPQuery"]:
@@ -109,13 +130,9 @@ class TestSimpleEBPF(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False, timeout=0.5)
             self.assertEqual(receivedResponse, None)
 
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         # but A should NOT be blocked
         for method in ["sendUDPQuery"]:
@@ -129,14 +146,10 @@ class TestSimpleEBPF(DNSDistTest):
         # block 127.0.0.1
         self.sendConsoleCommand('bpf:block(newCA("127.0.0.1"))')
 
-        name = 'ip-blocked.ebpf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "ip-blocked.ebpf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         # should be blocked over Do53 UDP, Do53 TCP, DoH
         for method in ["sendUDPQuery", "sendTCPQuery", "sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper"]:
@@ -155,7 +168,7 @@ class TestSimpleEBPF(DNSDistTest):
             (receivedQuery, receivedResponse) = sender(query, response, timeout=1)
             receivedQuery.id = query.id
             self.assertEqual(query, receivedQuery)
-            if method == 'sendDOQQueryWrapper':
+            if method == "sendDOQQueryWrapper":
                 # dnspython sets the ID to 0
                 receivedResponse.id = response.id
             self.assertEqual(response, receivedResponse)
index 0f730466edbf0b0ba291fbfe4af06cb7fbbe6444..e5082f3cd6c6ec637ef7118eaa2654cec13bbc2a 100644 (file)
@@ -3,8 +3,8 @@ import extendederrors
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestBasics(DNSDistTest):
 
+class TestBasics(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
@@ -46,15 +46,11 @@ class TestBasics(DNSDistTest):
         """
         EDE: No EDNS
         """
-        name = 'no-edns.ede.tests.powerdns.com.'
+        name = "no-edns.ede.tests.powerdns.com."
         # no EDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
@@ -69,26 +65,18 @@ class TestBasics(DNSDistTest):
         """
         EDE: Backend response
         """
-        name = 'backend-response.ede.tests.powerdns.com.'
-        ede = extendederrors.ExtendedErrorOption(16, b'my extended error status')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "backend-response.ede.tests.powerdns.com."
+        ede = extendederrors.ExtendedErrorOption(16, b"my extended error status")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
 
         backendResponse = dns.message.make_response(query)
         backendResponse.use_edns(edns=True, payload=4096, options=[])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         backendResponse.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -108,28 +96,20 @@ class TestBasics(DNSDistTest):
         """
         EDE: Backend response (DO)
         """
-        name = 'backend-response-do.ede.tests.powerdns.com.'
-        ede = extendederrors.ExtendedErrorOption(16, b'my extended error status')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, want_dnssec=True)
+        name = "backend-response-do.ede.tests.powerdns.com."
+        ede = extendederrors.ExtendedErrorOption(16, b"my extended error status")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, want_dnssec=True)
 
         backendResponse = dns.message.make_response(query)
         backendResponse.use_edns(edns=True, payload=4096, options=[])
         backendResponse.want_dnssec(True)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         backendResponse.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
         expectedResponse.want_dnssec(True)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -149,27 +129,19 @@ class TestBasics(DNSDistTest):
         """
         EDE: Backend response with existing EDE
         """
-        name = 'backend-response-existing-ede.ede.tests.powerdns.com.'
-        ede = extendederrors.ExtendedErrorOption(16, b'my extended error status')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "backend-response-existing-ede.ede.tests.powerdns.com."
+        ede = extendederrors.ExtendedErrorOption(16, b"my extended error status")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
 
         backendResponse = dns.message.make_response(query)
-        backendEDE = extendederrors.ExtendedErrorOption(3, b'Stale answer')
+        backendEDE = extendederrors.ExtendedErrorOption(3, b"Stale answer")
         backendResponse.use_edns(edns=True, payload=4096, options=[backendEDE])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         backendResponse.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -189,19 +161,15 @@ class TestBasics(DNSDistTest):
         """
         EDE: Self-answered
         """
-        name = 'self-answered.ede.tests.powerdns.com.'
-        ede = extendederrors.ExtendedErrorOption(42, b'my self-answered extended error status')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "self-answered.ede.tests.powerdns.com."
+        ede = extendederrors.ExtendedErrorOption(42, b"my self-answered extended error status")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         # dnsdist sets RA = RD for self-generated responses
         query.flags &= ~dns.flags.RD
 
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=1232, options=[ede])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -213,19 +181,15 @@ class TestBasics(DNSDistTest):
         """
         EDE: Self-answered via Lua FFI
         """
-        name = 'self-answered-ffi.ede.tests.powerdns.com.'
-        ede = extendederrors.ExtendedErrorOption(29, b'Synthesized from Lua')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "self-answered-ffi.ede.tests.powerdns.com."
+        ede = extendederrors.ExtendedErrorOption(29, b"Synthesized from Lua")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         # dnsdist sets RA = RD for self-generated responses
         query.flags &= ~dns.flags.RD
 
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=1232, options=[ede])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -237,19 +201,15 @@ class TestBasics(DNSDistTest):
         """
         EDE: Self-answered via Lua FFI without any extra text
         """
-        name = 'self-answered-ffi-no-extra.ede.tests.powerdns.com.'
-        ede = extendederrors.ExtendedErrorOption(29, b'')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "self-answered-ffi-no-extra.ede.tests.powerdns.com."
+        ede = extendederrors.ExtendedErrorOption(29, b"")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         # dnsdist sets RA = RD for self-generated responses
         query.flags &= ~dns.flags.RD
 
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=1232, options=[ede])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -257,8 +217,8 @@ class TestBasics(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.checkMessageEDNS(expectedResponse, receivedResponse)
 
-class TestMultipleEDE(DNSDistTest):
 
+class TestMultipleEDE(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
@@ -301,27 +261,19 @@ class TestMultipleEDE(DNSDistTest):
         """
         EDE: Backend response with existing EDE
         """
-        name = 'backend-response-existing-ede.ede.tests.powerdns.com.'
-        ede = extendederrors.ExtendedErrorOption(16, b'my extended error status')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "backend-response-existing-ede.ede.tests.powerdns.com."
+        ede = extendederrors.ExtendedErrorOption(16, b"my extended error status")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
 
         backendResponse = dns.message.make_response(query)
-        backendEDE = extendederrors.ExtendedErrorOption(3, b'Stale answer')
+        backendEDE = extendederrors.ExtendedErrorOption(3, b"Stale answer")
         backendResponse.use_edns(edns=True, payload=4096, options=[backendEDE])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         backendResponse.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=4096, options=[backendEDE, ede])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -341,28 +293,20 @@ class TestMultipleEDE(DNSDistTest):
         """
         EDE: Backend response with existing EDE that is replaced
         """
-        name = 'backend-response-existing-ede-replace.ede.tests.powerdns.com.'
-        replacingEde = extendederrors.ExtendedErrorOption(15, b'my replaced error status')
-        ede = extendederrors.ExtendedErrorOption(16, b'my extended error status')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "backend-response-existing-ede-replace.ede.tests.powerdns.com."
+        replacingEde = extendederrors.ExtendedErrorOption(15, b"my replaced error status")
+        ede = extendederrors.ExtendedErrorOption(16, b"my extended error status")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
 
         backendResponse = dns.message.make_response(query)
-        backendEDE = extendederrors.ExtendedErrorOption(3, b'Stale answer')
+        backendEDE = extendederrors.ExtendedErrorOption(3, b"Stale answer")
         backendResponse.use_edns(edns=True, payload=4096, options=[backendEDE])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         backendResponse.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=4096, options=[replacingEde, ede])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -382,20 +326,16 @@ class TestMultipleEDE(DNSDistTest):
         """
         EDE: Self-answered
         """
-        name = 'self-answered.ede.tests.powerdns.com.'
-        allEDE = extendederrors.ExtendedErrorOption(16, b'my extended error status')
-        ede = extendederrors.ExtendedErrorOption(42, b'my self-answered extended error status')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "self-answered.ede.tests.powerdns.com."
+        allEDE = extendederrors.ExtendedErrorOption(16, b"my extended error status")
+        ede = extendederrors.ExtendedErrorOption(42, b"my self-answered extended error status")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         # dnsdist sets RA = RD for self-generated responses
         query.flags &= ~dns.flags.RD
 
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=1232, options=[allEDE, ede])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -407,20 +347,16 @@ class TestMultipleEDE(DNSDistTest):
         """
         EDE: Self-answered via Lua FFI
         """
-        name = 'self-answered-ffi.ede.tests.powerdns.com.'
-        allEDE = extendederrors.ExtendedErrorOption(16, b'my extended error status')
-        ede = extendederrors.ExtendedErrorOption(29, b'Synthesized from Lua')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "self-answered-ffi.ede.tests.powerdns.com."
+        allEDE = extendederrors.ExtendedErrorOption(16, b"my extended error status")
+        ede = extendederrors.ExtendedErrorOption(29, b"Synthesized from Lua")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         # dnsdist sets RA = RD for self-generated responses
         query.flags &= ~dns.flags.RD
 
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=1232, options=[allEDE, ede])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -432,20 +368,16 @@ class TestMultipleEDE(DNSDistTest):
         """
         EDE: Self-answered via Lua FFI without any extra text
         """
-        name = 'self-answered-ffi-no-extra.ede.tests.powerdns.com.'
-        allEDE = extendederrors.ExtendedErrorOption(16, b'my extended error status')
-        ede = extendederrors.ExtendedErrorOption(29, b'')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "self-answered-ffi-no-extra.ede.tests.powerdns.com."
+        allEDE = extendederrors.ExtendedErrorOption(16, b"my extended error status")
+        ede = extendederrors.ExtendedErrorOption(29, b"")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         # dnsdist sets RA = RD for self-generated responses
         query.flags &= ~dns.flags.RD
 
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=1232, options=[allEDE, ede])
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index 0bfd8e2de62e9376a7e3cc4d637375b1d09cf4f5..8b810c287c58891eed70773919c1e85e02a446dd 100644 (file)
@@ -4,6 +4,7 @@ import clientsubnetoption
 import cookiesoption
 from dnsdisttests import DNSDistTest
 
+
 class EDNSOptionsBase(DNSDistTest):
     _ednsTestFunction = """
     function testEDNSOptions(dq)
@@ -98,8 +99,8 @@ class EDNSOptionsBase(DNSDistTest):
     end
     """
 
-class TestEDNSOptions(EDNSOptionsBase):
 
+class TestEDNSOptions(EDNSOptionsBase):
     _config_template = """
     %s
 
@@ -107,20 +108,16 @@ class TestEDNSOptions(EDNSOptionsBase):
 
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_ednsTestFunction', '_testServerPort']
+    _config_params = ["_ednsTestFunction", "_testServerPort"]
 
     def testWithoutEDNS(self):
         """
         EDNS Options: No EDNS
         """
-        name = 'noedns.ednsoptions.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "noedns.ednsoptions.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.255')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.255")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -136,15 +133,11 @@ class TestEDNSOptions(EDNSOptionsBase):
         """
         EDNS Options: Cookie
         """
-        name = 'cookie.ednsoptions.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco])
+        name = "cookie.ednsoptions.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -160,15 +153,11 @@ class TestEDNSOptions(EDNSOptionsBase):
         """
         EDNS Options: ECS4
         """
-        name = 'ecs4.ednsoptions.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4', 32)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "ecs4.ednsoptions.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.4", 32)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -184,15 +173,11 @@ class TestEDNSOptions(EDNSOptionsBase):
         """
         EDNS Options: ECS6
         """
-        name = 'ecs6.ednsoptions.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "ecs6.ednsoptions.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -208,16 +193,12 @@ class TestEDNSOptions(EDNSOptionsBase):
         """
         EDNS Options: Cookie + ECS6
         """
-        name = 'cookie-ecs6.ednsoptions.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso,eco])
+        name = "cookie-ecs6.ednsoptions.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso, eco])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -233,17 +214,13 @@ class TestEDNSOptions(EDNSOptionsBase):
         """
         EDNS Options: Two Cookies + ECS6
         """
-        name = 'multiplecookies-ecs6.ednsoptions.tests.powerdns.com.'
-        eco1 = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128)
-        eco2 = cookiesoption.CookiesOption(b'deadc0de', b'deadc0de')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco1, ecso, eco2])
+        name = "multiplecookies-ecs6.ednsoptions.tests.powerdns.com."
+        eco1 = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128)
+        eco2 = cookiesoption.CookiesOption(b"deadc0de", b"deadc0de")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco1, ecso, eco2])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -255,8 +232,8 @@ class TestEDNSOptions(EDNSOptionsBase):
             self.assertEqual(receivedQuery, query)
             self.assertEqual(receivedResponse, response)
 
-class TestEDNSOptionsAddingECS(EDNSOptionsBase):
 
+class TestEDNSOptionsAddingECS(EDNSOptionsBase):
     _config_template = """
     %s
 
@@ -265,22 +242,18 @@ class TestEDNSOptionsAddingECS(EDNSOptionsBase):
 
     newServer{address="127.0.0.1:%d", useClientSubnet=true}
     """
-    _config_params = ['_ednsTestFunction', '_testServerPort']
+    _config_params = ["_ednsTestFunction", "_testServerPort"]
 
     def testWithoutEDNS(self):
         """
         EDNS Options: No EDNS (adding ECS)
         """
-        name = 'noedns.ednsoptions-ecs.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "noedns.ednsoptions-ecs.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -296,17 +269,13 @@ class TestEDNSOptionsAddingECS(EDNSOptionsBase):
         """
         EDNS Options: Cookie (adding ECS)
         """
-        name = 'cookie.ednsoptions-ecs.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[eco])
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[eco,ecso], payload=512)
+        name = "cookie.ednsoptions-ecs.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=512, options=[eco])
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[eco, ecso], payload=512)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -322,17 +291,13 @@ class TestEDNSOptionsAddingECS(EDNSOptionsBase):
         """
         EDNS Options: ECS4 (adding ECS)
         """
-        name = 'ecs4.ednsoptions-ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4', 32)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('1.2.3.4', 24, scope=24)
+        name = "ecs4.ednsoptions-ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.4", 32)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("1.2.3.4", 24, scope=24)
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[ecsoResponse])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -348,17 +313,13 @@ class TestEDNSOptionsAddingECS(EDNSOptionsBase):
         """
         EDNS Options: ECS6 (adding ECS)
         """
-        name = 'ecs6.ednsoptions-ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128, scope=56)
+        name = "ecs6.ednsoptions-ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128, scope=56)
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[ecsoResponse])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -374,18 +335,14 @@ class TestEDNSOptionsAddingECS(EDNSOptionsBase):
         """
         EDNS Options: Cookie + ECS6 (adding ECS)
         """
-        name = 'cookie-ecs6.ednsoptions-ecs.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso,eco])
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128, scope=56)
+        name = "cookie-ecs6.ednsoptions-ecs.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso, eco])
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128, scope=56)
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[ecsoResponse])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -401,17 +358,13 @@ class TestEDNSOptionsAddingECS(EDNSOptionsBase):
         """
         EDNS Options: Two Cookies + ECS6
         """
-        name = 'multiplecookies-ecs6.ednsoptions.tests.powerdns.com.'
-        eco1 = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128)
-        eco2 = cookiesoption.CookiesOption(b'deadc0de', b'deadc0de')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco1, ecso, eco2])
+        name = "multiplecookies-ecs6.ednsoptions.tests.powerdns.com."
+        eco1 = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128)
+        eco2 = cookiesoption.CookiesOption(b"deadc0de", b"deadc0de")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco1, ecso, eco2])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -423,8 +376,8 @@ class TestEDNSOptionsAddingECS(EDNSOptionsBase):
             self.assertEqual(receivedQuery, query)
             self.assertEqual(receivedResponse, response)
 
-class TestEDNSOptionsLuaFFI(DNSDistTest):
 
+class TestEDNSOptionsLuaFFI(DNSDistTest):
     _config_template = """
     local ffi = require("ffi")
 
@@ -566,14 +519,10 @@ class TestEDNSOptionsLuaFFI(DNSDistTest):
         """
         EDNS Options: No EDNS (FFI)
         """
-        name = 'noedns.ednsoptions.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "noedns.ednsoptions.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.255')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.255")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -589,15 +538,11 @@ class TestEDNSOptionsLuaFFI(DNSDistTest):
         """
         EDNS Options: Cookie (FFI)
         """
-        name = 'cookie.ednsoptions.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco])
+        name = "cookie.ednsoptions.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -613,15 +558,11 @@ class TestEDNSOptionsLuaFFI(DNSDistTest):
         """
         EDNS Options: ECS4 (FFI)
         """
-        name = 'ecs4.ednsoptions.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4', 32)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "ecs4.ednsoptions.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.4", 32)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -637,15 +578,11 @@ class TestEDNSOptionsLuaFFI(DNSDistTest):
         """
         EDNS Options: ECS6 (FFI)
         """
-        name = 'ecs6.ednsoptions.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "ecs6.ednsoptions.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -661,16 +598,12 @@ class TestEDNSOptionsLuaFFI(DNSDistTest):
         """
         EDNS Options: Cookie + ECS6 (FFI)
         """
-        name = 'cookie-ecs6.ednsoptions.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso,eco])
+        name = "cookie-ecs6.ednsoptions.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso, eco])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -686,17 +619,13 @@ class TestEDNSOptionsLuaFFI(DNSDistTest):
         """
         EDNS Options: Two Cookies + ECS6 (FFI)
         """
-        name = 'multiplecookies-ecs6.ednsoptions.tests.powerdns.com.'
-        eco1 = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128)
-        eco2 = cookiesoption.CookiesOption(b'deadc0de', b'deadc0de')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco1, ecso, eco2])
+        name = "multiplecookies-ecs6.ednsoptions.tests.powerdns.com."
+        eco1 = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecso = clientsubnetoption.ClientSubnetOption("2001:DB8::1", 128)
+        eco2 = cookiesoption.CookiesOption(b"deadc0de", b"deadc0de")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco1, ecso, eco2])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index e29144ebe5ce4779b2c8847933d26b85ac99d437..cfcc43b04e617a2f081edf18bcc1a4f9155b582c 100644 (file)
@@ -3,6 +3,7 @@ import dns
 import clientsubnetoption
 from dnsdisttests import DNSDistTest
 
+
 class TestEDNSSelfGenerated(DNSDistTest):
     """
     Check that dnsdist sends correct EDNS data on
@@ -30,8 +31,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
         """
         EDNS on Self-Generated: No existing EDNS
         """
-        name = 'no-edns.rcode.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "no-edns.rcode.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -41,8 +42,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
-        name = 'no-edns.tc.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "no-edns.tc.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
@@ -51,8 +52,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
-        name = 'no-edns.lua.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "no-edns.lua.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
 
@@ -61,16 +62,14 @@ class TestEDNSSelfGenerated(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
-        name = 'no-edns.spoof.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "no-edns.spoof.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
-        expectedResponse.answer.append(dns.rrset.from_text(name,
-                                                           60,
-                                                           dns.rdataclass.IN,
-                                                           dns.rdatatype.A,
-                                                           '192.0.2.1', '192.0.2.2'))
+        expectedResponse.answer.append(
+            dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2")
+        )
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -81,8 +80,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
         """
         EDNS on Self-Generated: EDNS with DO=0
         """
-        name = 'edns-no-do.rcode.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=False)
+        name = "edns-no-do.rcode.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=False)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -94,8 +93,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
             self.assertFalse(receivedResponse.ednsflags & dns.flags.DO)
             self.assertEqual(receivedResponse.payload, 1042)
 
-        name = 'edns-no-do.tc.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=False)
+        name = "edns-no-do.tc.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=False)
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
@@ -106,8 +105,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
         self.assertFalse(receivedResponse.ednsflags & dns.flags.DO)
         self.assertEqual(receivedResponse.payload, 1042)
 
-        name = 'edns-no-do.lua.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=False)
+        name = "edns-no-do.lua.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=False)
         expectedResponse = dns.message.make_response(query, our_payload=1042)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
 
@@ -118,16 +117,14 @@ class TestEDNSSelfGenerated(DNSDistTest):
             self.assertFalse(receivedResponse.ednsflags & dns.flags.DO)
             self.assertEqual(receivedResponse.payload, 1042)
 
-        name = 'edns-no-do.spoof.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=False)
+        name = "edns-no-do.spoof.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=False)
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
-        expectedResponse.answer.append(dns.rrset.from_text(name,
-                                                           60,
-                                                           dns.rdataclass.IN,
-                                                           dns.rdatatype.A,
-                                                           '192.0.2.1', '192.0.2.2'))
+        expectedResponse.answer.append(
+            dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2")
+        )
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -140,8 +137,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
         """
         EDNS on Self-Generated: EDNS with DO=1
         """
-        name = 'edns-do.rcode.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=True)
+        name = "edns-do.rcode.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=True)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
         expectedResponse.want_dnssec(True)
@@ -154,8 +151,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
             self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
             self.assertEqual(receivedResponse.payload, 1042)
 
-        name = 'edns-do.tc.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=True)
+        name = "edns-do.tc.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=True)
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
@@ -167,8 +164,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
         self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
         self.assertEqual(receivedResponse.payload, 1042)
 
-        name = 'edns-do.lua.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=True)
+        name = "edns-do.lua.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=True)
         expectedResponse = dns.message.make_response(query, our_payload=1042)
         expectedResponse.want_dnssec(True)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
@@ -180,17 +177,15 @@ class TestEDNSSelfGenerated(DNSDistTest):
             self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
             self.assertEqual(receivedResponse.payload, 1042)
 
-        name = 'edns-do.spoof.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=True)
+        name = "edns-do.spoof.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=True)
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
         expectedResponse.want_dnssec(True)
-        expectedResponse.answer.append(dns.rrset.from_text(name,
-                                                           60,
-                                                           dns.rdataclass.IN,
-                                                           dns.rdatatype.A,
-                                                           '192.0.2.1', '192.0.2.2'))
+        expectedResponse.answer.append(
+            dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2")
+        )
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -203,9 +198,9 @@ class TestEDNSSelfGenerated(DNSDistTest):
         """
         EDNS on Self-Generated: EDNS with options in the query
         """
-        name = 'edns-options.rcode.edns-self.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512, want_dnssec=True)
+        name = "edns-options.rcode.edns-self.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512, want_dnssec=True)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -218,8 +213,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
             self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
             self.assertEqual(receivedResponse.payload, 1042)
 
-        name = 'edns-options.tc.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512, want_dnssec=True)
+        name = "edns-options.tc.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512, want_dnssec=True)
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
@@ -231,8 +226,8 @@ class TestEDNSSelfGenerated(DNSDistTest):
         self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
         self.assertEqual(receivedResponse.payload, 1042)
 
-        name = 'edns-options.lua.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512, want_dnssec=True)
+        name = "edns-options.lua.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512, want_dnssec=True)
         expectedResponse = dns.message.make_response(query, our_payload=1042)
         expectedResponse.want_dnssec(True)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
@@ -244,17 +239,15 @@ class TestEDNSSelfGenerated(DNSDistTest):
             self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
             self.assertEqual(receivedResponse.payload, 1042)
 
-        name = 'edns-options.spoof.edns-self.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512, want_dnssec=True)
+        name = "edns-options.spoof.edns-self.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512, want_dnssec=True)
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
         expectedResponse.want_dnssec(True)
-        expectedResponse.answer.append(dns.rrset.from_text(name,
-                                                           60,
-                                                           dns.rdataclass.IN,
-                                                           dns.rdatatype.A,
-                                                           '192.0.2.1', '192.0.2.2'))
+        expectedResponse.answer.append(
+            dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2")
+        )
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -293,8 +286,8 @@ class TestEDNSSelfGeneratedDisabled(DNSDistTest):
         """
         EDNS on Self-Generated (disabled): EDNS with DO=0
         """
-        name = 'edns-no-do.rcode.edns-self-disabled.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=False)
+        name = "edns-no-do.rcode.edns-self-disabled.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=False)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -304,8 +297,8 @@ class TestEDNSSelfGeneratedDisabled(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
-        name = 'edns-no-do.tc.edns-self-disabled.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=False)
+        name = "edns-no-do.tc.edns-self-disabled.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=False)
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
@@ -314,8 +307,8 @@ class TestEDNSSelfGeneratedDisabled(DNSDistTest):
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
-        name = 'edns-no-do.lua.edns-self-disabled.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=False)
+        name = "edns-no-do.lua.edns-self-disabled.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=False)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
 
@@ -324,16 +317,14 @@ class TestEDNSSelfGeneratedDisabled(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
-        name = 'edns-no-do.spoof.edns-self-disabled.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=False)
+        name = "edns-no-do.spoof.edns-self-disabled.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=False)
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        expectedResponse.answer.append(dns.rrset.from_text(name,
-                                                           60,
-                                                           dns.rdataclass.IN,
-                                                           dns.rdatatype.A,
-                                                           '192.0.2.1', '192.0.2.2'))
+        expectedResponse.answer.append(
+            dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2")
+        )
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
index e93bbe918b076b1ea8d3d0fbf898bb727cfc88dc..c758a83e28e127324982ed437f1685cfda4ad0e9 100644 (file)
@@ -4,6 +4,7 @@ import clientsubnetoption
 import cookiesoption
 from dnsdisttests import DNSDistTest
 
+
 class TestEdnsClientSubnetNoOverride(DNSDistTest):
     """
     dnsdist is configured to add the EDNS0 Client Subnet
@@ -25,17 +26,13 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest):
         and that the response received from dnsdist does not
         have an EDNS pseudo-RR.
         """
-        name = 'withoutedns.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "withoutedns.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
         response = dns.message.make_response(expectedQuery)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -57,17 +54,13 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest):
         has a valid ECS value and that the response
         received from dnsdist contains an EDNS pseudo-RR.
         """
-        name = 'withednsnoecs.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "withednsnoecs.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(expectedQuery)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -90,18 +83,13 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest):
         and that the response received from dnsdist contains
         an EDNS pseudo-RR.
         """
-        name = 'withednsecs.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "withednsecs.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("1.2.3.4", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             (receivedQuery, receivedResponse) = sender(query, response)
@@ -122,19 +110,15 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest):
         This time the response returned by the backend contains
         an ECS option with scope set.
         """
-        name = 'withoutedns.bereturnsecs.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "withoutedns.bereturnsecs.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
         response = dns.message.make_response(expectedQuery)
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, scope=24)
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24, scope=24)
         response.use_edns(edns=True, payload=4096, options=[ecsoResponse])
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -158,19 +142,15 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest):
         This time the response returned by the backend contains
         an ECS option with scope set.
         """
-        name = 'withednsnoecs.bereturnsecs.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "withednsnoecs.bereturnsecs.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(expectedQuery)
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, scope=24)
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24, scope=24)
         response.use_edns(edns=True, payload=4096, options=[ecsoResponse])
         expectedResponse = dns.message.make_response(query, our_payload=4096)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -194,21 +174,17 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest):
         This time the response returned by the backend contains
         one cookies then one ECS option.
         """
-        name = 'withednsnoecs.bereturnscookiesthenecs.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "withednsnoecs.bereturnscookiesthenecs.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(expectedQuery)
-        ecoResponse = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, scope=24)
+        ecoResponse = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24, scope=24)
         response.use_edns(edns=True, payload=4096, options=[ecoResponse, ecsoResponse])
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=4096, options=[ecoResponse])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
         expectedResponse.use_edns(edns=True, payload=4096, options=[ecoResponse])
@@ -233,21 +209,17 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest):
         This time the response returned by the backend contains
         one ECS then one Cookies option.
         """
-        name = 'withednsnoecs.bereturnsecsthencookies.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "withednsnoecs.bereturnsecsthencookies.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(expectedQuery)
-        ecoResponse = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, scope=24)
+        ecoResponse = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24, scope=24)
         response.use_edns(edns=True, payload=4096, options=[ecsoResponse, ecoResponse])
         expectedResponse = dns.message.make_response(query, our_payload=4096)
         expectedResponse.use_edns(edns=True, payload=4096, options=[ecoResponse])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
         response.use_edns(edns=True, payload=4096, options=[ecoResponse])
@@ -272,21 +244,17 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest):
         This time the response returned by the backend contains
         one Cookies, one ECS then one Cookies option.
         """
-        name = 'withednsnoecs.bereturnscookiesecscookies.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "withednsnoecs.bereturnscookiesecscookies.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(expectedQuery)
-        ecoResponse = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, scope=24)
+        ecoResponse = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        ecsoResponse = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24, scope=24)
         response.use_edns(edns=True, payload=4096, options=[ecoResponse, ecsoResponse, ecoResponse])
         expectedResponse = dns.message.make_response(query, our_payload=4096)
         expectedResponse.use_edns(edns=True, payload=4096, options=[ecoResponse, ecoResponse])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -299,6 +267,7 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest):
             self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
             self.checkResponseEDNSWithoutECS(expectedResponse, receivedResponse, withCookies=2)
 
+
 class TestEdnsClientSubnetOverride(DNSDistTest):
     """
     dnsdist is configured to add the EDNS0 Client Subnet
@@ -322,17 +291,13 @@ class TestEdnsClientSubnetOverride(DNSDistTest):
         and that the response received from dnsdist does not
         have an EDNS pseudo-RR.
         """
-        name = 'withoutedns.overridden.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "withoutedns.overridden.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
         response = dns.message.make_response(expectedQuery)
         response.use_edns(edns=True, payload=4096, options=[ecso])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
@@ -355,17 +320,13 @@ class TestEdnsClientSubnetOverride(DNSDistTest):
         has a valid ECS value and that the response
         received from dnsdist contains an EDNS pseudo-RR.
         """
-        name = 'withednsnoecs.overridden.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "withednsnoecs.overridden.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(expectedQuery)
         response.use_edns(edns=True, payload=4096, options=[ecso])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query, our_payload=4096)
         expectedResponse.answer.append(rrset)
@@ -391,18 +352,14 @@ class TestEdnsClientSubnetOverride(DNSDistTest):
         The initial ECS value is shorter than the one it will be
         replaced with.
         """
-        name = 'withednsecs.overridden.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 8)
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso])
+        name = "withednsecs.overridden.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 8)
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[rewrittenEcso])
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -426,18 +383,14 @@ class TestEdnsClientSubnetOverride(DNSDistTest):
         The initial ECS value is longer than the one it will
         replaced with.
         """
-        name = 'withednsecs.overridden.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso])
+        name = "withednsecs.overridden.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[rewrittenEcso])
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -461,18 +414,14 @@ class TestEdnsClientSubnetOverride(DNSDistTest):
         The initial ECS value is exactly the same size as
         the one it will replaced with.
         """
-        name = 'withednsecs.overridden.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso])
+        name = "withednsecs.overridden.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 24)
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[rewrittenEcso])
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -495,21 +444,19 @@ class TestEdnsClientSubnetOverride(DNSDistTest):
         has a valid ECS value and that the response
         received from dnsdist contains an EDNS pseudo-RR.
         """
-        name = 'withecs-followedbyanother.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
-
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco,ecso,eco])
+        name = "withecs-followedbyanother.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 24)
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
+
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco, ecso, eco])
         # I would have loved to use a TSIG here but I can't find how to make dnspython ignore
         # it while parsing the message in the receiver :-/
         query.additional.append(rrset)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco,eco,rewrittenEcso])
+        expectedQuery = dns.message.make_query(
+            name, "A", "IN", use_edns=True, payload=4096, options=[eco, eco, rewrittenEcso]
+        )
         expectedQuery.additional.append(rrset)
 
         response = dns.message.make_response(expectedQuery)
@@ -539,19 +486,17 @@ class TestEdnsClientSubnetOverride(DNSDistTest):
         has a valid ECS value and that the response
         received from dnsdist contains an EDNS pseudo-RR.
         """
-        name = 'record-in-an-withecs.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
-
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco,ecso,eco])
+        name = "record-in-an-withecs.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 24)
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
+
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco, ecso, eco])
         query.answer.append(rrset)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco,eco,rewrittenEcso])
+        expectedQuery = dns.message.make_query(
+            name, "A", "IN", use_edns=True, payload=4096, options=[eco, eco, rewrittenEcso]
+        )
         expectedQuery.answer.append(rrset)
 
         response = dns.message.make_response(expectedQuery)
@@ -581,19 +526,17 @@ class TestEdnsClientSubnetOverride(DNSDistTest):
         has a valid ECS value and that the response
         received from dnsdist contains an EDNS pseudo-RR.
         """
-        name = 'record-in-an-withecs.ecs.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
-
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco,ecso,eco])
+        name = "record-in-an-withecs.ecs.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 24)
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
+
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco, ecso, eco])
         query.authority.append(rrset)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco,eco,rewrittenEcso])
+        expectedQuery = dns.message.make_query(
+            name, "A", "IN", use_edns=True, payload=4096, options=[eco, eco, rewrittenEcso]
+        )
         expectedQuery.authority.append(rrset)
 
         response = dns.message.make_response(expectedQuery)
@@ -625,20 +568,18 @@ class TestEdnsClientSubnetOverride(DNSDistTest):
         has a valid ECS value and that the response
         received from dnsdist contains an EDNS pseudo-RR.
         """
-        name = 'withedns-no-ecs-followedbyanother.ecs.tests.powerdns.com.'
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
-
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco])
+        name = "withedns-no-ecs-followedbyanother.ecs.tests.powerdns.com."
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
+
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[eco])
         # I would have loved to use a TSIG here but I can't find how to make dnspython ignore
         # it while parsing the message in the receiver :-/
         query.additional.append(rrset)
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco,rewrittenEcso])
+        expectedQuery = dns.message.make_query(
+            name, "A", "IN", use_edns=True, payload=4096, options=[eco, rewrittenEcso]
+        )
         expectedQuery.additional.append(rrset)
 
         response = dns.message.make_response(expectedQuery)
@@ -659,6 +600,7 @@ class TestEdnsClientSubnetOverride(DNSDistTest):
             self.checkQueryEDNSWithECS(expectedQuery, receivedQuery, 1)
             self.checkResponseEDNSWithoutECS(expectedResponse, receivedResponse, 2)
 
+
 class TestECSDisabledByRuleOrLua(DNSDistTest):
     """
     dnsdist is configured to add the EDNS0 Client Subnet
@@ -683,17 +625,13 @@ class TestECSDisabledByRuleOrLua(DNSDistTest):
         """
         ECS Disable: ECS enabled in the backend
         """
-        name = 'notdisabled.ecsrules.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 16)
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "notdisabled.ecsrules.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 16)
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
         response = dns.message.make_response(expectedQuery)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -710,14 +648,10 @@ class TestECSDisabledByRuleOrLua(DNSDistTest):
         """
         ECS Disable: ECS enabled in the backend, but disabled by a rule
         """
-        name = 'disabled.ecsrules.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "disabled.ecsrules.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -733,14 +667,10 @@ class TestECSDisabledByRuleOrLua(DNSDistTest):
         """
         ECS Disable: ECS enabled in the backend, but disabled via Lua
         """
-        name = 'disabledvialua.ecsrules.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "disabledvialua.ecsrules.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -752,6 +682,7 @@ class TestECSDisabledByRuleOrLua(DNSDistTest):
             self.checkQueryNoEDNS(query, receivedQuery)
             self.checkResponseNoEDNS(response, receivedResponse)
 
+
 class TestECSOverrideSetByRuleOrLua(DNSDistTest):
     """
     dnsdist is configured to set the EDNS0 Client Subnet
@@ -776,16 +707,12 @@ class TestECSOverrideSetByRuleOrLua(DNSDistTest):
         """
         ECS Override: not set via Lua or a rule
         """
-        name = 'notoverridden.ecsrules.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
+        name = "notoverridden.ecsrules.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[ecso])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -801,18 +728,14 @@ class TestECSOverrideSetByRuleOrLua(DNSDistTest):
         """
         ECS Override: set with a rule
         """
-        name = 'overridden.ecsrules.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso])
+        name = "overridden.ecsrules.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 24)
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[rewrittenEcso])
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -828,18 +751,14 @@ class TestECSOverrideSetByRuleOrLua(DNSDistTest):
         """
         ECS Override: set via Lua
         """
-        name = 'overriddenvialua.ecsrules.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
-        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso])
+        name = "overriddenvialua.ecsrules.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 24)
+        rewrittenEcso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[ecso])
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, options=[rewrittenEcso])
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -851,6 +770,7 @@ class TestECSOverrideSetByRuleOrLua(DNSDistTest):
             self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
             self.checkResponseEDNSWithECS(response, receivedResponse)
 
+
 class TestECSPrefixLengthSetByRuleOrLua(DNSDistTest):
     """
     dnsdist is configured to set the EDNS0 Client Subnet
@@ -875,17 +795,13 @@ class TestECSPrefixLengthSetByRuleOrLua(DNSDistTest):
         """
         ECS Prefix Length: not overridden via Lua or a rule
         """
-        name = 'notoverriddenprefixlength.ecsrules.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "notoverriddenprefixlength.ecsrules.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[ecso])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
@@ -903,16 +819,12 @@ class TestECSPrefixLengthSetByRuleOrLua(DNSDistTest):
         """
         ECS Prefix Length: overridden with a rule
         """
-        name = 'overriddenprefixlength.ecsrules.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 32)
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "overriddenprefixlength.ecsrules.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 32)
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
         response = dns.message.make_response(expectedQuery)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
@@ -930,16 +842,12 @@ class TestECSPrefixLengthSetByRuleOrLua(DNSDistTest):
         """
         ECS Prefix Length: overridden via Lua
         """
-        name = 'overriddenprefixlengthvialua.ecsrules.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 32)
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "overriddenprefixlengthvialua.ecsrules.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 32)
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
         response = dns.message.make_response(expectedQuery)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
@@ -953,6 +861,7 @@ class TestECSPrefixLengthSetByRuleOrLua(DNSDistTest):
             self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
             self.checkResponseNoEDNS(expectedResponse, receivedResponse)
 
+
 class TestECSPrefixSetByRule(DNSDistTest):
     """
     dnsdist is configured to set the EDNS0 Client Subnet
@@ -972,17 +881,13 @@ class TestECSPrefixSetByRule(DNSDistTest):
         """
         ECS Prefix: not set
         """
-        name = 'notsetecsaction.ecsrules.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 32)
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "notsetecsaction.ecsrules.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 32)
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[ecso])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
@@ -1000,16 +905,12 @@ class TestECSPrefixSetByRule(DNSDistTest):
         """
         ECS Prefix: set with SetECSAction
         """
-        name = 'setecsaction.ecsrules.tests.powerdns.com.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        name = "setecsaction.ecsrules.tests.powerdns.com."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
         response = dns.message.make_response(expectedQuery)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
index 9f536b199ff6e63e8652d04958a3b5971923a1ca..430313a0adca0169ebfa4cde71957205c120a2b7 100644 (file)
@@ -8,14 +8,17 @@ import dns
 import queue
 from dnsdisttests import DNSDistTest, pickAvailablePort, ResponderDropAction
 
+
 class HealthCheckTest(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
-    _config_params = ['_consoleKeyB64', '_consolePort', '_webServerPort', '_webServerAPIKeyHashed', '_testServerPort']
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
+    _config_params = ["_consoleKeyB64", "_consolePort", "_webServerPort", "_webServerAPIKeyHashed", "_testServerPort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -28,18 +31,19 @@ class HealthCheckTest(DNSDistTest):
         return self.sendConsoleCommand("if getServer(0):isUp() then return 'up' else return 'down' end").strip("\n")
 
     def getBackendMetric(self, backendID, metricName):
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        self.assertIn('servers', content)
-        servers = content['servers']
+        self.assertIn("servers", content)
+        servers = content["servers"]
         server = servers[backendID]
         return int(server[metricName])
 
+
 class TestDefaultHealthCheck(HealthCheckTest):
     # this test suite uses a different responder port
     # because we need fresh counters
@@ -52,11 +56,11 @@ class TestDefaultHealthCheck(HealthCheckTest):
         before = TestDefaultHealthCheck._healthCheckCounter
         time.sleep(1.5)
         self.assertGreater(TestDefaultHealthCheck._healthCheckCounter, before)
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), 0)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), 0)
+        self.assertEqual(self.getBackendStatus(), "up")
 
         self.sendConsoleCommand("getServer(0):setUp()")
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendStatus(), "up")
         self.assertEqual(self.sendConsoleCommand("getServer(0):getHealthCheckMode()").rstrip(), "active")
 
         before = TestDefaultHealthCheck._healthCheckCounter
@@ -64,7 +68,7 @@ class TestDefaultHealthCheck(HealthCheckTest):
         self.assertEqual(TestDefaultHealthCheck._healthCheckCounter, before)
 
         self.sendConsoleCommand("getServer(0):setDown()")
-        self.assertEqual(self.getBackendStatus(), 'down')
+        self.assertEqual(self.getBackendStatus(), "down")
 
         before = TestDefaultHealthCheck._healthCheckCounter
         time.sleep(1.5)
@@ -72,24 +76,24 @@ class TestDefaultHealthCheck(HealthCheckTest):
 
         self.sendConsoleCommand("getServer(0):setAuto()")
         # we get back the previous state, which was up
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendStatus(), "up")
         self.assertEqual(self.sendConsoleCommand("getServer(0):getHealthCheckMode()").rstrip(), "active")
 
         before = TestDefaultHealthCheck._healthCheckCounter
         time.sleep(1.5)
         self.assertGreater(TestDefaultHealthCheck._healthCheckCounter, before)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendStatus(), "up")
 
         self.sendConsoleCommand("getServer(0):setDown()")
-        self.assertEqual(self.getBackendStatus(), 'down')
+        self.assertEqual(self.getBackendStatus(), "down")
         self.assertEqual(self.sendConsoleCommand("getServer(0):getHealthCheckMode()").rstrip(), "active")
         self.sendConsoleCommand("getServer(0):setAuto(false)")
 
         before = TestDefaultHealthCheck._healthCheckCounter
         time.sleep(1.5)
         self.assertGreater(TestDefaultHealthCheck._healthCheckCounter, before)
-        self.assertEqual(self.getBackendStatus(), 'up')
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), 0)
+        self.assertEqual(self.getBackendStatus(), "up")
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), 0)
         self.assertEqual(self.sendConsoleCommand("getServer(0):getHealthCheckMode()").rstrip(), "active")
 
         self.sendConsoleCommand("getServer(0):setLazyAuto()")
@@ -100,6 +104,7 @@ class TestDefaultHealthCheck(HealthCheckTest):
         self.sendConsoleCommand("getServer(0):setActiveAuto()")
         self.assertEqual(self.sendConsoleCommand("getServer(0):getHealthCheckMode()").rstrip(), "active")
 
+
 class TestHealthCheckForcedUP(HealthCheckTest):
     # this test suite uses a different responder port
     # because we need fresh counters
@@ -121,8 +126,9 @@ class TestHealthCheckForcedUP(HealthCheckTest):
         before = TestHealthCheckForcedUP._healthCheckCounter
         time.sleep(1.5)
         self.assertEqual(TestHealthCheckForcedUP._healthCheckCounter, before)
-        self.assertEqual(self.getBackendStatus(), 'up')
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), 0)
+        self.assertEqual(self.getBackendStatus(), "up")
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), 0)
+
 
 class TestHealthCheckForcedDown(HealthCheckTest):
     # this test suite uses a different responder port
@@ -145,15 +151,23 @@ class TestHealthCheckForcedDown(HealthCheckTest):
         before = TestHealthCheckForcedDown._healthCheckCounter
         time.sleep(1.5)
         self.assertEqual(TestHealthCheckForcedDown._healthCheckCounter, before)
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), 0)
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), 0)
+
 
 class TestHealthCheckCustomName(HealthCheckTest):
     # this test suite uses a different responder port
     # because it uses a different health check name
     _testServerPort = pickAvailablePort()
 
-    _healthCheckName = 'powerdns.com.'
-    _config_params = ['_consoleKeyB64', '_consolePort', '_webServerPort', '_webServerAPIKeyHashed', '_testServerPort', '_healthCheckName']
+    _healthCheckName = "powerdns.com."
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_webServerPort",
+        "_webServerAPIKeyHashed",
+        "_testServerPort",
+        "_healthCheckName",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -169,8 +183,9 @@ class TestHealthCheckCustomName(HealthCheckTest):
         before = TestHealthCheckCustomName._healthCheckCounter
         time.sleep(1.5)
         self.assertGreater(TestHealthCheckCustomName._healthCheckCounter, before)
-        self.assertEqual(self.getBackendStatus(), 'up')
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), 0)
+        self.assertEqual(self.getBackendStatus(), "up")
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), 0)
+
 
 class TestHealthCheckCustomNameNoAnswer(HealthCheckTest):
     # this test suite uses a different responder port
@@ -193,9 +208,10 @@ class TestHealthCheckCustomNameNoAnswer(HealthCheckTest):
         before = TestHealthCheckCustomNameNoAnswer._healthCheckCounter
         time.sleep(1.5)
         self.assertEqual(TestHealthCheckCustomNameNoAnswer._healthCheckCounter, before)
-        self.assertEqual(self.getBackendStatus(), 'down')
-        self.assertGreater(self.getBackendMetric(0, 'healthCheckFailures'), 0)
-        self.assertGreater(self.getBackendMetric(0, 'healthCheckFailuresTimeout'), 0)
+        self.assertEqual(self.getBackendStatus(), "down")
+        self.assertGreater(self.getBackendMetric(0, "healthCheckFailures"), 0)
+        self.assertGreater(self.getBackendMetric(0, "healthCheckFailuresTimeout"), 0)
+
 
 class TestHealthCheckCustomFunction(HealthCheckTest):
     # this test suite uses a different responder port
@@ -203,7 +219,7 @@ class TestHealthCheckCustomFunction(HealthCheckTest):
     _testServerPort = pickAvailablePort()
     _answerUnexpected = False
 
-    _healthCheckName = 'powerdns.com.'
+    _healthCheckName = "powerdns.com."
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -226,13 +242,14 @@ class TestHealthCheckCustomFunction(HealthCheckTest):
         before = TestHealthCheckCustomFunction._healthCheckCounter
         time.sleep(1.5)
         self.assertGreater(TestHealthCheckCustomFunction._healthCheckCounter, before)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendStatus(), "up")
+
 
 class TestHealthCheckCustomResponseValidationFunction(HealthCheckTest):
     # this test suite uses a different responder port
     # because it uses a different health check configuration
     _testServerPort = pickAvailablePort()
-    _healthCheckName = 'powerdns.com.'
+    _healthCheckName = "powerdns.com."
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -282,24 +299,32 @@ class TestHealthCheckCustomResponseValidationFunction(HealthCheckTest):
     backend:setHealthCheckResponseValidator(myHealthCheckValidationFunction)
     setVerboseHealthChecks(true)
     """
-    _config_params = ['_consoleKeyB64', '_consolePort', '_webServerPort', '_webServerAPIKeyHashed', '_healthCheckName', '_testServerPort', '_healthCheckName']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_webServerPort",
+        "_webServerAPIKeyHashed",
+        "_healthCheckName",
+        "_testServerPort",
+        "_healthCheckName",
+    ]
     _verboseMode = True
 
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP health-check Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, cls.healthCallback])
+        cls._UDPResponder = threading.Thread(
+            name="UDP health-check Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, cls.healthCallback],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
 
     @classmethod
     def healthCallback(cls, request):
         print(request)
-        rrset = dns.rrset.from_text(request.question[0].name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.2')
+        rrset = dns.rrset.from_text(request.question[0].name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.2")
         response = dns.message.make_response(request)
         response.answer.append(rrset)
         return response.to_wire()
@@ -309,12 +334,14 @@ class TestHealthCheckCustomResponseValidationFunction(HealthCheckTest):
         HealthChecks: Custom response validation function
         """
         time.sleep(1.5)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendStatus(), "up")
+
 
 _do53HealthCheckQueries = 0
 _dotHealthCheckQueries = 0
 _dohHealthCheckQueries = 0
 
+
 class TestLazyHealthChecks(HealthCheckTest):
     _extraStartupSleep = 1
     _do53Port = pickAvailablePort()
@@ -322,8 +349,8 @@ class TestLazyHealthChecks(HealthCheckTest):
     _dohPort = pickAvailablePort()
 
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_do53Port', '_dotPort', '_dohPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_do53Port", "_dotPort", "_dohPort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -341,14 +368,14 @@ class TestLazyHealthChecks(HealthCheckTest):
     @staticmethod
     def HandleDNSQuery(request):
         response = dns.message.make_response(request)
-        if str(request.question[0].name).startswith('server-failure'):
+        if str(request.question[0].name).startswith("server-failure"):
             response.set_rcode(dns.rcode.SERVFAIL)
         return response.to_wire()
 
     @classmethod
     def Do53Callback(cls, request):
         global _do53HealthCheckQueries
-        if str(request.question[0].name).startswith('a.root-servers.net'):
+        if str(request.question[0].name).startswith("a.root-servers.net"):
             _do53HealthCheckQueries = _do53HealthCheckQueries + 1
             response = dns.message.make_response(request)
             return response.to_wire()
@@ -357,7 +384,7 @@ class TestLazyHealthChecks(HealthCheckTest):
     @classmethod
     def DoTCallback(cls, request):
         global _dotHealthCheckQueries
-        if str(request.question[0].name).startswith('a.root-servers.net'):
+        if str(request.question[0].name).startswith("a.root-servers.net"):
             _dotHealthCheckQueries = _dotHealthCheckQueries + 1
             response = dns.message.make_response(request)
             return response.to_wire()
@@ -366,7 +393,7 @@ class TestLazyHealthChecks(HealthCheckTest):
     @classmethod
     def DoHCallback(cls, request, requestHeaders, fromQueue, toQueue):
         global _dohHealthCheckQueries
-        if str(request.question[0].name).startswith('a.root-servers.net'):
+        if str(request.question[0].name).startswith("a.root-servers.net"):
             _dohHealthCheckQueries = _dohHealthCheckQueries + 1
             response = dns.message.make_response(request)
             return 200, response.to_wire()
@@ -375,21 +402,53 @@ class TestLazyHealthChecks(HealthCheckTest):
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
-        Do53Responder = threading.Thread(name='Do53 Lazy Responder', target=cls.UDPResponder, args=[cls._do53Port, cls._toResponderQueue, cls._fromResponderQueue, False, cls.Do53Callback])
+        Do53Responder = threading.Thread(
+            name="Do53 Lazy Responder",
+            target=cls.UDPResponder,
+            args=[cls._do53Port, cls._toResponderQueue, cls._fromResponderQueue, False, cls.Do53Callback],
+        )
         Do53Responder.daemon = True
         Do53Responder.start()
 
-        Do53TCPResponder = threading.Thread(name='Do53 TCP Lazy Responder', target=cls.TCPResponder, args=[cls._do53Port, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.Do53Callback])
+        Do53TCPResponder = threading.Thread(
+            name="Do53 TCP Lazy Responder",
+            target=cls.TCPResponder,
+            args=[cls._do53Port, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.Do53Callback],
+        )
         Do53TCPResponder.daemon = True
         Do53TCPResponder.start()
 
-        DoTResponder = threading.Thread(name='DoT Lazy Responder', target=cls.TCPResponder, args=[cls._dotPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.DoTCallback, tlsContext])
+        DoTResponder = threading.Thread(
+            name="DoT Lazy Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._dotPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.DoTCallback,
+                tlsContext,
+            ],
+        )
         DoTResponder.daemon = True
         DoTResponder.start()
 
-        DoHResponder = threading.Thread(name='DoH Lazy Responder', target=cls.DOHResponder, args=[cls._dohPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.DoHCallback, tlsContext])
+        DoHResponder = threading.Thread(
+            name="DoH Lazy Responder",
+            target=cls.DOHResponder,
+            args=[
+                cls._dohPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.DoHCallback,
+                tlsContext,
+            ],
+        )
         DoHResponder.daemon = True
         DoHResponder.start()
 
@@ -402,10 +461,10 @@ class TestLazyHealthChecks(HealthCheckTest):
         time.sleep(1)
         self.assertEqual(_do53HealthCheckQueries, 1)
 
-        name = 'do53.lazy.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "do53.lazy.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        failedQuery = dns.message.make_query('server-failure.do53.lazy.test.powerdns.com.', 'A', 'IN')
+        failedQuery = dns.message.make_query("server-failure.do53.lazy.test.powerdns.com.", "A", "IN")
         failedResponse = dns.message.make_response(failedQuery)
         failedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -425,7 +484,7 @@ class TestLazyHealthChecks(HealthCheckTest):
 
         time.sleep(1.5)
         self.assertEqual(_do53HealthCheckQueries, 2)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendStatus(), "up")
 
     def testDoTLazy(self):
         """
@@ -436,10 +495,10 @@ class TestLazyHealthChecks(HealthCheckTest):
         time.sleep(1)
         self.assertEqual(_dotHealthCheckQueries, 1)
 
-        name = 'dot.lazy.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "dot.lazy.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        failedQuery = dns.message.make_query('server-failure.dot.lazy.test.powerdns.com.', 'A', 'IN')
+        failedQuery = dns.message.make_query("server-failure.dot.lazy.test.powerdns.com.", "A", "IN")
         failedResponse = dns.message.make_response(failedQuery)
         failedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -459,7 +518,7 @@ class TestLazyHealthChecks(HealthCheckTest):
 
         time.sleep(1.5)
         self.assertEqual(_dotHealthCheckQueries, 2)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendStatus(), "up")
 
     def testDoHLazy(self):
         """
@@ -470,10 +529,10 @@ class TestLazyHealthChecks(HealthCheckTest):
         time.sleep(1)
         self.assertEqual(_dohHealthCheckQueries, 1)
 
-        name = 'doh.lazy.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "doh.lazy.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        failedQuery = dns.message.make_query('server-failure.doh.lazy.test.powerdns.com.', 'A', 'IN')
+        failedQuery = dns.message.make_query("server-failure.doh.lazy.test.powerdns.com.", "A", "IN")
         failedResponse = dns.message.make_response(failedQuery)
         failedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -493,10 +552,10 @@ class TestLazyHealthChecks(HealthCheckTest):
 
         time.sleep(1.5)
         self.assertEqual(_dohHealthCheckQueries, 2)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendStatus(), "up")
 
-class HealthCheckUpdateParams(HealthCheckTest):
 
+class HealthCheckUpdateParams(HealthCheckTest):
     _healthQueue = queue.Queue()
     _dropHealthCheck = False
     _delayResponse = None
@@ -504,15 +563,19 @@ class HealthCheckUpdateParams(HealthCheckTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, cls.healthCallback])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, cls.healthCallback],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
 
     @classmethod
     def healthCallback(cls, request):
         if cls._dropHealthCheck:
-          cls._healthQueue.put(False)
-          return ResponderDropAction()
+            cls._healthQueue.put(False)
+            return ResponderDropAction()
         response = dns.message.make_response(request)
         if cls._delayResponse is not None:
             time.sleep(cls._delayResponse)
@@ -531,8 +594,8 @@ class HealthCheckUpdateParams(HealthCheckTest):
     def setDelay(cls, delay):
         cls._delayResponse = delay
 
-class TestUpdateHCParamsCombo1(HealthCheckUpdateParams):
 
+class TestUpdateHCParamsCombo1(HealthCheckUpdateParams):
     # this test suite uses a different responder port
     _testServerPort = pickAvailablePort()
 
@@ -542,13 +605,15 @@ class TestUpdateHCParamsCombo1(HealthCheckUpdateParams):
         """
         # consume health checks upon sys init
         try:
-          while self.wait1(False): pass
-        except queue.Empty: pass
+            while self.wait1(False):
+                pass
+        except queue.Empty:
+            pass
 
         self.assertEqual(self.wait1(), True)
         time.sleep(0.1)
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), 0)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), 0)
+        self.assertEqual(self.getBackendStatus(), "up")
 
         self.sendConsoleCommand("getServer(0):setHealthCheckParams({maxCheckFailures=2,rise=2})")
         self.setDrop()
@@ -557,20 +622,21 @@ class TestUpdateHCParamsCombo1(HealthCheckUpdateParams):
         i = 1
         while i <= 3:
             rc = self.wait1()
-            if rc is False: break
+            if rc is False:
+                break
             i += 1
         self.assertGreater(3, i)
         time.sleep(1.1)
         # should have failures but still up
-        self.assertGreater(self.getBackendMetric(0, 'healthCheckFailures'), 0)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertGreater(self.getBackendMetric(0, "healthCheckFailures"), 0)
+        self.assertEqual(self.getBackendStatus(), "up")
 
         # wait for 2nd failure
         self.assertEqual(self.wait1(), False)
         time.sleep(1.1)
         # should have more failures and down
-        self.assertGreater(self.getBackendMetric(0, 'healthCheckFailures'), 1)
-        self.assertEqual(self.getBackendStatus(), 'down')
+        self.assertGreater(self.getBackendMetric(0, "healthCheckFailures"), 1)
+        self.assertEqual(self.getBackendStatus(), "down")
 
         self.setDrop(False)
 
@@ -578,24 +644,25 @@ class TestUpdateHCParamsCombo1(HealthCheckUpdateParams):
         i = 1
         while i <= 3:
             rc = self.wait1()
-            if rc is True: break
+            if rc is True:
+                break
             i += 1
         self.assertGreater(3, i)
         time.sleep(0.1)
         # still down
-        self.assertEqual(self.getBackendStatus(), 'down')
+        self.assertEqual(self.getBackendStatus(), "down")
 
-        beforeFailure = self.getBackendMetric(0, 'healthCheckFailures')
+        beforeFailure = self.getBackendMetric(0, "healthCheckFailures")
 
         # wati for 2nd success
         self.assertEqual(self.wait1(), True)
         time.sleep(0.1)
         # should have no more failures, back to up
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), beforeFailure)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), beforeFailure)
+        self.assertEqual(self.getBackendStatus(), "up")
 
-class TestUpdateHCParamsCombo2(HealthCheckUpdateParams):
 
+class TestUpdateHCParamsCombo2(HealthCheckUpdateParams):
     # this test suite uses a different responder port
     _testServerPort = pickAvailablePort()
 
@@ -605,13 +672,15 @@ class TestUpdateHCParamsCombo2(HealthCheckUpdateParams):
         """
         # consume health checks upon sys init
         try:
-          while self.wait1(False): pass
-        except queue.Empty: pass
+            while self.wait1(False):
+                pass
+        except queue.Empty:
+            pass
 
         self.assertEqual(self.wait1(), True)
         time.sleep(0.1)
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), 0)
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), 0)
+        self.assertEqual(self.getBackendStatus(), "up")
 
         self.sendConsoleCommand("getServer(0):setHealthCheckParams({checkInterval=2})")
 
@@ -621,7 +690,7 @@ class TestUpdateHCParamsCombo2(HealthCheckUpdateParams):
         self.assertEqual(self.wait1(), True)
         t2 = time.time()
         # intervals shall be greater than 1
-        self.assertGreater(t2-t1, 1.5)
+        self.assertGreater(t2 - t1, 1.5)
 
         self.sendConsoleCommand("getServer(0):setHealthCheckParams({checkTimeout=2000})")
         self.setDrop()
@@ -630,22 +699,23 @@ class TestUpdateHCParamsCombo2(HealthCheckUpdateParams):
         i = 1
         while i <= 3:
             rc = self.wait1()
-            if rc is False: break
+            if rc is False:
+                break
             i += 1
         self.assertGreater(3, i)
 
-        beforeFailure = self.getBackendMetric(0, 'healthCheckFailures')
+        beforeFailure = self.getBackendMetric(0, "healthCheckFailures")
 
         time.sleep(1.5)
         # not timeout yet, should have no failure increase
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), beforeFailure)
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), beforeFailure)
 
         time.sleep(1)
         # now should timeout and failure increased
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), beforeFailure+1)
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), beforeFailure + 1)
 
-class TestHealthCheckLatency(HealthCheckUpdateParams):
 
+class TestHealthCheckLatency(HealthCheckUpdateParams):
     # this test suite uses a different responder port
     _testServerPort = pickAvailablePort()
 
@@ -655,14 +725,16 @@ class TestHealthCheckLatency(HealthCheckUpdateParams):
         """
         # consume health checks upon sys init
         try:
-          while self.wait1(False): pass
-        except queue.Empty: pass
+            while self.wait1(False):
+                pass
+        except queue.Empty:
+            pass
 
         self.assertEqual(self.wait1(), True)
         time.sleep(0.1)
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), 0)
-        self.assertEqual(self.getBackendStatus(), 'up')
-        latency = self.getBackendMetric(0, 'healthCheckLatency')
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), 0)
+        self.assertEqual(self.getBackendStatus(), "up")
+        latency = self.getBackendMetric(0, "healthCheckLatency")
         # less than 500 ms
         self.assertLess(latency, 500)
 
@@ -672,16 +744,16 @@ class TestHealthCheckLatency(HealthCheckUpdateParams):
         self.wait1(True)
 
         # should have no failures, still up
-        self.assertEqual(self.getBackendMetric(0, 'healthCheckFailures'), 0)
-        self.assertEqual(self.getBackendStatus(), 'up')
-        latency = self.getBackendMetric(0, 'healthCheckLatency')
+        self.assertEqual(self.getBackendMetric(0, "healthCheckFailures"), 0)
+        self.assertEqual(self.getBackendStatus(), "up")
+        latency = self.getBackendMetric(0, "healthCheckLatency")
         # should be at least 500 ms
         self.assertGreaterEqual(latency, 500)
 
         self.setDelay(None)
 
-class TestServerStateChange(HealthCheckTest):
 
+class TestServerStateChange(HealthCheckTest):
     _healthQueue = queue.Queue()
     _dropHealthCheck = False
     _config_template = """
@@ -717,16 +789,20 @@ class TestServerStateChange(HealthCheckTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, cls.healthCallback])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, cls.healthCallback],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
 
     @classmethod
     def healthCallback(cls, request):
         if cls._dropHealthCheck:
-          cls._healthQueue.put(False)
-          print("health check received drop")
-          return ResponderDropAction()
+            cls._healthQueue.put(False)
+            print("health check received drop")
+            return ResponderDropAction()
         response = dns.message.make_response(request)
         cls._healthQueue.put(True)
         print("health check received return")
@@ -751,20 +827,20 @@ class TestServerStateChange(HealthCheckTest):
 
         time.sleep(1)
         # server initial up shall have been hit
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendStatus(), "up")
         self.assertEqual(self.getCount(nameAddr, True), 1)
         self.assertEqual(self.getCount(nameAddr, False), 0)
 
         self.setDrop(True)
         time.sleep(2.5)
         # up count did not change, down count increased by 1
-        self.assertEqual(self.getBackendStatus(), 'down')
+        self.assertEqual(self.getBackendStatus(), "down")
         self.assertEqual(self.getCount(nameAddr, True), 1)
         self.assertEqual(self.getCount(nameAddr, False), 1)
 
         self.setDrop(False)
         time.sleep(1.5)
         # up count increased again, down count did not change
-        self.assertEqual(self.getBackendStatus(), 'up')
+        self.assertEqual(self.getBackendStatus(), "up")
         self.assertEqual(self.getCount(nameAddr, True), 2)
         self.assertEqual(self.getCount(nameAddr, False), 1)
index e02d3f20d346a87fe6debf9eee22c91bf4c82683..e454e1ee59ee10d0eb7323a3796e0ec121cd432b 100644 (file)
@@ -4,13 +4,15 @@ import unittest
 import dns
 from dnsdisttests import DNSDistTest
 
+
 def get_loopback_itf():
     interfaces = socket.if_nameindex()
     for itf in interfaces:
-        if itf[1] == 'lo':
-            return 'lo'
+        if itf[1] == "lo":
+            return "lo"
     return None
 
+
 class TestIncomingInterface(DNSDistTest):
     _lo_itf = get_loopback_itf()
     _config_template = """
@@ -35,7 +37,7 @@ class TestIncomingInterface(DNSDistTest):
     addResponseAction(AllRule(), LuaResponseAction(checkItfResponse))
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_lo_itf', '_dnsDistPort', '_testServerPort']
+    _config_params = ["_lo_itf", "_dnsDistPort", "_testServerPort"]
     _skipListeningOnCL = True
 
     def testItfName(self):
@@ -43,17 +45,13 @@ class TestIncomingInterface(DNSDistTest):
         Advanced: Check incoming interface name
         """
         if get_loopback_itf() is None:
-            raise unittest.SkipTest('No lo interface')
+            raise unittest.SkipTest("No lo interface")
 
-        name = 'incoming-interface.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "incoming-interface.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '4.3.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "4.3.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -63,6 +61,7 @@ class TestIncomingInterface(DNSDistTest):
             self.assertEqual(receivedQuery, query)
             self.assertEqual(receivedResponse, response)
 
+
 class TestIncomingInterfaceNotSet(DNSDistTest):
     _lo_itf = get_loopback_itf()
     _config_template = """
@@ -87,7 +86,7 @@ class TestIncomingInterfaceNotSet(DNSDistTest):
     addResponseAction(AllRule(), LuaResponseAction(checkItfResponse))
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_lo_itf', '_dnsDistPort', '_testServerPort']
+    _config_params = ["_lo_itf", "_dnsDistPort", "_testServerPort"]
     _skipListeningOnCL = True
 
     def testItfName(self):
@@ -95,19 +94,15 @@ class TestIncomingInterfaceNotSet(DNSDistTest):
         Advanced: Check incoming interface name (not set)
         """
         if get_loopback_itf() is None:
-            raise unittest.SkipTest('No lo interface')
+            raise unittest.SkipTest("No lo interface")
 
-        name = 'incoming-interface-not-set.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "incoming-interface-not-set.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.4')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index d221aae63a51c192af821ad477907f4ec7826604..7b05f87f43d591c72adffda034b7a779fc4271f3 100644 (file)
@@ -2,43 +2,48 @@
 import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
+
 class IncomingProtocol:
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
-    _dohWithNGHTTP2BaseURL = ("https://%s:%d/dns-query" % (_serverName, _dohWithNGHTTP2ServerPort))
+    _dohWithNGHTTP2BaseURL = "https://%s:%d/dns-query" % (_serverName, _dohWithNGHTTP2ServerPort)
     _doqServerPort = pickAvailablePort()
     _doh3ServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doh3ServerPort)
 
     def testIncomingProtocolRule(self):
         """
         Incoming protocol
         """
-        name = 'incoming-protocol.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "incoming-protocol.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
 
-        for method in ["sendUDPQuery", "sendTCPQuery", "sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper", "sendDOQQueryWrapper", "sendDOH3QueryWrapper"]:
+        for method in [
+            "sendUDPQuery",
+            "sendTCPQuery",
+            "sendDOTQueryWrapper",
+            "sendDOHWithNGHTTP2QueryWrapper",
+            "sendDOQQueryWrapper",
+            "sendDOH3QueryWrapper",
+        ]:
             sender = getattr(self, method)
             expectedResponse = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(name,
-                                        60,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.CNAME,
-                                        method + ".")
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.CNAME, method + ".")
             expectedResponse.answer.append(rrset)
 
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
-            if method in ['sendDOQQueryWrapper', 'sendDOH3QueryWrapper']:
+            if method in ["sendDOQQueryWrapper", "sendDOH3QueryWrapper"]:
                 # dnspython sets the ID to 0
                 receivedResponse.id = expectedResponse.id
             self.assertEqual(expectedResponse, receivedResponse)
 
+
 class IncomingProtocolLuaConfig(DNSDistTest, IncomingProtocol):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -55,7 +60,22 @@ class IncomingProtocolLuaConfig(DNSDistTest, IncomingProtocol):
     addAction(IncomingProtocolRule("DoQ"), SpoofCNAMEAction("sendDOQQueryWrapper"))
     addAction(IncomingProtocolRule("DoH3"), SpoofCNAMEAction("sendDOH3QueryWrapper"))
     """
-    _config_params = ['_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey', '_doqServerPort', '_serverCert', '_serverKey', '_doh3ServerPort', '_serverCert', '_serverKey']
+    _config_params = [
+        "_testServerPort",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_dohWithNGHTTP2ServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doh3ServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
+
 
 class IncomingProtocolYAMLConfig(DNSDistTest, IncomingProtocol):
     _yaml_config_template = """
@@ -141,5 +161,21 @@ query_rules:
       cname: "sendDOH3QueryWrapper"
 """
     _config_params = []
-    _yaml_config_params = ['_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey', '_doqServerPort', '_serverCert', '_serverKey', '_doh3ServerPort', '_serverCert', '_serverKey']
-    _checkConfigExpectedOutput = b"DNS over HTTPS configured\nConfiguration 'configs/dnsdist_IncomingProtocolYAMLConfig.yml' OK!\n"
+    _yaml_config_params = [
+        "_testServerPort",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_dohWithNGHTTP2ServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doh3ServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
+    _checkConfigExpectedOutput = (
+        b"DNS over HTTPS configured\nConfiguration 'configs/dnsdist_IncomingProtocolYAMLConfig.yml' OK!\n"
+    )
index 97c37b6c604c7e9383b2da774c38be7319798ef5..a06a9b18d349801d89e52c7900173c6b50476837 100644 (file)
@@ -8,11 +8,11 @@ import struct
 
 from dnsdisttests import DNSDistTest
 
-@unittest.skipIf('SKIP_LMDB_TESTS' in os.environ, 'LMDB tests are disabled')
-class TestLMDB(DNSDistTest):
 
-    _lmdbFileName = '/tmp/test-lmdb-db'
-    _lmdbDBName = 'db-name'
+@unittest.skipIf("SKIP_LMDB_TESTS" in os.environ, "LMDB tests are disabled")
+class TestLMDB(DNSDistTest):
+    _lmdbFileName = "/tmp/test-lmdb-db"
+    _lmdbDBName = "db-name"
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -59,19 +59,19 @@ class TestLMDB(DNSDistTest):
     -- otherwise, spoof a different response
     addAction(AllRule(), SpoofAction('9.9.9.9'))
     """
-    _config_params = ['_testServerPort', '_lmdbFileName', '_lmdbDBName']
+    _config_params = ["_testServerPort", "_lmdbFileName", "_lmdbDBName"]
 
     @classmethod
     def setUpLMDB(cls):
-        env = lmdb.open(cls._lmdbFileName, map_size=1014*1024, max_dbs=1024, subdir=False)
+        env = lmdb.open(cls._lmdbFileName, map_size=1014 * 1024, max_dbs=1024, subdir=False)
         db = env.open_db(key=cls._lmdbDBName.encode())
         with env.begin(db=db, write=True) as txn:
-            txn.put(b'\x05qname\x04lmdb\x05tests\x08powerdns\x03com\x00', b'this is the value of the qname tag')
-            txn.put(socket.inet_aton('127.0.0.1'), b'this is the value of the source address tag')
-            txn.put(b'this is the value of the qname tag', b'this is the value of the second tag')
-            txn.put(b'\x06suffix\x04lmdb\x05tests\x08powerdns\x03com\x00', b'this is the value of the suffix tag')
-            txn.put(b'qname-plaintext.lmdb.tests.powerdns.com', b'this is the value of the plaintext tag')
-            txn.put(b'kvs-rule.lmdb.tests.powerdns.com', b'the value does not matter')
+            txn.put(b"\x05qname\x04lmdb\x05tests\x08powerdns\x03com\x00", b"this is the value of the qname tag")
+            txn.put(socket.inet_aton("127.0.0.1"), b"this is the value of the source address tag")
+            txn.put(b"this is the value of the qname tag", b"this is the value of the second tag")
+            txn.put(b"\x06suffix\x04lmdb\x05tests\x08powerdns\x03com\x00", b"this is the value of the suffix tag")
+            txn.put(b"qname-plaintext.lmdb.tests.powerdns.com", b"this is the value of the plaintext tag")
+            txn.put(b"kvs-rule.lmdb.tests.powerdns.com", b"the value does not matter")
 
     @classmethod
     def setUpClass(cls):
@@ -87,16 +87,12 @@ class TestLMDB(DNSDistTest):
         """
         LMDB: Match on source address
         """
-        name = 'source-ip.lmdb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "source-ip.lmdb.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '5.6.7.8')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "5.6.7.8")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -110,16 +106,12 @@ class TestLMDB(DNSDistTest):
         """
         LMDB: Match on qname then does a second lookup using the value of the first lookup
         """
-        name = 'qname.lmdb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "qname.lmdb.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.4')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -133,16 +125,12 @@ class TestLMDB(DNSDistTest):
         """
         LMDB: Match on the qname via a suffix lookup
         """
-        name = 'sub.sub.suffix.lmdb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "sub.sub.suffix.lmdb.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '42.42.42.42')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "42.42.42.42")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -156,16 +144,12 @@ class TestLMDB(DNSDistTest):
         """
         LMDB: Match on qname in plain text format
         """
-        name = 'qname-plaintext.lmdb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "qname-plaintext.lmdb.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '9.10.11.12')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "9.10.11.12")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -179,16 +163,12 @@ class TestLMDB(DNSDistTest):
         """
         LMDB: KeyValueStoreLookupRule
         """
-        name = 'kvs-rule.lmdb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "kvs-rule.lmdb.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '13.14.15.16')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "13.14.15.16")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -198,10 +178,10 @@ class TestLMDB(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestLMDBYaml(TestLMDB):
 
-    _lmdbFileName = '/tmp/test-lmdb-db'
-    _lmdbDBName = 'db-name'
+class TestLMDBYaml(TestLMDB):
+    _lmdbFileName = "/tmp/test-lmdb-db"
+    _lmdbDBName = "db-name"
     _config_template = ""
     _config_params = []
     _yaml_config_template = """---
@@ -334,12 +314,12 @@ query_rules:
       ips:
         - "9.9.9.9"
     """
-    _yaml_config_params = ['_testServerPort', '_lmdbFileName', '_lmdbDBName']
+    _yaml_config_params = ["_testServerPort", "_lmdbFileName", "_lmdbDBName"]
 
-class TestLMDBIPInRange(DNSDistTest):
 
-    _lmdbFileName = '/tmp/test-lmdb-range-1-db'
-    _lmdbDBName = 'db-name'
+class TestLMDBIPInRange(DNSDistTest):
+    _lmdbFileName = "/tmp/test-lmdb-range-1-db"
+    _lmdbDBName = "db-name"
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -352,14 +332,17 @@ class TestLMDBIPInRange(DNSDistTest):
     -- otherwise, spoof a different response
     addAction(AllRule(), SpoofAction('9.9.9.9'))
     """
-    _config_params = ['_testServerPort', '_lmdbFileName', '_lmdbDBName']
+    _config_params = ["_testServerPort", "_lmdbFileName", "_lmdbDBName"]
 
     @classmethod
     def setUpLMDB(cls):
-        env = lmdb.open(cls._lmdbFileName, map_size=1014*1024, max_dbs=1024, subdir=False)
+        env = lmdb.open(cls._lmdbFileName, map_size=1014 * 1024, max_dbs=1024, subdir=False)
         db = env.open_db(key=cls._lmdbDBName.encode())
         with env.begin(db=db, write=True) as txn:
-            txn.put(socket.inet_aton('127.255.255.255') + struct.pack("!H", 255), socket.inet_aton('127.0.0.0') + struct.pack("!H", 0) + b'this is the value of the source address tag')
+            txn.put(
+                socket.inet_aton("127.255.255.255") + struct.pack("!H", 255),
+                socket.inet_aton("127.0.0.0") + struct.pack("!H", 0) + b"this is the value of the source address tag",
+            )
 
     @classmethod
     def setUpClass(cls):
@@ -375,16 +358,12 @@ class TestLMDBIPInRange(DNSDistTest):
         """
         LMDB range: Match on source address
         """
-        name = 'source-ip.lmdb-range.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "source-ip.lmdb-range.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '5.6.7.8')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "5.6.7.8")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -394,10 +373,10 @@ class TestLMDBIPInRange(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestLMDBIPNotInRange(DNSDistTest):
 
-    _lmdbFileName = '/tmp/test-lmdb-range-2-db'
-    _lmdbDBName = 'db-name'
+class TestLMDBIPNotInRange(DNSDistTest):
+    _lmdbFileName = "/tmp/test-lmdb-range-2-db"
+    _lmdbDBName = "db-name"
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -410,14 +389,17 @@ class TestLMDBIPNotInRange(DNSDistTest):
     -- otherwise, spoof a different response
     addAction(AllRule(), SpoofAction('9.9.9.9'))
     """
-    _config_params = ['_testServerPort', '_lmdbFileName', '_lmdbDBName']
+    _config_params = ["_testServerPort", "_lmdbFileName", "_lmdbDBName"]
 
     @classmethod
     def setUpLMDB(cls):
-        env = lmdb.open(cls._lmdbFileName, map_size=1014*1024, max_dbs=1024, subdir=False)
+        env = lmdb.open(cls._lmdbFileName, map_size=1014 * 1024, max_dbs=1024, subdir=False)
         db = env.open_db(key=cls._lmdbDBName.encode())
         with env.begin(db=db, write=True) as txn:
-            txn.put(socket.inet_aton('127.0.0.0') + struct.pack("!H", 255), socket.inet_aton('127.0.0.0') + struct.pack("!H", 0) + b'this is the value of the source address tag')
+            txn.put(
+                socket.inet_aton("127.0.0.0") + struct.pack("!H", 255),
+                socket.inet_aton("127.0.0.0") + struct.pack("!H", 0) + b"this is the value of the source address tag",
+            )
 
     @classmethod
     def setUpClass(cls):
@@ -433,16 +415,12 @@ class TestLMDBIPNotInRange(DNSDistTest):
         """
         LMDB not in range: Match on source address
         """
-        name = 'source-ip.lmdb-not-in-range.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "source-ip.lmdb-not-in-range.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '9.9.9.9')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "9.9.9.9")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index d390bf7b0d2369bb9fe3351b6ca88c1569f5f03d..f7afa6f49393ad85ea435fce3bfc43d99dcf3063 100644 (file)
@@ -5,11 +5,12 @@ import dns
 import time
 from dnsdisttests import DNSDistTest
 
+
 class TestLuaThread(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _config_params = ['_consoleKeyB64', '_consolePort']
+    _config_params = ["_consoleKeyB64", "_consolePort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -36,11 +37,12 @@ class TestLuaThread(DNSDistTest):
         """
         LuaThread: Test the lua newThread interface
         """
-        count1 = self.sendConsoleCommand('counter')
+        count1 = self.sendConsoleCommand("counter")
         time.sleep(3)
-        count2 = self.sendConsoleCommand('counter')
+        count2 = self.sendConsoleCommand("counter")
         self.assertGreater(count2, count1)
 
+
 class TestLuaDNSHeaderBindings(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -60,30 +62,24 @@ class TestLuaDNSHeaderBindings(DNSDistTest):
         """
         LuaDNSHeaders: TC
         """
-        name = 'notset.check-tc.lua-dnsheaders.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "notset.check-tc.lua-dnsheaders.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'tc-not-set.check-tc.lua-dnsheaders.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name, 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "tc-not-set.check-tc.lua-dnsheaders.tests.powerdns.com."
+        )
         response.answer.append(rrset)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(response, receivedResponse)
 
-        name = 'set.check-tc.lua-dnsheaders.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "set.check-tc.lua-dnsheaders.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         query.flags |= dns.flags.TC
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -93,6 +89,7 @@ class TestLuaDNSHeaderBindings(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
+
 class TestLuaFrontendBindings(DNSDistTest):
     _config_template = """
     setStructuredLogging(false)
@@ -120,8 +117,8 @@ class TestLuaFrontendBindings(DNSDistTest):
         """
         LuaFrontendBindings: Test Lua frontend bindings
         """
-        name = 'basic.lua-frontend-bindings.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "basic.lua-frontend-bindings.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
@@ -131,6 +128,7 @@ class TestLuaFrontendBindings(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
+
 class TestLuaPoolBindings(DNSDistTest):
     _config_template = """
     local serverPort = %d
@@ -176,8 +174,8 @@ class TestLuaPoolBindings(DNSDistTest):
         """
         LuaPoolBindings: Test Lua pool bindings
         """
-        name = 'basic.lua-pool-bindings.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "basic.lua-pool-bindings.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
@@ -186,11 +184,12 @@ class TestLuaPoolBindings(DNSDistTest):
             (_, receivedResponse) = sender(query, response=response)
             self.assertEqual(receivedResponse, response)
 
+
 class TestLuaError(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _config_params = ['_consoleKeyB64', '_consolePort']
+    _config_params = ["_consoleKeyB64", "_consolePort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -203,4 +202,4 @@ class TestLuaError(DNSDistTest):
         LuaError: Test exception handling while debug module is obscured
         """
         res = self.sendConsoleCommand('error("expected" .. " " .. "error")')
-        self.assertIn('expected error', res)
+        self.assertIn("expected error", res)
index c794bcb68c729bb977d9eecb20bebdbd01485431..ee190ef2851ca584b0d709bdc59bbad7870bc2d1 100644 (file)
@@ -3,8 +3,8 @@
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestAdvancedLuaFFI(DNSDistTest):
 
+class TestAdvancedLuaFFI(DNSDistTest):
     _config_template = """
     local ffi = require("ffi")
 
@@ -156,17 +156,13 @@ class TestAdvancedLuaFFI(DNSDistTest):
         """
         Lua FFI: Test the Lua FFI interface
         """
-        name = 'luaffi.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "luaffi.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -178,8 +174,8 @@ class TestAdvancedLuaFFI(DNSDistTest):
         """
         Lua FFI: Test the Lua FFI interface via an update
         """
-        name = 'luaffi.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'SOA', 'IN')
+        name = "luaffi.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "SOA", "IN")
         query.set_opcode(dns.opcode.UPDATE)
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
@@ -192,8 +188,8 @@ class TestAdvancedLuaFFI(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, response)
 
-class TestAdvancedLuaFFIPerThread(DNSDistTest):
 
+class TestAdvancedLuaFFIPerThread(DNSDistTest):
     _config_template = """
 
     local rulefunction = [[
@@ -317,17 +313,13 @@ class TestAdvancedLuaFFIPerThread(DNSDistTest):
         """
         Lua FFI: Test the Lua FFI per-thread interface
         """
-        name = 'luaffiperthread.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "luaffiperthread.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -339,8 +331,8 @@ class TestAdvancedLuaFFIPerThread(DNSDistTest):
         """
         Lua FFI: Test the Lua FFI per-thread interface via an update
         """
-        name = 'luaffiperthread.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'SOA', 'IN')
+        name = "luaffiperthread.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "SOA", "IN")
         query.set_opcode(dns.opcode.UPDATE)
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
@@ -353,8 +345,8 @@ class TestAdvancedLuaFFIPerThread(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, response)
 
-class TestLuaFFIHeader(DNSDistTest):
 
+class TestLuaFFIHeader(DNSDistTest):
     _config_template = """
     local bit = require("bit")
     local ffi = require("ffi")
@@ -391,22 +383,14 @@ class TestLuaFFIHeader(DNSDistTest):
         """
         Lua FFI: Set AA=1
         """
-        name = 'dnsheader-set-aa.luaffi.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "dnsheader-set-aa.luaffi.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
         expectedResponse.flags |= dns.flags.AA
 
@@ -421,15 +405,11 @@ class TestLuaFFIHeader(DNSDistTest):
         """
         Lua FFI: check AA=0, return REFUSED otherwise
         """
-        name = 'dnsheader-get-aa.luaffi.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "dnsheader-get-aa.luaffi.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         response.flags |= dns.flags.AA
         expectedResponse = dns.message.make_response(query)
@@ -444,8 +424,8 @@ class TestLuaFFIHeader(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestLuaFFISetAlternateName(DNSDistTest):
 
+class TestLuaFFISetAlternateName(DNSDistTest):
     _config_template = """
     local ffi = require("ffi")
 
@@ -480,25 +460,17 @@ class TestLuaFFISetAlternateName(DNSDistTest):
         """
         Lua FFI: Set alternate name
         """
-        name = 'alternate-name.luaffi.tests.powerdns.com.'
-        alternateName = 'dnsdist.org.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        alternateQuery = dns.message.make_query(alternateName, 'A', 'IN')
+        name = "alternate-name.luaffi.tests.powerdns.com."
+        alternateName = "dnsdist.org."
+        query = dns.message.make_query(name, "A", "IN")
+        alternateQuery = dns.message.make_query(alternateName, "A", "IN")
 
         response = dns.message.make_response(alternateQuery)
-        rrset = dns.rrset.from_text(alternateName,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(alternateName, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index 8d167f1c4be4e79e8c84fc79af9beef039fe9e2b..ec53112212057624d684922f85644a593acc3891 100644 (file)
@@ -4,8 +4,8 @@ import requests
 import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class RuleMetricsTest(object):
 
+class RuleMetricsTest(object):
     _config_template = """
     addTLSLocal("127.0.0.1:%d", "%s", "%s", { provider="openssl" })
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/"})
@@ -24,46 +24,58 @@ class RuleMetricsTest(object):
     """
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _dohServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
-    _config_params = ['_tlsServerPort', '_serverCert', '_serverKey', '_dohServerPort', '_serverCert', '_serverKey', '_testServerPort', '_webServerPort', '_webServerAPIKeyHashed']
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _dohServerPort)
+    _config_params = [
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_dohServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_testServerPort",
+        "_webServerPort",
+        "_webServerAPIKeyHashed",
+    ]
 
     @classmethod
     def setUpClass(cls):
         cls.startResponders()
         cls.startDNSDist()
         cls.setUpSockets()
-        cls.waitForTCPSocket('127.0.0.1', cls._webServerPort)
+        cls.waitForTCPSocket("127.0.0.1", cls._webServerPort)
         print("Launching tests..")
 
     def getMetric(self, name):
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        stats = content['statistics']
+        stats = content["statistics"]
         self.assertIn(name, stats)
         return int(stats[name])
 
     def getPoolMetric(self, poolName, metricName):
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost/pool?name=' + poolName
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost/pool?name=" + poolName
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        stats = content['stats']
+        stats = content["stats"]
         self.assertIn(metricName, stats)
         return int(stats[metricName])
 
@@ -71,36 +83,32 @@ class RuleMetricsTest(object):
         """
         Metrics: Check that metrics are correctly updated for RCodeAction
         """
-        rcodes = [
-            ( 'nxdomain', dns.rcode.NXDOMAIN ),
-            ( 'refused', dns.rcode.REFUSED ),
-            ( 'servfail', dns.rcode.SERVFAIL )
-        ]
-        servfailBackendResponses = self.getMetric('servfail-responses')
-
-        for (name, rcode) in rcodes:
-            qname = 'rcode-' + name + '.metrics.tests.powerdns.com.'
-            query = dns.message.make_query(qname, 'A', 'IN')
+        rcodes = [("nxdomain", dns.rcode.NXDOMAIN), ("refused", dns.rcode.REFUSED), ("servfail", dns.rcode.SERVFAIL)]
+        servfailBackendResponses = self.getMetric("servfail-responses")
+
+        for name, rcode in rcodes:
+            qname = "rcode-" + name + ".metrics.tests.powerdns.com."
+            query = dns.message.make_query(qname, "A", "IN")
             # dnsdist set RA = RD for spoofed responses
             query.flags &= ~dns.flags.RD
             expectedResponse = dns.message.make_response(query)
             expectedResponse.set_rcode(rcode)
 
-            ruleMetricBefore = self.getMetric('rule-' + name)
-            if name != 'refused':
-                frontendMetricBefore = self.getMetric('frontend-' + name)
+            ruleMetricBefore = self.getMetric("rule-" + name)
+            if name != "refused":
+                frontendMetricBefore = self.getMetric("frontend-" + name)
 
             for method in ("sendUDPQuery", "sendTCPQuery"):
                 sender = getattr(self, method)
                 (_, receivedResponse) = sender(query, response=None, useQueue=False)
                 self.assertEqual(receivedResponse, expectedResponse)
 
-            self.assertEqual(self.getMetric('rule-' + name), ruleMetricBefore + 2)
-            if name != 'refused':
-                self.assertEqual(self.getMetric('frontend-' + name), frontendMetricBefore + 2)
+            self.assertEqual(self.getMetric("rule-" + name), ruleMetricBefore + 2)
+            if name != "refused":
+                self.assertEqual(self.getMetric("frontend-" + name), frontendMetricBefore + 2)
 
         # self-generated responses should not increase this metric
-        self.assertEqual(self.getMetric('servfail-responses'), servfailBackendResponses)
+        self.assertEqual(self.getMetric("servfail-responses"), servfailBackendResponses)
 
     def testCacheMetrics(self):
         """
@@ -108,23 +116,19 @@ class RuleMetricsTest(object):
         """
 
         for method in ("sendUDPQuery", "sendTCPQuery", "sendDOTQueryWrapper", "sendDOHQueryWrapper"):
-            qname = method + '.cache.metrics.tests.powerdns.com.'
-            query = dns.message.make_query(qname, 'A', 'IN')
+            qname = method + ".cache.metrics.tests.powerdns.com."
+            query = dns.message.make_query(qname, "A", "IN")
             # dnsdist set RA = RD for spoofed responses
             query.flags &= ~dns.flags.RD
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(qname,
-                                        3600,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.A,
-                                        '127.0.0.1')
+            rrset = dns.rrset.from_text(qname, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
             response.answer.append(rrset)
 
-            responsesBefore = self.getMetric('responses')
-            cacheHitsBefore = self.getMetric('cache-hits')
-            cacheMissesBefore = self.getMetric('cache-misses')
-            poolCacheHitsBefore = self.getPoolMetric('cache', 'cacheHits')
-            poolCacheMissesBefore = self.getPoolMetric('cache', 'cacheMisses')
+            responsesBefore = self.getMetric("responses")
+            cacheHitsBefore = self.getMetric("cache-hits")
+            cacheMissesBefore = self.getMetric("cache-misses")
+            poolCacheHitsBefore = self.getPoolMetric("cache", "cacheHits")
+            poolCacheMissesBefore = self.getPoolMetric("cache", "cacheMisses")
 
             sender = getattr(self, method)
             # first time, cache miss
@@ -136,11 +140,11 @@ class RuleMetricsTest(object):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, response)
 
-            self.assertEqual(self.getMetric('responses'), responsesBefore + 2)
-            self.assertEqual(self.getMetric('cache-hits'), cacheHitsBefore + 1)
-            self.assertEqual(self.getMetric('cache-misses'), cacheMissesBefore + 1)
-            self.assertEqual(self.getPoolMetric('cache', 'cacheHits'), poolCacheHitsBefore + 1)
-            self.assertEqual(self.getPoolMetric('cache', 'cacheMisses'), poolCacheMissesBefore + 1)
+            self.assertEqual(self.getMetric("responses"), responsesBefore + 2)
+            self.assertEqual(self.getMetric("cache-hits"), cacheHitsBefore + 1)
+            self.assertEqual(self.getMetric("cache-misses"), cacheMissesBefore + 1)
+            self.assertEqual(self.getPoolMetric("cache", "cacheHits"), poolCacheHitsBefore + 1)
+            self.assertEqual(self.getPoolMetric("cache", "cacheMisses"), poolCacheMissesBefore + 1)
 
     def testServFailMetrics(self):
         """
@@ -148,16 +152,16 @@ class RuleMetricsTest(object):
         """
 
         for method in ("sendUDPQuery", "sendTCPQuery", "sendDOTQueryWrapper", "sendDOHQueryWrapper"):
-            qname = method + '.servfail.cache.metrics.tests.powerdns.com.'
-            query = dns.message.make_query(qname, 'A', 'IN')
+            qname = method + ".servfail.cache.metrics.tests.powerdns.com."
+            query = dns.message.make_query(qname, "A", "IN")
             # dnsdist set RA = RD for spoofed responses
             query.flags &= ~dns.flags.RD
             response = dns.message.make_response(query)
             response.set_rcode(dns.rcode.SERVFAIL)
 
-            frontendBefore = self.getMetric('frontend-servfail')
-            servfailBefore = self.getMetric('servfail-responses')
-            ruleBefore = self.getMetric('rule-servfail')
+            frontendBefore = self.getMetric("frontend-servfail")
+            servfailBefore = self.getMetric("servfail-responses")
+            ruleBefore = self.getMetric("rule-servfail")
 
             sender = getattr(self, method)
             # first time, cache miss
@@ -169,15 +173,20 @@ class RuleMetricsTest(object):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, response)
 
-            self.assertEqual(self.getMetric('frontend-servfail'), frontendBefore + 2)
-            self.assertEqual(self.getMetric('servfail-responses'), servfailBefore + 1)
-            self.assertEqual(self.getMetric('rule-servfail'), ruleBefore)
+            self.assertEqual(self.getMetric("frontend-servfail"), frontendBefore + 2)
+            self.assertEqual(self.getMetric("servfail-responses"), servfailBefore + 1)
+            self.assertEqual(self.getMetric("rule-servfail"), ruleBefore)
+
 
 class TestRuleMetricsDefault(RuleMetricsTest, DNSDistTest):
     pass
 
+
 class TestRuleMetricsRecvmmsg(RuleMetricsTest, DNSDistTest):
     # test the metrics with recvmmsg/sendmmsg support enabled as well
-    _config_template = RuleMetricsTest._config_template + """
+    _config_template = (
+        RuleMetricsTest._config_template
+        + """
         setUDPMultipleMessagesVectorSize(10)
     """
+    )
index 3e161d1f6c19d4a9e9615be12f86479f58c5be24..70aa88df6aba68b6eca51a89602c9d3fd91d2ce1 100644 (file)
@@ -3,19 +3,19 @@ import unittest
 import os
 import subprocess
 
-class TestNetworkEndpointConfig(unittest.TestCase):
 
+class TestNetworkEndpointConfig(unittest.TestCase):
     def checkDNSDistExitCode(self, configTemplate, expectedCode, clientMode=False, verboseMode=False):
-        conffile = 'configs/dnsdist_TestNetworkEndpointConfig.conf'
-        with open(conffile, 'w') as conf:
+        conffile = "configs/dnsdist_TestNetworkEndpointConfig.conf"
+        with open(conffile, "w") as conf:
             conf.write("-- Autogenerated by dnsdisttests.py\n")
             conf.write(configTemplate)
 
-        dnsdistcmd = [os.environ['DNSDISTBIN'], '-C', conffile, '--check-config']
+        dnsdistcmd = [os.environ["DNSDISTBIN"], "-C", conffile, "--check-config"]
         if clientMode:
-            dnsdistcmd.append('-c')
+            dnsdistcmd.append("-c")
         if verboseMode:
-            dnsdistcmd.append('-v')
+            dnsdistcmd.append("-v")
 
         output = None
         returnCode = None
index 39474ed29401dd5772f89af11feb3173829466c4..dae8d58862d68cf28d966d29f1b1c1ad010af0c1 100644 (file)
@@ -7,7 +7,6 @@ from dnsdisttests import DNSDistTest, pickAvailablePort
 
 
 class DNSDistOCSPStaplingTest(DNSDistTest):
-
     @classmethod
     def checkOCSPStaplingStatus(cls, addr, port, serverName, caFile):
         testcmd = [
@@ -32,9 +31,7 @@ class DNSDistOCSPStaplingTest(DNSDistTest):
             )
             output = process.communicate(input="")
         except subprocess.CalledProcessError as exc:
-            raise AssertionError(
-                "openssl s_client failed (%d): %s" % (exc.returncode, exc.output)
-            )
+            raise AssertionError("openssl s_client failed (%d): %s" % (exc.returncode, exc.output))
 
         return output[0].decode()
 
@@ -63,7 +60,6 @@ class DNSDistOCSPStaplingTest(DNSDistTest):
 
 @unittest.skipIf("SKIP_DOH_TESTS" in os.environ, "DNS over HTTPS tests are disabled")
 class TestOCSPStaplingDOH(DNSDistOCSPStaplingTest):
-
     _consoleKey = DNSDistTest.generateConsoleKey()
     _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _serverKey = "server-ocsp.key"
@@ -115,9 +111,7 @@ class TestOCSPStaplingDOH(DNSDistOCSPStaplingTest):
         OCSP Stapling: DOH
         """
         for port in [self._dohWithNGHTTP2ServerPort]:
-            output = self.checkOCSPStaplingStatus(
-                "127.0.0.1", port, self._serverName, self._caCert
-            )
+            output = self.checkOCSPStaplingStatus("127.0.0.1", port, self._serverName, self._caCert)
             self.assertIn("OCSP Response Status: successful (0x0)", output)
 
             serialNumber = self.getOCSPSerial(output)
@@ -130,9 +124,7 @@ class TestOCSPStaplingDOH(DNSDistOCSPStaplingTest):
             )
             self.sendConsoleCommand("reloadAllCertificates()")
 
-            output = self.checkOCSPStaplingStatus(
-                "127.0.0.1", port, self._serverName, self._caCert
-            )
+            output = self.checkOCSPStaplingStatus("127.0.0.1", port, self._serverName, self._caCert)
             self.assertIn("OCSP Response Status: successful (0x0)", output)
             serialNumber2 = self.getOCSPSerial(output)
             self.assertTrue(serialNumber2)
@@ -140,7 +132,6 @@ class TestOCSPStaplingDOH(DNSDistOCSPStaplingTest):
 
 
 class TestBrokenOCSPStaplingDoH(DNSDistOCSPStaplingTest):
-
     _consoleKey = DNSDistTest.generateConsoleKey()
     _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _serverKey = "server-ocsp.key"
@@ -173,14 +164,11 @@ class TestBrokenOCSPStaplingDoH(DNSDistOCSPStaplingTest):
         OCSP Stapling: Broken (DoH)
         """
         for port in [self._dohWithNGHTTP2ServerPort]:
-            output = self.checkOCSPStaplingStatus(
-                "127.0.0.1", port, self._serverName, self._caCert
-            )
+            output = self.checkOCSPStaplingStatus("127.0.0.1", port, self._serverName, self._caCert)
             self.assertNotIn("OCSP Response Status: successful (0x0)", output)
 
 
 class TestOCSPStaplingTLSGnuTLS(DNSDistOCSPStaplingTest):
-
     _consoleKey = DNSDistTest.generateConsoleKey()
     _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _serverKey = "server-ocsp.key"
@@ -217,9 +205,7 @@ class TestOCSPStaplingTLSGnuTLS(DNSDistOCSPStaplingTest):
         """
         OCSP Stapling: TLS (GnuTLS)
         """
-        output = self.checkOCSPStaplingStatus(
-            "127.0.0.1", self._tlsServerPort, self._serverName, self._caCert
-        )
+        output = self.checkOCSPStaplingStatus("127.0.0.1", self._tlsServerPort, self._serverName, self._caCert)
         self.assertIn("OCSP Response Status: successful (0x0)", output)
         self.assertEqual(self.getTLSProvider(), "gnutls")
 
@@ -233,9 +219,7 @@ class TestOCSPStaplingTLSGnuTLS(DNSDistOCSPStaplingTest):
         )
         self.sendConsoleCommand("reloadAllCertificates()")
 
-        output = self.checkOCSPStaplingStatus(
-            "127.0.0.1", self._tlsServerPort, self._serverName, self._caCert
-        )
+        output = self.checkOCSPStaplingStatus("127.0.0.1", self._tlsServerPort, self._serverName, self._caCert)
         self.assertIn("OCSP Response Status: successful (0x0)", output)
         serialNumber2 = self.getOCSPSerial(output)
         self.assertTrue(serialNumber2)
@@ -243,7 +227,6 @@ class TestOCSPStaplingTLSGnuTLS(DNSDistOCSPStaplingTest):
 
 
 class TestBrokenOCSPStaplingTLSGnuTLS(DNSDistOCSPStaplingTest):
-
     _consoleKey = DNSDistTest.generateConsoleKey()
     _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _serverKey = "server-ocsp.key"
@@ -274,15 +257,12 @@ class TestBrokenOCSPStaplingTLSGnuTLS(DNSDistOCSPStaplingTest):
         """
         OCSP Stapling: Broken (GnuTLS)
         """
-        output = self.checkOCSPStaplingStatus(
-            "127.0.0.1", self._tlsServerPort, self._serverName, self._caCert
-        )
+        output = self.checkOCSPStaplingStatus("127.0.0.1", self._tlsServerPort, self._serverName, self._caCert)
         self.assertNotIn("OCSP Response Status: successful (0x0)", output)
         self.assertEqual(self.getTLSProvider(), "gnutls")
 
 
 class TestOCSPStaplingTLSOpenSSL(DNSDistOCSPStaplingTest):
-
     _consoleKey = DNSDistTest.generateConsoleKey()
     _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _serverKey = "server-ocsp.key"
@@ -319,9 +299,7 @@ class TestOCSPStaplingTLSOpenSSL(DNSDistOCSPStaplingTest):
         """
         OCSP Stapling: TLS (OpenSSL)
         """
-        output = self.checkOCSPStaplingStatus(
-            "127.0.0.1", self._tlsServerPort, self._serverName, self._caCert
-        )
+        output = self.checkOCSPStaplingStatus("127.0.0.1", self._tlsServerPort, self._serverName, self._caCert)
         self.assertIn("OCSP Response Status: successful (0x0)", output)
         self.assertEqual(self.getTLSProvider(), "openssl")
 
@@ -335,9 +313,7 @@ class TestOCSPStaplingTLSOpenSSL(DNSDistOCSPStaplingTest):
         )
         self.sendConsoleCommand("reloadAllCertificates()")
 
-        output = self.checkOCSPStaplingStatus(
-            "127.0.0.1", self._tlsServerPort, self._serverName, self._caCert
-        )
+        output = self.checkOCSPStaplingStatus("127.0.0.1", self._tlsServerPort, self._serverName, self._caCert)
         self.assertIn("OCSP Response Status: successful (0x0)", output)
         serialNumber2 = self.getOCSPSerial(output)
         self.assertTrue(serialNumber2)
@@ -345,7 +321,6 @@ class TestOCSPStaplingTLSOpenSSL(DNSDistOCSPStaplingTest):
 
 
 class TestBrokenOCSPStaplingTLSOpenSSL(DNSDistOCSPStaplingTest):
-
     _consoleKey = DNSDistTest.generateConsoleKey()
     _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _serverKey = "server-ocsp.key"
@@ -376,8 +351,6 @@ class TestBrokenOCSPStaplingTLSOpenSSL(DNSDistOCSPStaplingTest):
         """
         OCSP Stapling: Broken (OpenSSL)
         """
-        output = self.checkOCSPStaplingStatus(
-            "127.0.0.1", self._tlsServerPort, self._serverName, self._caCert
-        )
+        output = self.checkOCSPStaplingStatus("127.0.0.1", self._tlsServerPort, self._serverName, self._caCert)
         self.assertNotIn("OCSP Response Status: successful (0x0)", output)
         self.assertEqual(self.getTLSProvider(), "openssl")
index c3486e2479da4c5241e706c33ae08c09468b80aa..81a4f7209667bf1d15ec0bd15d1548ac0fb24fe0 100644 (file)
@@ -6,11 +6,10 @@ import time
 import threading
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class OOORTCPResponder(object):
 
+class OOORTCPResponder(object):
     def handleConnection(self, conn):
         try:
-
             while True:
                 try:
                     data = conn.recv(2)
@@ -26,7 +25,7 @@ class OOORTCPResponder(object):
 
                 # computing the correct ID for the response
                 request = dns.message.from_wire(data)
-                #print("got a query for %s" % (request.question[0].name))
+                # print("got a query for %s" % (request.question[0].name))
                 if request.question[0].name == "0.simple.ooor.tests.powerdns.com":
                     time.sleep(1)
 
@@ -61,17 +60,15 @@ class OOORTCPResponder(object):
                 conn.settimeout(5.0)
 
                 OOORTCPResponder.numberOfConnections = OOORTCPResponder.numberOfConnections + 1
-                thread = threading.Thread(name='Connection Handler',
-                                        target=self.handleConnection,
-                                        args=[conn])
+                thread = threading.Thread(name="Connection Handler", target=self.handleConnection, args=[conn])
                 thread.daemon = True
                 thread.start()
 
         finally:
             sock.close()
 
-class ReverseOOORTCPResponder(OOORTCPResponder):
 
+class ReverseOOORTCPResponder(OOORTCPResponder):
     def handleConnection(self, conn):
         try:
             # short timeout since we want to answer only after receiving 5 requests
@@ -105,7 +102,7 @@ class ReverseOOORTCPResponder(OOORTCPResponder):
 
                 # computing the correct ID for the response
                 request = dns.message.from_wire(data)
-                #print("got a query for %s" % (request.question[0].name))
+                # print("got a query for %s" % (request.question[0].name))
 
                 response = dns.message.make_response(request)
                 queuedResponses.append(response)
@@ -134,9 +131,7 @@ class ReverseOOORTCPResponder(OOORTCPResponder):
                 (conn, _) = sock.accept()
 
                 ReverseOOORTCPResponder.numberOfConnections = ReverseOOORTCPResponder.numberOfConnections + 1
-                thread = threading.Thread(name='Connection Handler',
-                                        target=self.handleConnection,
-                                        args=[conn])
+                thread = threading.Thread(name="Connection Handler", target=self.handleConnection, args=[conn])
                 thread.daemon = True
                 thread.start()
 
@@ -145,15 +140,18 @@ class ReverseOOORTCPResponder(OOORTCPResponder):
 
 
 OOORResponderPort = pickAvailablePort()
-ooorTCPResponder = threading.Thread(name='TCP Responder', target=OOORTCPResponder, args=[OOORResponderPort])
+ooorTCPResponder = threading.Thread(name="TCP Responder", target=OOORTCPResponder, args=[OOORResponderPort])
 ooorTCPResponder.daemon = True
 ooorTCPResponder.start()
 
 ReverseOOORResponderPort = pickAvailablePort()
-ReverseOoorTCPResponder = threading.Thread(name='TCP Responder', target=ReverseOOORTCPResponder, args=[ReverseOOORResponderPort])
+ReverseOoorTCPResponder = threading.Thread(
+    name="TCP Responder", target=ReverseOOORTCPResponder, args=[ReverseOOORResponderPort]
+)
 ReverseOoorTCPResponder.daemon = True
 ReverseOoorTCPResponder.start()
 
+
 class TestOOORWithClientNotBackend(DNSDistTest):
     # this test suite uses a different responder port
     _testServerPort = OOORResponderPort
@@ -166,7 +164,13 @@ class TestOOORWithClientNotBackend(DNSDistTest):
     addAction("more-queries.ooor.tests.powerdns.com.", PoolAction("more-queries"))
     setLocal("%s:%d", {maxInFlight=%d})
     """
-    _config_params = ['_testServerPort', '_testServerPort', '_dnsDistListeningAddr', '_dnsDistPort', '_concurrentQueriesFromClient']
+    _config_params = [
+        "_testServerPort",
+        "_testServerPort",
+        "_dnsDistListeningAddr",
+        "_dnsDistPort",
+        "_concurrentQueriesFromClient",
+    ]
     _verboseMode = True
     _skipListeningOnCL = True
 
@@ -182,13 +186,13 @@ class TestOOORWithClientNotBackend(DNSDistTest):
         OOORTCPResponder.numberOfConnections = 0
 
         for idx in range(5):
-            names.append('%d.simple.ooor.tests.powerdns.com.' % (idx))
+            names.append("%d.simple.ooor.tests.powerdns.com." % (idx))
 
         conn = self.openTCPConnection()
 
         counter = 0
         for name in names:
-            query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+            query = dns.message.make_query(name, "A", "IN", use_edns=False)
             query.id = counter
             counter = counter + 1
 
@@ -199,11 +203,11 @@ class TestOOORWithClientNotBackend(DNSDistTest):
         for _ in names:
             receivedResponse = self.recvTCPResponseOverConnection(conn)
             self.assertTrue(receivedResponse)
-            receivedResponses[str(receivedResponse.question[0].name)] = (receivedResponse)
+            receivedResponses[str(receivedResponse.question[0].name)] = receivedResponse
 
         self.assertEqual(len(receivedResponses), 5)
         for idx in range(5):
-            self.assertIn('%d.simple.ooor.tests.powerdns.com.' % (idx), receivedResponses)
+            self.assertIn("%d.simple.ooor.tests.powerdns.com." % (idx), receivedResponses)
 
         # we can get a response to one of the first query before they all have
         # been read, reusing a backend connection
@@ -217,13 +221,13 @@ class TestOOORWithClientNotBackend(DNSDistTest):
         OOORTCPResponder.numberOfConnections = 0
 
         for idx in range(100):
-            names.append('%d.more-queries.ooor.tests.powerdns.com.' % (idx))
+            names.append("%d.more-queries.ooor.tests.powerdns.com." % (idx))
 
         conn = self.openTCPConnection()
 
         counter = 0
         for name in names:
-            query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+            query = dns.message.make_query(name, "A", "IN", use_edns=False)
             query.id = counter
             counter = counter + 1
 
@@ -234,14 +238,15 @@ class TestOOORWithClientNotBackend(DNSDistTest):
         for _ in names:
             receivedResponse = self.recvTCPResponseOverConnection(conn)
             self.assertTrue(receivedResponse)
-            receivedResponses[str(receivedResponse.question[0].name)] = (receivedResponse)
+            receivedResponses[str(receivedResponse.question[0].name)] = receivedResponse
 
         self.assertEqual(len(receivedResponses), 100)
         for idx in range(5):
-            self.assertIn('%d.more-queries.ooor.tests.powerdns.com.' % (idx), receivedResponses)
+            self.assertIn("%d.more-queries.ooor.tests.powerdns.com." % (idx), receivedResponses)
 
         self.assertLessEqual(OOORTCPResponder.numberOfConnections, self._concurrentQueriesFromClient)
 
+
 class TestOOORWithClientAndBackend(DNSDistTest):
     # this test suite uses a different responder port
     _testServerPort = ReverseOOORResponderPort
@@ -255,7 +260,15 @@ class TestOOORWithClientAndBackend(DNSDistTest):
     addAction("more-queries.reverse-ooor.tests.powerdns.com.", PoolAction("more-queries"))
     setLocal("%s:%d", {maxInFlight=%d})
     """
-    _config_params = ['_testServerPort', '_concurrentQueriesToServer', '_testServerPort', '_concurrentQueriesToServer', '_dnsDistListeningAddr', '_dnsDistPort', '_concurrentQueriesFromClient']
+    _config_params = [
+        "_testServerPort",
+        "_concurrentQueriesToServer",
+        "_testServerPort",
+        "_concurrentQueriesToServer",
+        "_dnsDistListeningAddr",
+        "_dnsDistPort",
+        "_concurrentQueriesFromClient",
+    ]
     _verboseMode = True
     _skipListeningOnCL = True
 
@@ -271,13 +284,13 @@ class TestOOORWithClientAndBackend(DNSDistTest):
         ReverseOOORTCPResponder.numberOfConnections = 0
 
         for idx in range(5):
-            names.append('%d.simple.reverse-ooor.tests.powerdns.com.' % (idx))
+            names.append("%d.simple.reverse-ooor.tests.powerdns.com." % (idx))
 
         conn = self.openTCPConnection()
 
         counter = 0
         for name in names:
-            query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+            query = dns.message.make_query(name, "A", "IN", use_edns=False)
             query.id = counter
             counter = counter + 1
 
@@ -288,11 +301,11 @@ class TestOOORWithClientAndBackend(DNSDistTest):
         for _ in names:
             receivedResponse = self.recvTCPResponseOverConnection(conn)
             self.assertTrue(receivedResponse)
-            receivedResponses[str(receivedResponse.question[0].name)] = (receivedResponse)
+            receivedResponses[str(receivedResponse.question[0].name)] = receivedResponse
 
         self.assertEqual(len(receivedResponses), 5)
         for idx in range(5):
-            self.assertIn('%d.simple.reverse-ooor.tests.powerdns.com.' % (idx), receivedResponses)
+            self.assertIn("%d.simple.reverse-ooor.tests.powerdns.com." % (idx), receivedResponses)
 
         self.assertEqual(ReverseOOORTCPResponder.numberOfConnections, 1)
 
@@ -304,13 +317,13 @@ class TestOOORWithClientAndBackend(DNSDistTest):
         ReverseOOORTCPResponder.numberOfConnections = 0
 
         for idx in range(100):
-            names.append('%d.more-queries.reverse-ooor.tests.powerdns.com.' % (idx))
+            names.append("%d.more-queries.reverse-ooor.tests.powerdns.com." % (idx))
 
         conn = self.openTCPConnection()
 
         counter = 0
         for name in names:
-            query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+            query = dns.message.make_query(name, "A", "IN", use_edns=False)
             query.id = counter
             counter = counter + 1
 
@@ -321,12 +334,12 @@ class TestOOORWithClientAndBackend(DNSDistTest):
         for _ in names:
             receivedResponse = self.recvTCPResponseOverConnection(conn)
             self.assertTrue(receivedResponse)
-            receivedResponses[str(receivedResponse.question[0].name)] = (receivedResponse)
-            #print("Received a response for %s" % (receivedResponse.question[0].name))
+            receivedResponses[str(receivedResponse.question[0].name)] = receivedResponse
+            # print("Received a response for %s" % (receivedResponse.question[0].name))
 
         self.assertEqual(len(receivedResponses), 100)
         for idx in range(5):
-            self.assertIn('%d.more-queries.reverse-ooor.tests.powerdns.com.' % (idx), receivedResponses)
+            self.assertIn("%d.more-queries.reverse-ooor.tests.powerdns.com." % (idx), receivedResponses)
 
         # in theory they could all be handled by the same backend if we get the responses
         # fast enough, but over 100 queries that's very, very unlikely
index 959d52442aefd08bc8a1db9b894f8d8c0712d3bf..9aed27349a7f8474a48eb3ac7c89baf4e0a6238c 100644 (file)
@@ -42,20 +42,14 @@ class DNSDistOpenTelemetryProtobufTest(test_Protobuf.DNSDistProtobufTest):
             if spanID != "":
                 ottrace.data += binascii.a2b_hex(spanID)
             ottrace.data += b"\x00"  # flags
-            query = dns.message.make_query(
-                name, "A", "IN", use_edns=True, options=[ottrace]
-            )
+            query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ottrace])
 
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(
-            name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target
-        )
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(
-            target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1"
-        )
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         if useTCP:
@@ -98,19 +92,11 @@ class DNSDistOpenTelemetryProtobufTest(test_Protobuf.DNSDistProtobufTest):
 
         # Ensure the values are correct
         # TODO: query.remote with port
-        msg_scope_attr_keys = [
-            v["key"]
-            for v in otData["resource_spans"][0]["scope_spans"][0]["scope"][
-                "attributes"
-            ]
-        ]
+        msg_scope_attr_keys = [v["key"] for v in otData["resource_spans"][0]["scope_spans"][0]["scope"]["attributes"]]
         self.assertListEqual(msg_scope_attr_keys, ["instance"])
 
         root_span_attr_keys = [
-            v["key"]
-            for v in otData["resource_spans"][0]["scope_spans"][0]["spans"][0][
-                "attributes"
-            ]
+            v["key"] for v in otData["resource_spans"][0]["scope_spans"][0]["spans"][0]["attributes"]
         ]
         self.assertListEqual(
             root_span_attr_keys,
@@ -120,9 +106,7 @@ class DNSDistOpenTelemetryProtobufTest(test_Protobuf.DNSDistProtobufTest):
         # No way to guess the test port, but check the rest of the values
         root_span_attrs = {
             v["key"]: v["value"]["string_value"]
-            for v in otData["resource_spans"][0]["scope_spans"][0]["spans"][0][
-                "attributes"
-            ]
+            for v in otData["resource_spans"][0]["scope_spans"][0]["spans"][0]["attributes"]
             if v["key"] not in ["query.remote.port"]
         }
         self.assertDictEqual(
@@ -134,9 +118,7 @@ class DNSDistOpenTelemetryProtobufTest(test_Protobuf.DNSDistProtobufTest):
             root_span_attrs,
         )
 
-        msg_span_name = {
-            v["name"] for v in otData["resource_spans"][0]["scope_spans"][0]["spans"]
-        }
+        msg_span_name = {v["name"] for v in otData["resource_spans"][0]["scope_spans"][0]["spans"]}
 
         funcs = {
             "processQuery",
@@ -190,13 +172,9 @@ class DNSDistOpenTelemetryProtobufBaseTest(DNSDistOpenTelemetryProtobufTest):
         self.assertTrue(msg.HasField("openTelemetryData"))
         traces_data = opentelemetry.proto.trace.v1.trace_pb2.TracesData()
         traces_data.ParseFromString(msg.openTelemetryData)
-        ot_data = google.protobuf.json_format.MessageToDict(
-            traces_data, preserving_proto_field_name=True
-        )
+        ot_data = google.protobuf.json_format.MessageToDict(traces_data, preserving_proto_field_name=True)
 
-        self.checkOTData(
-            ot_data, hasProcessResponseAfterRules, useTCP, extraFunctions=extraFunctions
-        )
+        self.checkOTData(ot_data, hasProcessResponseAfterRules, useTCP, extraFunctions=extraFunctions)
 
         traceId = base64.b64encode(msg.openTelemetryTraceID).decode()
         for msg_span in ot_data["resource_spans"][0]["scope_spans"][0]["spans"]:
@@ -471,9 +449,7 @@ class DNSDistOpenTelemetryProtobufNoOTDataTest(DNSDistOpenTelemetryProtobufTest)
         self.assertFalse(msg.HasField("openTelemetryData"))
 
 
-class DNSDistOpenTelemetryProtobufEnabledButUnsetYAML(
-    DNSDistOpenTelemetryProtobufNoOTDataTest
-):
+class DNSDistOpenTelemetryProtobufEnabledButUnsetYAML(DNSDistOpenTelemetryProtobufNoOTDataTest):
     _yaml_config_params = ["_testServerPort", "_protobufServerPort"]
     _yaml_config_template = """---
 
@@ -503,9 +479,7 @@ response_rules:
         self.doTest()
 
 
-class DNSDistOpenTelemetryProtobufEnabledButUnsetLua(
-    DNSDistOpenTelemetryProtobufNoOTDataTest
-):
+class DNSDistOpenTelemetryProtobufEnabledButUnsetLua(DNSDistOpenTelemetryProtobufNoOTDataTest):
     _config_params = ["_testServerPort", "_protobufServerPort"]
     _config_template = """
 newServer{address="127.0.0.1:%d"}
@@ -519,9 +493,7 @@ addResponseAction(AllRule(), RemoteLogResponseAction(rl))
         self.doTest()
 
 
-class DNSDistOpenTelemetryProtobufEnabledSetButTurnedOffYAML(
-    DNSDistOpenTelemetryProtobufNoOTDataTest
-):
+class DNSDistOpenTelemetryProtobufEnabledSetButTurnedOffYAML(DNSDistOpenTelemetryProtobufNoOTDataTest):
     """Here we turn tracing on for the query, only to disable it after that"""
 
     _yaml_config_params = ["_testServerPort", "_protobufServerPort"]
@@ -567,9 +539,7 @@ response_rules:
         self.doTest()
 
 
-class DNSDistOpenTelemetryProtobufEnabledSetButTurnedOffLua(
-    DNSDistOpenTelemetryProtobufNoOTDataTest
-):
+class DNSDistOpenTelemetryProtobufEnabledSetButTurnedOffLua(DNSDistOpenTelemetryProtobufNoOTDataTest):
     _config_params = ["_testServerPort", "_protobufServerPort"]
     _config_template = """
 newServer{address="127.0.0.1:%d"}
@@ -585,9 +555,7 @@ addResponseAction(AllRule(), RemoteLogResponseAction(rl))
         self.doTest()
 
 
-class TestOpenTelemetryTracingBaseYAMLIncludedRemoteLoggerDropped(
-    DNSDistOpenTelemetryProtobufTest
-):
+class TestOpenTelemetryTracingBaseYAMLIncludedRemoteLoggerDropped(DNSDistOpenTelemetryProtobufTest):
     _yaml_config_params = [
         "_testServerPort",
         "_protobufServerPort",
@@ -628,9 +596,7 @@ response_rules:
         msg = self.sendQueryAndGetProtobuf(useTCP=useTCP, dropped=True)
         traces_data = opentelemetry.proto.trace.v1.trace_pb2.TracesData()
         traces_data.ParseFromString(msg.openTelemetryData)
-        ot_data = google.protobuf.json_format.MessageToDict(
-            traces_data, preserving_proto_field_name=True
-        )
+        ot_data = google.protobuf.json_format.MessageToDict(traces_data, preserving_proto_field_name=True)
 
         funcs = extraFunctions.union(
             {
@@ -684,9 +650,7 @@ addResponseAction(AllRule(), DropResponseAction(), {name="Drop"})
 """
 
 
-class TestOpenTelemetryTracingBaseYAMLIncludedRemoteLoggerSpoofed(
-    DNSDistOpenTelemetryProtobufTest
-):
+class TestOpenTelemetryTracingBaseYAMLIncludedRemoteLoggerSpoofed(DNSDistOpenTelemetryProtobufTest):
     _yaml_config_params = [
         "_testServerPort",
         "_protobufServerPort",
@@ -724,14 +688,10 @@ query_rules:
 """
 
     def doTest(self, useTCP=False, extraFunctions=set()):
-        msg = self.sendQueryAndGetProtobuf(
-            useTCP=useTCP, querySentByDNSDist=False, dropped=True
-        )
+        msg = self.sendQueryAndGetProtobuf(useTCP=useTCP, querySentByDNSDist=False, dropped=True)
         traces_data = opentelemetry.proto.trace.v1.trace_pb2.TracesData()
         traces_data.ParseFromString(msg.openTelemetryData)
-        ot_data = google.protobuf.json_format.MessageToDict(
-            traces_data, preserving_proto_field_name=True
-        )
+        ot_data = google.protobuf.json_format.MessageToDict(traces_data, preserving_proto_field_name=True)
 
         funcs = extraFunctions.union({"Rule: Spoof A record"})
         self.checkOTData(
@@ -758,9 +718,7 @@ def servfailOnTraceParent(request: dns.message.Message):
     return response.to_wire()
 
 
-class TestOpenTelemetryTracingStripIncomingTraceParent(
-    DNSDistOpenTelemetryProtobufTest
-):
+class TestOpenTelemetryTracingStripIncomingTraceParent(DNSDistOpenTelemetryProtobufTest):
     _yaml_config_params = [
         "_testServerPort",
     ]
@@ -823,9 +781,7 @@ query_rules:
         ottrace.data += binascii.a2b_hex("12345678901234567890123456789012")
         ottrace.data += binascii.a2b_hex("1234567890123456")
         ottrace.data += binascii.a2b_hex("00")
-        query = dns.message.make_query(
-            name, "A", "IN", use_edns=True, options=[ottrace]
-        )
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ottrace])
 
         if useTCP:
             _, receivedResponse = self.sendTCPQuery(query, response=None)
@@ -847,9 +803,7 @@ def verifyTraceparentInQuery(request: dns.message.Message):
     print(request)
     response = dns.message.make_response(request)
 
-    traceparent: dns.edns.Option | None = next(
-        (i for i in request.options if i.otype == 65500), None
-    )
+    traceparent: dns.edns.Option | None = next((i for i in request.options if i.otype == 65500), None)
 
     print(traceparent)
 
@@ -866,9 +820,7 @@ def verifyTraceparentInQuery(request: dns.message.Message):
     return response.to_wire()
 
 
-class TestOpenTelemetryTracingSendTraceparentDownstream(
-    DNSDistOpenTelemetryProtobufTest
-):
+class TestOpenTelemetryTracingSendTraceparentDownstream(DNSDistOpenTelemetryProtobufTest):
     _yaml_config_params = [
         "_testServerPort",
     ]
@@ -947,9 +899,7 @@ query_rules:
         self.doQuery(True)
 
 
-class TestOpenTelemetryTracingSendTraceparentDownstreamLua(
-    TestOpenTelemetryTracingSendTraceparentDownstream
-):
+class TestOpenTelemetryTracingSendTraceparentDownstreamLua(TestOpenTelemetryTracingSendTraceparentDownstream):
     _yaml_config_template = None
     _config_params = [
         "_testServerPort",
index 72878f13d442b4cf3e9db08d84bb6cb7cf720da6..8413773ed897a74a898fe56849be9b6e0b69359f 100644 (file)
@@ -10,31 +10,35 @@ import os
 
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class OutgoingDOHTests(object):
 
+class OutgoingDOHTests(object):
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerAPIKey = 'apisecret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
+    _webServerBasicAuthPassword = "secret"
+    _webServerAPIKey = "apisecret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
 
     def checkOnlyDOHResponderHit(self, numberOfDOHQueries=1):
-        self.assertNotIn('UDP Responder', self._responsesCounter)
-        self.assertNotIn('TCP Responder', self._responsesCounter)
-        self.assertNotIn('TLS Responder', self._responsesCounter)
-        self.assertEqual(self._responsesCounter['DoH Connection Handler'], numberOfDOHQueries)
+        self.assertNotIn("UDP Responder", self._responsesCounter)
+        self.assertNotIn("TCP Responder", self._responsesCounter)
+        self.assertNotIn("TLS Responder", self._responsesCounter)
+        self.assertEqual(self._responsesCounter["DoH Connection Handler"], numberOfDOHQueries)
 
     def getServerStat(self, key):
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        self.assertTrue(len(content['servers']), 1)
-        server = content['servers'][0]
+        self.assertTrue(len(content["servers"]), 1)
+        server = content["servers"][0]
         self.assertIn(key, server)
         return server[key]
 
@@ -42,17 +46,13 @@ class OutgoingDOHTests(object):
         """
         Outgoing DOH: UDP query is sent via DOH
         """
-        name = 'udp.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
-        connsBefore = self.getServerStat('tcpReusedConnections')
+        connsBefore = self.getServerStat("tcpReusedConnections")
 
         numberOfUDPQueries = 10
         for _ in range(numberOfUDPQueries):
@@ -64,46 +64,38 @@ class OutgoingDOHTests(object):
         numberOfQueries = numberOfUDPQueries + 1
         self.checkOnlyDOHResponderHit(numberOfUDPQueries)
 
-        self.assertEqual(self.getServerStat('tcpNewConnections'), 1)
-        self.assertEqual(self.getServerStat('tcpReusedConnections'), connsBefore + numberOfQueries - 1)
-        self.assertEqual(self.getServerStat('tlsResumptions'), 0)
+        self.assertEqual(self.getServerStat("tcpNewConnections"), 1)
+        self.assertEqual(self.getServerStat("tcpReusedConnections"), connsBefore + numberOfQueries - 1)
+        self.assertEqual(self.getServerStat("tlsResumptions"), 0)
 
     def testTCP(self):
         """
         Outgoing DOH: TCP query is sent via DOH
         """
-        name = 'tcp.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tcp.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
-        connsBefore = self.getServerStat('tcpReusedConnections')
+        connsBefore = self.getServerStat("tcpReusedConnections")
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, expectedResponse)
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, expectedResponse)
         self.checkOnlyDOHResponderHit()
-        self.assertEqual(self.getServerStat('tcpNewConnections'), 1)
-        self.assertEqual(self.getServerStat('tcpReusedConnections'), connsBefore)
-        self.assertEqual(self.getServerStat('tlsResumptions'), 0)
+        self.assertEqual(self.getServerStat("tcpNewConnections"), 1)
+        self.assertEqual(self.getServerStat("tcpReusedConnections"), connsBefore)
+        self.assertEqual(self.getServerStat("tlsResumptions"), 0)
 
     def testUDPCache(self):
         """
         Outgoing DOH: UDP query is sent via DOH, should be cached
         """
-        name = 'udp.cached.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.cached.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
@@ -119,14 +111,10 @@ class OutgoingDOHTests(object):
         """
         Outgoing DOH: TCP query is sent via DOH, should be cached
         """
-        name = 'tcp.cached.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tcp.cached.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, expectedResponse)
@@ -144,29 +132,33 @@ class OutgoingDOHTests(object):
         self.sendConsoleCommand("getServer(0):setAuto()")
         time.sleep(2)
         status = self.sendConsoleCommand("if getServer(0):isUp() then return 'up' else return 'down' end").strip("\n")
-        self.assertEqual(status, 'up')
+        self.assertEqual(status, "up")
 
-class BrokenOutgoingDOHTests(object):
 
+class BrokenOutgoingDOHTests(object):
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerAPIKey = 'apisecret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
+    _webServerBasicAuthPassword = "secret"
+    _webServerAPIKey = "apisecret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
 
     def checkNoResponderHit(self):
-        self.assertNotIn('UDP Responder', self._responsesCounter)
-        self.assertNotIn('TCP Responder', self._responsesCounter)
-        self.assertNotIn('TLS Responder', self._responsesCounter)
-        self.assertNotIn('DOH Responder', self._responsesCounter)
+        self.assertNotIn("UDP Responder", self._responsesCounter)
+        self.assertNotIn("TCP Responder", self._responsesCounter)
+        self.assertNotIn("TLS Responder", self._responsesCounter)
+        self.assertNotIn("DOH Responder", self._responsesCounter)
 
     def testUDP(self):
         """
         Outgoing DOH (broken): UDP query is sent via DOH
         """
-        name = 'udp.broken-outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.broken-outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
@@ -176,54 +168,54 @@ class BrokenOutgoingDOHTests(object):
         """
         Outgoing DOH (broken): TCP query is sent via DOH
         """
-        name = 'tcp.broken-outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tcp.broken-outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
         self.checkNoResponderHit()
 
-class OutgoingDOHBrokenResponsesTests(object):
 
+class OutgoingDOHBrokenResponsesTests(object):
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerAPIKey = 'apisecret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
+    _webServerBasicAuthPassword = "secret"
+    _webServerAPIKey = "apisecret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
 
     def testUDP(self):
         """
         Outgoing DOH (broken responses): UDP query is sent via DOH
         """
-        name = '500-status.broken-responses.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "500-status.broken-responses.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
 
-        name = 'invalid-dns-payload.broken-responses.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "invalid-dns-payload.broken-responses.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
 
-        name = 'closing-connection-id.broken-responses.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "closing-connection-id.broken-responses.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
 
         # but a valid response should be successful
-        name = 'valid.broken-responses.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "valid.broken-responses.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         (_, receivedResponse) = self.sendUDPQuery(query, response)
@@ -235,42 +227,51 @@ class OutgoingDOHBrokenResponsesTests(object):
         """
         Outgoing DOH (broken responses): TCP query is sent via DOH
         """
-        name = '500-status.broken-responses.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "500-status.broken-responses.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
 
-        name = 'invalid-dns-payload.broken-responses.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "invalid-dns-payload.broken-responses.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
 
-        name = 'closing-connection-id.broken-responses.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "closing-connection-id.broken-responses.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
 
         # but a valid response should be successful
-        name = 'valid.broken-responses.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "valid.broken-responses.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         (_, receivedResponse) = self.sendTCPQuery(query, response)
         # we can't check the received query because the responder does not populate the queue..
-        #self.assertEqual(query, receivedQuery)
+        # self.assertEqual(query, receivedQuery)
         self.assertEqual(response, receivedResponse)
 
+
 class TestOutgoingDOHOpenSSL(DNSDistTest, OutgoingDOHTests):
     if os.path.exists("/tmp/dohkeys"):
         os.remove("/tmp/dohkeys")
     _tlsBackendPort = pickAvailablePort()
-    _tlsProvider = 'openssl'
+    _tlsProvider = "openssl"
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_tlsBackendPort', '_tlsProvider', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_tlsBackendPort",
+        "_tlsProvider",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -292,29 +293,42 @@ class TestOutgoingDOHOpenSSL(DNSDistTest, OutgoingDOHTests):
 
     @staticmethod
     def sniCallback(sslSocket, sni, sslContext):
-        assert(sni == 'powerdns.com')
+        assert sni == "powerdns.com"
         return None
 
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
         tlsContext.set_alpn_protocols(["h2"])
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
         # requires Python 3.7+
-        if hasattr(tlsContext, 'sni_callback'):
+        if hasattr(tlsContext, "sni_callback"):
             tlsContext.sni_callback = cls.sniCallback
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
+
 class TestOutgoingDOHGnuTLS(DNSDistTest, OutgoingDOHTests):
     _tlsBackendPort = pickAvailablePort()
-    _tlsProvider = 'gnutls'
+    _tlsProvider = "gnutls"
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_tlsBackendPort', '_tlsProvider', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_tlsBackendPort",
+        "_tlsProvider",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -333,19 +347,24 @@ class TestOutgoingDOHGnuTLS(DNSDistTest, OutgoingDOHTests):
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
         tlsContext.keylog_filename = "/tmp/keys"
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
+
 class TestOutgoingDOHOpenSSLYaml(DNSDistTest, OutgoingDOHTests):
     _tlsBackendPort = pickAvailablePort()
-    _tlsProvider = 'openssl'
+    _tlsProvider = "openssl"
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _config_params = []
     _config_template = ""
     _yaml_config_template = """---
@@ -395,30 +414,48 @@ query_rules:
       type: "Pool"
       pool_name: "cache"
 """
-    _yaml_config_params = ['_consoleKeyB64', '_consolePort', '_tlsBackendPort', '_tlsProvider', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _yaml_config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_tlsBackendPort",
+        "_tlsProvider",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
 
     @staticmethod
     def sniCallback(sslSocket, sni, sslContext):
-        assert(sni == 'powerdns.com')
+        assert sni == "powerdns.com"
         return None
 
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
         tlsContext.set_alpn_protocols(["h2"])
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
         # requires Python 3.7+
-        if hasattr(tlsContext, 'sni_callback'):
+        if hasattr(tlsContext, "sni_callback"):
             tlsContext.sni_callback = cls.sniCallback
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
+
 class TestOutgoingDOHOpenSSLWrongCertName(DNSDistTest, BrokenOutgoingDOHTests):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='openssl', validateCertificates=true, caStore='ca.pem', subjectName='not-powerdns.com', dohPath='/dns-query'}:setUp()
@@ -429,16 +466,26 @@ class TestOutgoingDOHOpenSSLWrongCertName(DNSDistTest, BrokenOutgoingDOHTests):
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
+
 class TestOutgoingDOHGnuTLSWrongCertName(DNSDistTest, BrokenOutgoingDOHTests):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='gnutls', validateCertificates=true, caStore='ca.pem', subjectName='not-powerdns.com', dohPath='/dns-query'}:setUp()
@@ -449,19 +496,32 @@ class TestOutgoingDOHGnuTLSWrongCertName(DNSDistTest, BrokenOutgoingDOHTests):
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
+
 class TestOutgoingDOHOpenSSLWrongCertNameButNoCheck(DNSDistTest, OutgoingDOHTests):
     _tlsBackendPort = pickAvailablePort()
-    _tlsProvider = 'openssl'
+    _tlsProvider = "openssl"
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_tlsBackendPort', '_tlsProvider', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_tlsBackendPort",
+        "_tlsProvider",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -480,19 +540,32 @@ class TestOutgoingDOHOpenSSLWrongCertNameButNoCheck(DNSDistTest, OutgoingDOHTest
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
+
 class TestOutgoingDOHGnuTLSWrongCertNameButNoCheck(DNSDistTest, OutgoingDOHTests):
     _tlsBackendPort = pickAvailablePort()
-    _tlsProvider = 'gnutls'
+    _tlsProvider = "gnutls"
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_tlsBackendPort', '_tlsProvider', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_tlsBackendPort",
+        "_tlsProvider",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -511,16 +584,26 @@ class TestOutgoingDOHGnuTLSWrongCertNameButNoCheck(DNSDistTest, OutgoingDOHTests
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
+
 class TestOutgoingDOHBrokenResponsesOpenSSL(DNSDistTest, OutgoingDOHBrokenResponsesTests):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='openssl', validateCertificates=true, caStore='ca.pem', subjectName='powerdns.com', dohPath='/dns-query', pool={'', 'cache'}}:setUp()
@@ -536,14 +619,14 @@ class TestOutgoingDOHBrokenResponsesOpenSSL(DNSDistTest, OutgoingDOHBrokenRespon
 
     def callback(request, headers, fromQueue, toQueue):
 
-        if str(request.question[0].name) == '500-status.broken-responses.outgoing-doh.test.powerdns.com.':
+        if str(request.question[0].name) == "500-status.broken-responses.outgoing-doh.test.powerdns.com.":
             print("returning 500")
-            return 500, b'Server error'
+            return 500, b"Server error"
 
-        if str(request.question[0].name) == 'invalid-dns-payload.broken-responses.outgoing-doh.test.powerdns.com.':
-            return 200, b'not DNS'
+        if str(request.question[0].name) == "invalid-dns-payload.broken-responses.outgoing-doh.test.powerdns.com.":
+            return 200, b"not DNS"
 
-        if str(request.question[0].name) == 'closing-connection-id.broken-responses.outgoing-doh.test.powerdns.com.':
+        if str(request.question[0].name) == "closing-connection-id.broken-responses.outgoing-doh.test.powerdns.com.":
             return 200, None
 
         print("Returning default for %s" % (request.question[0].name))
@@ -553,16 +636,34 @@ class TestOutgoingDOHBrokenResponsesOpenSSL(DNSDistTest, OutgoingDOHBrokenRespon
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
         tlsContext.set_alpn_protocols(["h2"])
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.callback, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[
+                cls._tlsBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.callback,
+                tlsContext,
+            ],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
+
 class TestOutgoingDOHBrokenResponsesGnuTLS(DNSDistTest, OutgoingDOHBrokenResponsesTests):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='gnutls', validateCertificates=true, caStore='ca.pem', subjectName='powerdns.com', dohPath='/dns-query'}:setUp()
@@ -573,14 +674,14 @@ class TestOutgoingDOHBrokenResponsesGnuTLS(DNSDistTest, OutgoingDOHBrokenRespons
 
     def callback(request, headers, fromQueue, toQueue):
 
-        if str(request.question[0].name) == '500-status.broken-responses.outgoing-doh.test.powerdns.com.':
+        if str(request.question[0].name) == "500-status.broken-responses.outgoing-doh.test.powerdns.com.":
             print("returning 500")
-            return 500, b'Server error'
+            return 500, b"Server error"
 
-        if str(request.question[0].name) == 'invalid-dns-payload.broken-responses.outgoing-doh.test.powerdns.com.':
-            return 200, b'not DNS'
+        if str(request.question[0].name) == "invalid-dns-payload.broken-responses.outgoing-doh.test.powerdns.com.":
+            return 200, b"not DNS"
 
-        if str(request.question[0].name) == 'closing-connection-id.broken-responses.outgoing-doh.test.powerdns.com.':
+        if str(request.question[0].name) == "closing-connection-id.broken-responses.outgoing-doh.test.powerdns.com.":
             return 200, None
 
         print("Returning default for %s" % (request.question[0].name))
@@ -590,17 +691,29 @@ class TestOutgoingDOHBrokenResponsesGnuTLS(DNSDistTest, OutgoingDOHBrokenRespons
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
         tlsContext.set_alpn_protocols(["h2"])
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.callback, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[
+                cls._tlsBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.callback,
+                tlsContext,
+            ],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
-class TestOutgoingDOHProxyProtocol(DNSDistTest):
 
+class TestOutgoingDOHProxyProtocol(DNSDistTest):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort']
+    _config_params = ["_tlsBackendPort"]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='gnutls', validateCertificates=true, caStore='ca.pem', subjectName='powerdns.com', dohPath='/dns-query', useProxyProtocol=true}:setUp()
@@ -611,10 +724,23 @@ class TestOutgoingDOHProxyProtocol(DNSDistTest):
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
         tlsContext.set_alpn_protocols(["h2"])
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching DOH with Proxy Protocol responder..")
-        cls._DOHResponder = threading.Thread(name='DOH with Proxy Protocol Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext, True])
+        cls._DOHResponder = threading.Thread(
+            name="DOH with Proxy Protocol Responder",
+            target=cls.DOHResponder,
+            args=[
+                cls._tlsBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                None,
+                tlsContext,
+                True,
+            ],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
@@ -622,31 +748,28 @@ class TestOutgoingDOHProxyProtocol(DNSDistTest):
         """
         Outgoing DOH with Proxy Protocol
         """
-        name = 'proxy-protocol.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "proxy-protocol.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         (receivedProxyPayload, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
         receivedQuery = self._fromResponderQueue.get(True, 1.0)
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, expectedResponse)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', False)
+        self.checkMessageProxyProtocol(receivedProxyPayload, "127.0.0.1", "127.0.0.1", False)
 
         (receivedProxyPayload, receivedResponse) = self.sendTCPQuery(query, expectedResponse)
         receivedQuery = self._fromResponderQueue.get(True, 1.0)
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, expectedResponse)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True)
+        self.checkMessageProxyProtocol(receivedProxyPayload, "127.0.0.1", "127.0.0.1", True)
+
 
 class TestOutgoingDOHXForwarded(DNSDistTest):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort']
+    _config_params = ["_tlsBackendPort"]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='gnutls', validateCertificates=true, caStore='ca.pem', subjectName='powerdns.com', dohPath='/dns-query', addXForwardedHeaders=true}
@@ -655,24 +778,24 @@ class TestOutgoingDOHXForwarded(DNSDistTest):
 
     def callback(request, headersList, fromQueue, toQueue):
 
-        if str(request.question[0].name) == 'a.root-servers.net.':
+        if str(request.question[0].name) == "a.root-servers.net.":
             # do not check headers on health-check queries
             return 200, dns.message.make_response(request).to_wire()
 
         headers = {}
         if headersList:
-            for k,v in headersList:
+            for k, v in headersList:
                 headers[k] = v
 
-        if not b'x-forwarded-for' in headers:
+        if not b"x-forwarded-for" in headers:
             print("missing X-Forwarded-For")
-            return 406, b'Missing X-Forwarded-For header'
-        if not b'x-forwarded-port' in headers:
+            return 406, b"Missing X-Forwarded-For header"
+        if not b"x-forwarded-port" in headers:
             print("missing X-Forwarded-Port")
-            return 406, b'Missing X-Forwarded-Port header'
-        if not b'x-forwarded-proto' in headers:
+            return 406, b"Missing X-Forwarded-Port header"
+        if not b"x-forwarded-proto" in headers:
             print("missing X-Forwarded-Proto")
-            return 406, b'Missing X-Forwarded-Proto header'
+            return 406, b"Missing X-Forwarded-Proto header"
 
         toQueue.put(request, True, 1.0)
         response = fromQueue.get(True, 1.0)
@@ -686,10 +809,22 @@ class TestOutgoingDOHXForwarded(DNSDistTest):
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
         tlsContext.set_alpn_protocols(["h2"])
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, cls.callback, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[
+                cls._tlsBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                cls.callback,
+                tlsContext,
+            ],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
@@ -697,14 +832,10 @@ class TestOutgoingDOHXForwarded(DNSDistTest):
         """
         Outgoing DOH: X-Forwarded
         """
-        name = 'x-forwarded-for.outgoing-doh.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "x-forwarded-for.outgoing-doh.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
index e5109b2624c056dc4baf27373019a1e0e50cab7b..0a77d4906bedf6e808601191954b5a7af70e9445 100644 (file)
@@ -7,30 +7,34 @@ import os
 
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class OutgoingTLSTests(object):
 
+class OutgoingTLSTests(object):
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerAPIKey = 'apisecret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
+    _webServerBasicAuthPassword = "secret"
+    _webServerAPIKey = "apisecret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
 
     def checkOnlyTLSResponderHit(self, numberOfTLSQueries=1):
-        self.assertNotIn('UDP Responder', self._responsesCounter)
-        self.assertNotIn('TCP Responder', self._responsesCounter)
-        self.assertEqual(self._responsesCounter['TLS Responder'], numberOfTLSQueries)
+        self.assertNotIn("UDP Responder", self._responsesCounter)
+        self.assertNotIn("TCP Responder", self._responsesCounter)
+        self.assertEqual(self._responsesCounter["TLS Responder"], numberOfTLSQueries)
 
     def getServerStat(self, key):
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        self.assertTrue(len(content['servers']), 1)
-        server = content['servers'][0]
+        self.assertTrue(len(content["servers"]), 1)
+        server = content["servers"][0]
         self.assertIn(key, server)
         return server[key]
 
@@ -38,14 +42,10 @@ class OutgoingTLSTests(object):
         """
         Outgoing TLS: UDP query is sent via TLS
         """
-        name = 'udp.outgoing-tls.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.outgoing-tls.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         numberOfUDPQueries = 10
@@ -60,27 +60,23 @@ class OutgoingTLSTests(object):
         self.checkOnlyTLSResponderHit(numberOfUDPQueries)
         # our TLS responder does only one query per connection, so we need one for the TCP
         # query and one for the UDP one (the TCP test is done first)
-        self.assertEqual(self.getServerStat('tcpNewConnections'), numberOfQueries)
+        self.assertEqual(self.getServerStat("tcpNewConnections"), numberOfQueries)
         # we tried to reuse the connection (and then it failed but hey)
-        self.assertEqual(self.getServerStat('tcpReusedConnections'), numberOfQueries - 1)
+        self.assertEqual(self.getServerStat("tcpReusedConnections"), numberOfQueries - 1)
         # we resumed the TLS session, though, but since we only learn about that
         # when the connection is closed, we might be off by one, except if a health check
         # allowed the first TCP connection to be resumed as well
-        self.assertGreaterEqual(self.getServerStat('tlsResumptions'), numberOfUDPQueries - 1)
-        self.assertLessEqual(self.getServerStat('tlsResumptions'), numberOfUDPQueries)
+        self.assertGreaterEqual(self.getServerStat("tlsResumptions"), numberOfUDPQueries - 1)
+        self.assertLessEqual(self.getServerStat("tlsResumptions"), numberOfUDPQueries)
 
     def testTCP(self):
         """
         Outgoing TLS: TCP query is sent via TLS
         """
-        name = 'tcp.outgoing-tls.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tcp.outgoing-tls.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, expectedResponse)
@@ -88,30 +84,34 @@ class OutgoingTLSTests(object):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, expectedResponse)
         self.checkOnlyTLSResponderHit()
-        self.assertEqual(self.getServerStat('tcpNewConnections'), 1)
-        self.assertEqual(self.getServerStat('tcpReusedConnections'), 0)
-        self.assertEqual(self.getServerStat('tlsResumptions'), 0)
+        self.assertEqual(self.getServerStat("tcpNewConnections"), 1)
+        self.assertEqual(self.getServerStat("tcpReusedConnections"), 0)
+        self.assertEqual(self.getServerStat("tlsResumptions"), 0)
 
-class BrokenOutgoingTLSTests(object):
 
+class BrokenOutgoingTLSTests(object):
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerAPIKey = 'apisecret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
+    _webServerBasicAuthPassword = "secret"
+    _webServerAPIKey = "apisecret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
 
     def checkNoResponderHit(self):
-        self.assertNotIn('UDP Responder', self._responsesCounter)
-        self.assertNotIn('TCP Responder', self._responsesCounter)
-        self.assertNotIn('TLS Responder', self._responsesCounter)
+        self.assertNotIn("UDP Responder", self._responsesCounter)
+        self.assertNotIn("TCP Responder", self._responsesCounter)
+        self.assertNotIn("TLS Responder", self._responsesCounter)
 
     def testUDP(self):
         """
         Outgoing TLS (broken): UDP query is sent via TLS
         """
-        name = 'udp.broken-outgoing-tls.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.broken-outgoing-tls.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
@@ -121,25 +121,27 @@ class BrokenOutgoingTLSTests(object):
         """
         Outgoing TLS (broken): TCP query is sent via TLS
         """
-        name = 'tcp.broken-outgoing-tls.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tcp.broken-outgoing-tls.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
         self.checkNoResponderHit()
 
+
 class TestOutgoingTLSOpenSSL(DNSDistTest, OutgoingTLSTests):
     if os.path.exists("/tmp/dotkeys"):
         os.remove("/tmp/dotkeys")
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='openssl', validateCertificates=true, caStore='ca.pem', subjectName='powerdns.com', keyLogFile="/tmp/dotkeys"}
@@ -153,22 +155,27 @@ class TestOutgoingTLSOpenSSL(DNSDistTest, OutgoingTLSTests):
 
     @staticmethod
     def sniCallback(sslSocket, sni, sslContext):
-        assert(sni == 'powerdns.com')
+        assert sni == "powerdns.com"
         return None
 
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
         # requires Python 3.7+
-        if hasattr(tlsContext, 'sni_callback'):
+        if hasattr(tlsContext, "sni_callback"):
             tlsContext.sni_callback = cls.sniCallback
 
         print("Launching TLS responder..")
-        cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._TLSResponder = threading.Thread(
+            name="TLS Responder",
+            target=cls.TCPResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
 
+
 class TestOutgoingTLSOpenSSLYaml(DNSDistTest, OutgoingTLSTests):
     _tlsBackendPort = pickAvailablePort()
     _config_params = []
@@ -193,29 +200,44 @@ tuning:
   tcp:
     worker_threads: 1
     """
-    _yaml_config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _yaml_config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
 
     @staticmethod
     def sniCallback(sslSocket, sni, sslContext):
-        assert(sni == 'powerdns.com')
+        assert sni == "powerdns.com"
         return None
 
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
         # requires Python 3.7+
-        if hasattr(tlsContext, 'sni_callback'):
+        if hasattr(tlsContext, "sni_callback"):
             tlsContext.sni_callback = cls.sniCallback
 
         print("Launching TLS responder..")
-        cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._TLSResponder = threading.Thread(
+            name="TLS Responder",
+            target=cls.TCPResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
 
+
 class TestOutgoingTLSGnuTLS(DNSDistTest, OutgoingTLSTests):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='gnutls', validateCertificates=true, caStore='ca.pem', subjectName='powerdns.com'}
@@ -226,17 +248,27 @@ class TestOutgoingTLSGnuTLS(DNSDistTest, OutgoingTLSTests):
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
         tlsContext.keylog_filename = "/tmp/keys"
 
         print("Launching TLS responder..")
-        cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._TLSResponder = threading.Thread(
+            name="TLS Responder",
+            target=cls.TCPResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
 
+
 class TestOutgoingTLSOpenSSLWrongCertName(DNSDistTest, BrokenOutgoingTLSTests):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='openssl', validateCertificates=true, caStore='ca.pem', subjectName='not-powerdns.com'}
@@ -247,16 +279,26 @@ class TestOutgoingTLSOpenSSLWrongCertName(DNSDistTest, BrokenOutgoingTLSTests):
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching TLS responder..")
-        cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._TLSResponder = threading.Thread(
+            name="TLS Responder",
+            target=cls.TCPResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
 
+
 class TestOutgoingTLSGnuTLSWrongCertName(DNSDistTest, BrokenOutgoingTLSTests):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='gnutls', validateCertificates=true, caStore='ca.pem', subjectName='not-powerdns.com'}
@@ -267,16 +309,26 @@ class TestOutgoingTLSGnuTLSWrongCertName(DNSDistTest, BrokenOutgoingTLSTests):
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching TLS responder..")
-        cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._TLSResponder = threading.Thread(
+            name="TLS Responder",
+            target=cls.TCPResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
 
+
 class TestOutgoingTLSOpenSSLWrongCertNameButNoCheck(DNSDistTest, OutgoingTLSTests):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='openssl', validateCertificates=false, caStore='ca.pem', subjectName='not-powerdns.com'}
@@ -287,16 +339,26 @@ class TestOutgoingTLSOpenSSLWrongCertNameButNoCheck(DNSDistTest, OutgoingTLSTest
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching TLS responder..")
-        cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._TLSResponder = threading.Thread(
+            name="TLS Responder",
+            target=cls.TCPResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
 
+
 class TestOutgoingTLSGnuTLSWrongCertNameButNoCheck(DNSDistTest, OutgoingTLSTests):
     _tlsBackendPort = pickAvailablePort()
-    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _config_params = [
+        "_tlsBackendPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%d", tls='gnutls', validateCertificates=false, caStore='ca.pem', subjectName='not-powerdns.com'}
@@ -307,10 +369,14 @@ class TestOutgoingTLSGnuTLSWrongCertNameButNoCheck(DNSDistTest, OutgoingTLSTests
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching TLS responder..")
-        cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._TLSResponder = threading.Thread(
+            name="TLS Responder",
+            target=cls.TCPResponder,
+            args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext],
+        )
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
 
index 7e6c31b0fb221d0d4b40a336bf7e218194895890..69f7d42c43aaeb5552ac5c7a59db0a7aae511448 100644 (file)
@@ -2,6 +2,7 @@
 import dns
 from dnsdisttests import DNSDistTest
 
+
 class TestPoolManagement(DNSDistTest):
     _config_template = """
     local backendPort = %d
@@ -22,14 +23,10 @@ class TestPoolManagement(DNSDistTest):
         """
         Pool management: A query without EDNS
         """
-        name = 'pool-mngmt.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "pool-mngmt.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index ee781d7b658abb52be067ddd498d68a4094ce2da..2e0a084e2f881699e28cbcecd62d5f9cf697d28d 100644 (file)
@@ -8,13 +8,16 @@ from dnsdisttests import DNSDistTest, pickAvailablePort
 
 @unittest.skipIf("SKIP_PROMETHEUS_TESTS" in os.environ, "Prometheus tests are disabled")
 class TestPrometheus(DNSDistTest):
-
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
     _webServerBasicAuthPassword = "secret"
-    _webServerBasicAuthPasswordHashed = "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
     _webServerAPIKey = "apisecret"
-    _webServerAPIKeyHashed = "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
     _config_params = [
         "_testServerPort",
         "_webServerPort",
@@ -60,17 +63,14 @@ class TestPrometheus(DNSDistTest):
                 self.assertEqual(len(tokens), 2)
                 if not line.startswith("dnsdist_") and not line.startswith("custom_"):
                     raise AssertionError(
-                        "Expecting prometheus metric to be prefixed by 'dnsdist_', got: \"%s\""
-                        % (line)
+                        "Expecting prometheus metric to be prefixed by 'dnsdist_', got: \"%s\"" % (line)
                     )
                 key = tokens[0]
                 if key in keysSeen:
                     raise AssertionError(f"Duplicate prometheus key: '{key}'")
                 keysSeen[key] = True
 
-    def checkMetric(
-        self, content, name, expectedType, expectedValue, expectedLabels=""
-    ):
+    def checkMetric(self, content, name, expectedType, expectedValue, expectedLabels=""):
         typeFound = False
         helpFound = False
         valueFound = False
@@ -117,15 +117,11 @@ class TestPrometheus(DNSDistTest):
             )
             output = process.communicate(input=content)
         except subprocess.CalledProcessError as exc:
-            raise AssertionError(
-                "%s failed (%d): %s" % (testcmd, process.returncode, process.output)
-            )
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, process.output))
 
         # promtool may return 3 because of the "_total" suffix warnings
         if not process.returncode in [0, 3]:
-            raise AssertionError(
-                "%s failed (%d): %s" % (testcmd, process.returncode, output)
-            )
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, output))
 
         for line in output[0].splitlines():
             if line.endswith(b'should have "_total" suffix'):
@@ -152,12 +148,8 @@ class TestPrometheus(DNSDistTest):
         self.checkMetric(r.text, "dnsdist_custom_metric1", "counter", 1)
         self.checkMetric(r.text, "dnsdist_custom_metric2", "gauge", 0)
         self.checkMetric(r.text, "custom_prometheus_name", "counter", 0)
-        self.checkMetric(
-            r.text, "dnsdist_custom_metric_foo", "counter", 1, '{x="bar",y="xyz"}'
-        )
-        self.checkMetric(
-            r.text, "dnsdist_custom_metric_foo", "counter", 1, '{x="baz",y="abc"}'
-        )
+        self.checkMetric(r.text, "dnsdist_custom_metric_foo", "counter", 1, '{x="bar",y="xyz"}')
+        self.checkMetric(r.text, "dnsdist_custom_metric_foo", "counter", 1, '{x="baz",y="abc"}')
 
 
 class TestPrometheusWithInstance(TestPrometheus):
@@ -205,15 +197,9 @@ class TestPrometheusWithInstance(TestPrometheus):
         self.checkPrometheusContentWithInstance(r.text)
 
         self.checkPrometheusContentPromtool(r.content)
-        self.checkMetric(
-            r.text, "dnsdist_custom_metric1", "counter", 1, '{instance="my-id"}'
-        )
-        self.checkMetric(
-            r.text, "dnsdist_custom_metric2", "gauge", 0, '{instance="my-id"}'
-        )
-        self.checkMetric(
-            r.text, "custom_prometheus_name", "counter", 0, '{instance="my-id"}'
-        )
+        self.checkMetric(r.text, "dnsdist_custom_metric1", "counter", 1, '{instance="my-id"}')
+        self.checkMetric(r.text, "dnsdist_custom_metric2", "gauge", 0, '{instance="my-id"}')
+        self.checkMetric(r.text, "custom_prometheus_name", "counter", 0, '{instance="my-id"}')
         self.checkMetric(
             r.text,
             "dnsdist_custom_metric_foo",
index 551a8ac85fe8fd913441302c2376cc870066bb10..f43e1534d7304199eebe78f3fe92f1ff2e02c03a 100644 (file)
@@ -14,10 +14,11 @@ import dns
 import dnsmessage_pb2
 import extendederrors
 
+
 class DNSDistProtobufTest(DNSDistTest):
     _protobufServerPort = pickAvailablePort()
     _protobufQueue = Queue()
-    _protobufServerID = 'dnsdist-server-1'
+    _protobufServerID = "dnsdist-server-1"
     _protobufCounter = 0
 
     @classmethod
@@ -60,15 +61,25 @@ class DNSDistProtobufTest(DNSDistTest):
 
     @classmethod
     def startResponders(cls):
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._protobufListener = threading.Thread(name='Protobuf Listener', target=cls.ProtobufListener, args=[cls._protobufServerPort])
+        cls._protobufListener = threading.Thread(
+            name="Protobuf Listener", target=cls.ProtobufListener, args=[cls._protobufServerPort]
+        )
         cls._protobufListener.daemon = True
         cls._protobufListener.start()
 
@@ -82,53 +93,55 @@ class DNSDistProtobufTest(DNSDistTest):
 
     def checkProtobufBase(self, msg, protocol, query, initiator, normalQueryResponse=True, v6=False, flags=None):
         self.assertTrue(msg)
-        self.assertTrue(msg.HasField('timeSec'))
-        self.assertTrue(msg.HasField('socketFamily'))
+        self.assertTrue(msg.HasField("timeSec"))
+        self.assertTrue(msg.HasField("socketFamily"))
         if v6:
             self.assertEqual(msg.socketFamily, dnsmessage_pb2.PBDNSMessage.INET6)
         else:
             self.assertEqual(msg.socketFamily, dnsmessage_pb2.PBDNSMessage.INET)
-        self.assertTrue(msg.HasField('from'))
-        fromvalue = getattr(msg, 'from')
+        self.assertTrue(msg.HasField("from"))
+        fromvalue = getattr(msg, "from")
         if v6:
             self.assertEqual(socket.inet_ntop(socket.AF_INET6, fromvalue), initiator)
         else:
             self.assertEqual(socket.inet_ntop(socket.AF_INET, fromvalue), initiator)
-        self.assertTrue(msg.HasField('socketProtocol'))
+        self.assertTrue(msg.HasField("socketProtocol"))
         self.assertEqual(msg.socketProtocol, protocol)
-        self.assertTrue(msg.HasField('messageId'))
-        self.assertTrue(msg.HasField('id'))
+        self.assertTrue(msg.HasField("messageId"))
+        self.assertTrue(msg.HasField("id"))
         self.assertEqual(msg.id, query.id)
-        self.assertTrue(msg.HasField('inBytes'))
-        self.assertTrue(msg.HasField('headerFlags'))
+        self.assertTrue(msg.HasField("inBytes"))
+        self.assertTrue(msg.HasField("headerFlags"))
         queryFlags = flags or int.from_bytes(query.to_wire()[2:4], byteorder=sys.byteorder)
         self.assertEqual(msg.headerFlags, queryFlags)
-        self.assertTrue(msg.HasField('serverIdentity'))
-        self.assertEqual(msg.serverIdentity, self._protobufServerID.encode('utf-8'))
-
-        if normalQueryResponse and (protocol == dnsmessage_pb2.PBDNSMessage.UDP or protocol == dnsmessage_pb2.PBDNSMessage.TCP):
-          # compare inBytes with length of query/response
-          self.assertEqual(msg.inBytes, len(query.to_wire()))
+        self.assertTrue(msg.HasField("serverIdentity"))
+        self.assertEqual(msg.serverIdentity, self._protobufServerID.encode("utf-8"))
+
+        if normalQueryResponse and (
+            protocol == dnsmessage_pb2.PBDNSMessage.UDP or protocol == dnsmessage_pb2.PBDNSMessage.TCP
+        ):
+            # compare inBytes with length of query/response
+            self.assertEqual(msg.inBytes, len(query.to_wire()))
         # dnsdist doesn't set the existing EDNS Subnet for now,
         # although it might be set from Lua
         # self.assertTrue(msg.HasField('originalRequestorSubnet'))
         # self.assertEqual(len(msg.originalRequestorSubnet), 4)
         # self.assertEqual(socket.inet_ntop(socket.AF_INET, msg.originalRequestorSubnet), '127.0.0.1')
 
-    def checkProtobufQuery(self, msg, protocol, query, qclass, qtype, qname, initiator='127.0.0.1', v6=False):
+    def checkProtobufQuery(self, msg, protocol, query, qclass, qtype, qname, initiator="127.0.0.1", v6=False):
         self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSQueryType)
         self.checkProtobufBase(msg, protocol, query, initiator, v6=v6)
         # dnsdist doesn't fill the responder field for responses
         # because it doesn't keep the information around.
-        self.assertTrue(msg.HasField('to'))
+        self.assertTrue(msg.HasField("to"))
         if not v6:
-            self.assertEqual(socket.inet_ntop(socket.AF_INET, msg.to), '127.0.0.1')
-        self.assertTrue(msg.HasField('question'))
-        self.assertTrue(msg.question.HasField('qClass'))
+            self.assertEqual(socket.inet_ntop(socket.AF_INET, msg.to), "127.0.0.1")
+        self.assertTrue(msg.HasField("question"))
+        self.assertTrue(msg.question.HasField("qClass"))
         self.assertEqual(msg.question.qClass, qclass)
-        self.assertTrue(msg.question.HasField('qType'))
+        self.assertTrue(msg.question.HasField("qType"))
         self.assertEqual(msg.question.qClass, qtype)
-        self.assertTrue(msg.question.HasField('qName'))
+        self.assertTrue(msg.question.HasField("qName"))
         self.assertEqual(msg.question.qName, qname)
 
     def checkProtobufTags(self, tags, expectedTags):
@@ -137,32 +150,33 @@ class DNSDistProtobufTest(DNSDistTest):
         # exclusive or of lists should be empty
         self.assertEqual(len(listx), 0, "Protobuf tags don't match")
 
-    def checkProtobufQueryConvertedToResponse(self, msg, protocol, response, initiator='127.0.0.0', flags=None):
+    def checkProtobufQueryConvertedToResponse(self, msg, protocol, response, initiator="127.0.0.0", flags=None):
         self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSResponseType)
         # skip comparing inBytes (size of the query) with the length of the generated response
         self.checkProtobufBase(msg, protocol, response, initiator, False, flags=flags)
-        self.assertTrue(msg.HasField('response'))
-        self.assertTrue(msg.response.HasField('queryTimeSec'))
+        self.assertTrue(msg.HasField("response"))
+        self.assertTrue(msg.response.HasField("queryTimeSec"))
 
-    def checkProtobufResponse(self, msg, protocol, response, initiator='127.0.0.1', v6=False):
+    def checkProtobufResponse(self, msg, protocol, response, initiator="127.0.0.1", v6=False):
         self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSResponseType)
         self.checkProtobufBase(msg, protocol, response, initiator, v6=v6)
-        self.assertTrue(msg.HasField('response'))
-        self.assertTrue(msg.response.HasField('queryTimeSec'))
+        self.assertTrue(msg.HasField("response"))
+        self.assertTrue(msg.response.HasField("queryTimeSec"))
 
     def checkProtobufResponseRecord(self, record, rclass, rtype, rname, rttl):
-        self.assertTrue(record.HasField('class'))
-        self.assertEqual(getattr(record, 'class'), rclass)
-        self.assertTrue(record.HasField('type'))
+        self.assertTrue(record.HasField("class"))
+        self.assertEqual(getattr(record, "class"), rclass)
+        self.assertTrue(record.HasField("type"))
         self.assertEqual(record.type, rtype)
-        self.assertTrue(record.HasField('name'))
+        self.assertTrue(record.HasField("name"))
         self.assertEqual(record.name, rname)
-        self.assertTrue(record.HasField('ttl'))
+        self.assertTrue(record.HasField("ttl"))
         self.assertEqual(record.ttl, rttl)
-        self.assertTrue(record.HasField('rdata'))
+        self.assertTrue(record.HasField("rdata"))
+
 
 class TestProtobuf(DNSDistProtobufTest):
-    _config_params = ['_testServerPort', '_protobufServerPort', '_protobufServerID', '_protobufServerID']
+    _config_params = ["_testServerPort", "_protobufServerPort", "_protobufServerID", "_protobufServerID"]
     _config_template = """
     luasmn = newSuffixMatchNode()
     luasmn:add(newDNSName('lua.protobuf.tests.powerdns.com.'))
@@ -274,24 +288,16 @@ class TestProtobuf(DNSDistProtobufTest):
         """
         Protobuf: Send data to a protobuf server
         """
-        name = 'query.protobuf.tests.powerdns.com.'
+        name = "query.protobuf.tests.powerdns.com."
 
-        target = 'target.protobuf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        target = "target.protobuf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    target)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(target,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -309,19 +315,23 @@ class TestProtobuf(DNSDistProtobufTest):
         msg = self.getFirstProtobufMessage()
 
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
-        self.checkProtobufTags(msg.response.tags, [u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Query,123"])
+        self.checkProtobufTags(
+            msg.response.tags, ["TestLabel1,TestData1", "TestLabel2,TestData2", "TestLabel3,TestData3", "Query,123"]
+        )
 
         # check the protobuf message corresponding to the UDP response
         msg = self.getFirstProtobufMessage()
         self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response)
-        self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Response,456"])
+        self.checkProtobufTags(
+            msg.response.tags, ["TestLabel1,TestData1", "TestLabel2,TestData2", "TestLabel3,TestData3", "Response,456"]
+        )
         self.assertEqual(len(msg.response.rrs), 2)
         rr = msg.response.rrs[0]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 3600)
-        self.assertEqual(rr.rdata.decode('utf-8'), target)
+        self.assertEqual(rr.rdata.decode("utf-8"), target)
         rr = msg.response.rrs[1]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "127.0.0.1")
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
         self.assertTrue(receivedQuery)
@@ -338,36 +348,34 @@ class TestProtobuf(DNSDistProtobufTest):
         msg = self.getFirstProtobufMessage()
 
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.TCP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
-        self.checkProtobufTags(msg.response.tags, [u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Query,123"])
+        self.checkProtobufTags(
+            msg.response.tags, ["TestLabel1,TestData1", "TestLabel2,TestData2", "TestLabel3,TestData3", "Query,123"]
+        )
 
         # check the protobuf message corresponding to the TCP response
         msg = self.getFirstProtobufMessage()
         self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response)
-        self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Response,456"])
+        self.checkProtobufTags(
+            msg.response.tags, ["TestLabel1,TestData1", "TestLabel2,TestData2", "TestLabel3,TestData3", "Response,456"]
+        )
         self.assertEqual(len(msg.response.rrs), 2)
         rr = msg.response.rrs[0]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 3600)
-        self.assertEqual(rr.rdata.decode('utf-8'), target)
+        self.assertEqual(rr.rdata.decode("utf-8"), target)
         rr = msg.response.rrs[1]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "127.0.0.1")
 
     def testLuaProtobuf(self):
-
         """
         Protobuf: Check that the Lua callback rewrote the initiator
         """
-        name = 'lua.protobuf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "lua.protobuf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
 
         self.assertTrue(receivedQuery)
@@ -383,17 +391,23 @@ class TestProtobuf(DNSDistProtobufTest):
         # check the protobuf message corresponding to the UDP query
         msg = self.getFirstProtobufMessage()
         flags = int.from_bytes(query.to_wire()[2:4], byteorder=sys.byteorder)
-        self.checkProtobufQueryConvertedToResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response, '127.0.0.0', flags=flags)
-        self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Query,123"])
+        self.checkProtobufQueryConvertedToResponse(
+            msg, dnsmessage_pb2.PBDNSMessage.UDP, response, "127.0.0.0", flags=flags
+        )
+        self.checkProtobufTags(
+            msg.response.tags, ["TestLabel1,TestData1", "TestLabel2,TestData2", "TestLabel3,TestData3", "Query,123"]
+        )
 
         # check the protobuf message corresponding to the UDP response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response, '127.0.0.0')
-        self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Response,456"])
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response, "127.0.0.0")
+        self.checkProtobufTags(
+            msg.response.tags, ["TestLabel1,TestData1", "TestLabel2,TestData2", "TestLabel3,TestData3", "Response,456"]
+        )
         self.assertEqual(len(msg.response.rrs), 1)
         for rr in msg.response.rrs:
             self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 3600)
-            self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
+            self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "127.0.0.1")
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
         self.assertTrue(receivedQuery)
@@ -409,20 +423,27 @@ class TestProtobuf(DNSDistProtobufTest):
         # check the protobuf message corresponding to the TCP query
         msg = self.getFirstProtobufMessage()
         flags = int.from_bytes(query.to_wire()[2:4], byteorder=sys.byteorder)
-        self.checkProtobufQueryConvertedToResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response, '127.0.0.0', flags=flags)
-        self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Query,123"])
+        self.checkProtobufQueryConvertedToResponse(
+            msg, dnsmessage_pb2.PBDNSMessage.TCP, response, "127.0.0.0", flags=flags
+        )
+        self.checkProtobufTags(
+            msg.response.tags, ["TestLabel1,TestData1", "TestLabel2,TestData2", "TestLabel3,TestData3", "Query,123"]
+        )
 
         # check the protobuf message corresponding to the TCP response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response, '127.0.0.0')
-        self.checkProtobufTags(msg.response.tags, [ u"TestLabel1,TestData1", u"TestLabel2,TestData2", u"TestLabel3,TestData3", u"Response,456"])
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response, "127.0.0.0")
+        self.checkProtobufTags(
+            msg.response.tags, ["TestLabel1,TestData1", "TestLabel2,TestData2", "TestLabel3,TestData3", "Response,456"]
+        )
         self.assertEqual(len(msg.response.rrs), 1)
         for rr in msg.response.rrs:
             self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 3600)
-            self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
+            self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "127.0.0.1")
+
 
 class TestProtobufMetaTags(DNSDistProtobufTest):
-    _config_params = ['_testServerPort', '_protobufServerPort']
+    _config_params = ["_testServerPort", "_protobufServerPort"]
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     rl = newRemoteLogger('127.0.0.1:%d')
@@ -474,14 +495,10 @@ class TestProtobufMetaTags(DNSDistProtobufTest):
         """
         Protobuf: Meta values
         """
-        name = 'meta.protobuf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "meta.protobuf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -501,75 +518,76 @@ class TestProtobufMetaTags(DNSDistProtobufTest):
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
         # regular tags
         self.assertEqual(len(msg.response.tags), 2)
-        self.assertIn('my-tag-key:my-tag-value', msg.response.tags)
-        self.assertIn('my-empty-key', msg.response.tags)
+        self.assertIn("my-tag-key:my-tag-value", msg.response.tags)
+        self.assertIn("my-empty-key", msg.response.tags)
         # meta tags
         self.assertEqual(len(msg.meta), 4)
         tags = {}
         for entry in msg.meta:
             tags[entry.key] = entry.value.stringVal
 
-        self.assertIn('b64', tags)
-        self.assertIn('my-tag-export-name', tags)
+        self.assertIn("b64", tags)
+        self.assertIn("my-tag-export-name", tags)
 
-        self.assertEqual(msg.meta[2].key, 'my-meta-key-1')
+        self.assertEqual(msg.meta[2].key, "my-meta-key-1")
         self.assertEqual(len(msg.meta[2].value.stringVal), 2)
-        self.assertIn('test', msg.meta[2].value.stringVal)
-        self.assertIn('test2', msg.meta[2].value.stringVal)
+        self.assertIn("test", msg.meta[2].value.stringVal)
+        self.assertIn("test2", msg.meta[2].value.stringVal)
         self.assertIn(-42, msg.meta[2].value.intVal)
 
-        self.assertEqual(msg.meta[3].key, 'my-meta-key-3')
+        self.assertEqual(msg.meta[3].key, "my-meta-key-3")
         self.assertEqual(len(msg.meta[2].value.stringVal), 2)
-        self.assertIn('test', msg.meta[2].value.stringVal)
-        self.assertIn('test2', msg.meta[2].value.stringVal)
+        self.assertIn("test", msg.meta[2].value.stringVal)
+        self.assertIn("test2", msg.meta[2].value.stringVal)
         self.assertIn(-42, msg.meta[2].value.intVal)
 
-        b64EncodedQuery = base64.b64encode(query.to_wire()).decode('ascii')
-        self.assertEqual(tags['b64'], [b64EncodedQuery])
-        self.assertEqual(tags['my-tag-export-name'], ['my-tag-value'])
+        b64EncodedQuery = base64.b64encode(query.to_wire()).decode("ascii")
+        self.assertEqual(tags["b64"], [b64EncodedQuery])
+        self.assertEqual(tags["my-tag-export-name"], ["my-tag-value"])
 
         # check the protobuf message corresponding to the UDP response
         msg = self.getFirstProtobufMessage()
         self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response)
         # regular tags
         self.assertEqual(len(msg.response.tags), 2)
-        self.assertIn('my-tag-key2:my-tag-value2', msg.response.tags)
-        self.assertIn('my-empty-key', msg.response.tags)
+        self.assertIn("my-tag-key2:my-tag-value2", msg.response.tags)
+        self.assertIn("my-empty-key", msg.response.tags)
         # meta tags
         self.assertEqual(len(msg.meta), 5)
-        self.assertEqual(msg.meta[0].key, 'my-tag-export-name')
+        self.assertEqual(msg.meta[0].key, "my-tag-export-name")
         self.assertEqual(len(msg.meta[0].value.stringVal), 3)
-        self.assertIn('my-tag-key:my-tag-value', msg.meta[0].value.stringVal)
-        self.assertIn('my-tag-key2:my-tag-value2', msg.meta[0].value.stringVal)
+        self.assertIn("my-tag-key:my-tag-value", msg.meta[0].value.stringVal)
+        self.assertIn("my-tag-key2:my-tag-value2", msg.meta[0].value.stringVal)
         # no ':' when the value is empty
-        self.assertIn('my-empty-key', msg.meta[0].value.stringVal)
+        self.assertIn("my-empty-key", msg.meta[0].value.stringVal)
 
-        self.assertEqual(msg.meta[1].key, 'my-meta-key-1')
+        self.assertEqual(msg.meta[1].key, "my-meta-key-1")
         self.assertEqual(len(msg.meta[1].value.stringVal), 2)
-        self.assertIn('test', msg.meta[1].value.stringVal)
-        self.assertIn('test2', msg.meta[1].value.stringVal)
+        self.assertIn("test", msg.meta[1].value.stringVal)
+        self.assertIn("test2", msg.meta[1].value.stringVal)
         self.assertIn(-42, msg.meta[1].value.intVal)
 
-        self.assertEqual(msg.meta[2].key, 'my-meta-key-3')
+        self.assertEqual(msg.meta[2].key, "my-meta-key-3")
         self.assertEqual(len(msg.meta[2].value.stringVal), 2)
-        self.assertIn('test', msg.meta[2].value.stringVal)
-        self.assertIn('test2', msg.meta[2].value.stringVal)
+        self.assertIn("test", msg.meta[2].value.stringVal)
+        self.assertIn("test2", msg.meta[2].value.stringVal)
         self.assertIn(-42, msg.meta[2].value.intVal)
 
-        self.assertEqual(msg.meta[3].key, 'my-meta-key-2')
+        self.assertEqual(msg.meta[3].key, "my-meta-key-2")
         self.assertEqual(len(msg.meta[3].value.stringVal), 2)
-        self.assertIn('foo', msg.meta[3].value.stringVal)
-        self.assertIn('bar', msg.meta[3].value.stringVal)
+        self.assertIn("foo", msg.meta[3].value.stringVal)
+        self.assertIn("bar", msg.meta[3].value.stringVal)
         self.assertIn(42, msg.meta[3].value.intVal)
 
-        self.assertEqual(msg.meta[4].key, 'my-meta-key-4')
+        self.assertEqual(msg.meta[4].key, "my-meta-key-4")
         self.assertEqual(len(msg.meta[4].value.stringVal), 2)
-        self.assertIn('foo', msg.meta[4].value.stringVal)
-        self.assertIn('bar', msg.meta[4].value.stringVal)
+        self.assertIn("foo", msg.meta[4].value.stringVal)
+        self.assertIn("bar", msg.meta[4].value.stringVal)
         self.assertIn(42, msg.meta[4].value.intVal)
 
+
 class TestProtobufExtendedDNSErrorTags(DNSDistProtobufTest):
-    _config_params = ['_testServerPort', '_protobufServerPort']
+    _config_params = ["_testServerPort", "_protobufServerPort"]
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     rl = newRemoteLogger('127.0.0.1:%d')
@@ -582,16 +600,12 @@ class TestProtobufExtendedDNSErrorTags(DNSDistProtobufTest):
         """
         Protobuf: Extended Error
         """
-        name = 'extended-error.protobuf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "extended-error.protobuf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
-        ede = extendederrors.ExtendedErrorOption(15, b'Blocked by RPZ!')
+        ede = extendederrors.ExtendedErrorOption(15, b"Blocked by RPZ!")
         response.use_edns(edns=True, payload=4096, options=[ede])
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -620,14 +634,15 @@ class TestProtobufExtendedDNSErrorTags(DNSDistProtobufTest):
         # meta tags
         self.assertEqual(len(msg.meta), 1)
 
-        self.assertEqual(msg.meta[0].key, 'extended-error')
+        self.assertEqual(msg.meta[0].key, "extended-error")
         self.assertEqual(len(msg.meta[0].value.intVal), 1)
         self.assertEqual(len(msg.meta[0].value.stringVal), 1)
         self.assertIn(15, msg.meta[0].value.intVal)
-        self.assertIn('Blocked by RPZ!', msg.meta[0].value.stringVal)
+        self.assertIn("Blocked by RPZ!", msg.meta[0].value.stringVal)
+
 
 class TestProtobufCacheHit(DNSDistProtobufTest):
-    _config_params = ['_testServerPort', '_protobufServerPort']
+    _config_params = ["_testServerPort", "_protobufServerPort"]
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     rl = newRemoteLogger('127.0.0.1:%d')
@@ -642,14 +657,10 @@ class TestProtobufCacheHit(DNSDistProtobufTest):
         """
         Protobuf: CacheHit field
         """
-        name = 'cachehit.protobuf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "cachehit.protobuf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # fill the cache
@@ -667,9 +678,9 @@ class TestProtobufCacheHit(DNSDistProtobufTest):
         # check the protobuf message corresponding to the UDP response
         msg = self.getFirstProtobufMessage()
         self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response)
-        self.assertTrue(msg.HasField('packetCacheHit'))
+        self.assertTrue(msg.HasField("packetCacheHit"))
         self.assertFalse(msg.packetCacheHit)
-        self.assertTrue(msg.HasField('outgoingQueries'))
+        self.assertTrue(msg.HasField("outgoingQueries"))
         self.assertEqual(msg.outgoingQueries, 1)
 
         # now should be a cache hit
@@ -684,21 +695,21 @@ class TestProtobufCacheHit(DNSDistProtobufTest):
         # check the protobuf message corresponding to the UDP response
         msg = self.getFirstProtobufMessage()
         self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response)
-        self.assertTrue(msg.HasField('packetCacheHit'))
+        self.assertTrue(msg.HasField("packetCacheHit"))
         self.assertTrue(msg.packetCacheHit)
-        self.assertTrue(msg.HasField('outgoingQueries'))
+        self.assertTrue(msg.HasField("outgoingQueries"))
         self.assertEqual(msg.outgoingQueries, 0)
 
-@unittest.skipIf('SKIP_DOH_TESTS' in os.environ, 'DNS over HTTPS tests are disabled')
-class TestProtobufMetaDOH(DNSDistProtobufTest):
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+@unittest.skipIf("SKIP_DOH_TESTS" in os.environ, "DNS over HTTPS tests are disabled")
+class TestProtobufMetaDOH(DNSDistProtobufTest):
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
-    _dohWithNGHTTP2BaseURL = ("https://%s:%d/dns-query" % (_serverName, _dohWithNGHTTP2ServerPort))
+    _dohWithNGHTTP2BaseURL = "https://%s:%d/dns-query" % (_serverName, _dohWithNGHTTP2ServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     rl = newRemoteLogger('127.0.0.1:%d')
@@ -710,20 +721,25 @@ class TestProtobufMetaDOH(DNSDistProtobufTest):
     addAction(AllRule(), RemoteLogAction(rl, nil, {serverID='dnsdist-server-1'}, mytags))
     addResponseAction(AllRule(), RemoteLogResponseAction(rl, nil, false, {serverID='dnsdist-server-1'}, mytags))
     """
-    _config_params = ['_testServerPort', '_protobufServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey']
+    _config_params = [
+        "_testServerPort",
+        "_protobufServerPort",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_dohWithNGHTTP2ServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
 
     def testProtobufMetaDoH(self):
         """
         Protobuf: Meta values - DoH
         """
-        name = 'meta-doh.protobuf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "meta-doh.protobuf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery", "sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper"):
@@ -759,18 +775,18 @@ class TestProtobufMetaDOH(DNSDistProtobufTest):
                 self.assertEqual(len(entry.value.stringVal), 1)
                 tags[entry.key] = entry.value.stringVal[0]
 
-            self.assertIn('agent', tags)
+            self.assertIn("agent", tags)
             if method == "sendDOHWithNGHTTP2QueryWrapper":
-                self.assertIn('PycURL', tags['agent'])
-                self.assertIn('host', tags)
+                self.assertIn("PycURL", tags["agent"])
+                self.assertIn("host", tags)
                 if method == "sendDOHWithNGHTTP2QueryWrapper":
-                    self.assertEqual(tags['host'], self._serverName + ':' + str(self._dohWithNGHTTP2ServerPort))
-                self.assertIn('path', tags)
-                self.assertEqual(tags['path'], '/dns-query')
-                self.assertIn('query-string', tags)
-                self.assertIn('?dns=', tags['query-string'])
-                self.assertIn('scheme', tags)
-                self.assertEqual(tags['scheme'], 'https')
+                    self.assertEqual(tags["host"], self._serverName + ":" + str(self._dohWithNGHTTP2ServerPort))
+                self.assertIn("path", tags)
+                self.assertEqual(tags["path"], "/dns-query")
+                self.assertIn("query-string", tags)
+                self.assertIn("?dns=", tags["query-string"])
+                self.assertIn("scheme", tags)
+                self.assertEqual(tags["scheme"], "https")
                 self.assertEqual(msg.httpVersion, dnsmessage_pb2.PBDNSMessage.HTTPVersion.HTTP2)
 
             # check the protobuf message corresponding to the response
@@ -782,22 +798,22 @@ class TestProtobufMetaDOH(DNSDistProtobufTest):
                 self.assertEqual(len(entry.value.stringVal), 1)
                 tags[entry.key] = entry.value.stringVal[0]
 
-            self.assertIn('agent', tags)
+            self.assertIn("agent", tags)
             if method == "sendDOHWithNGHTTP2QueryWrapper":
-                self.assertIn('PycURL', tags['agent'])
-                self.assertIn('host', tags)
+                self.assertIn("PycURL", tags["agent"])
+                self.assertIn("host", tags)
                 if method == "sendDOHWithNGHTTP2QueryWrapper":
-                    self.assertEqual(tags['host'], self._serverName + ':' + str(self._dohWithNGHTTP2ServerPort))
-                self.assertIn('path', tags)
-                self.assertEqual(tags['path'], '/dns-query')
-                self.assertIn('query-string', tags)
-                self.assertIn('?dns=', tags['query-string'])
-                self.assertIn('scheme', tags)
-                self.assertEqual(tags['scheme'], 'https')
+                    self.assertEqual(tags["host"], self._serverName + ":" + str(self._dohWithNGHTTP2ServerPort))
+                self.assertIn("path", tags)
+                self.assertEqual(tags["path"], "/dns-query")
+                self.assertIn("query-string", tags)
+                self.assertIn("?dns=", tags["query-string"])
+                self.assertIn("scheme", tags)
+                self.assertEqual(tags["scheme"], "https")
 
-class TestProtobufMetaProxy(DNSDistProtobufTest):
 
-    _config_params = ['_testServerPort', '_protobufServerPort']
+class TestProtobufMetaProxy(DNSDistProtobufTest):
+    _config_params = ["_testServerPort", "_protobufServerPort"]
     _config_template = """
     setProxyProtocolACL( { "127.0.0.1/32" } )
 
@@ -814,21 +830,19 @@ class TestProtobufMetaProxy(DNSDistProtobufTest):
         """
         Protobuf: Meta values - Proxy
         """
-        name = 'meta-proxy.protobuf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "meta-proxy.protobuf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         destAddr = "2001:db8::9"
         destPort = 9999
         srcAddr = "2001:db8::8"
         srcPort = 8888
-        udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 42, b'proxy'] ])
+        udpPayload = ProxyProtocol.getPayload(
+            False, False, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [42, b"proxy"]]
+        )
         (receivedQuery, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(), response, rawQuery=True)
 
         self.assertTrue(receivedQuery)
@@ -844,21 +858,31 @@ class TestProtobufMetaProxy(DNSDistProtobufTest):
         # check the protobuf message corresponding to the UDP query
         msg = self.getFirstProtobufMessage()
 
-        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, initiator='2001:db8::8', v6=True)
+        self.checkProtobufQuery(
+            msg,
+            dnsmessage_pb2.PBDNSMessage.UDP,
+            query,
+            dns.rdataclass.IN,
+            dns.rdatatype.A,
+            name,
+            initiator="2001:db8::8",
+            v6=True,
+        )
         self.assertEqual(len(msg.meta), 2)
         tags = {}
         for entry in msg.meta:
             tags[entry.key] = entry.value.stringVal
 
-        self.assertIn('pp42', tags)
-        self.assertEqual(tags['pp42'], ['proxy'])
-        self.assertIn('pp', tags)
-        self.assertEqual(len(tags['pp']), 2)
-        self.assertIn('2:foo', tags['pp'])
-        self.assertIn('42:proxy', tags['pp'])
+        self.assertIn("pp42", tags)
+        self.assertEqual(tags["pp42"], ["proxy"])
+        self.assertIn("pp", tags)
+        self.assertEqual(len(tags["pp"]), 2)
+        self.assertIn("2:foo", tags["pp"])
+        self.assertIn("42:proxy", tags["pp"])
+
 
 class TestProtobufIPCipher(DNSDistProtobufTest):
-    _config_params = ['_testServerPort', '_protobufServerPort', '_protobufServerID', '_protobufServerID']
+    _config_params = ["_testServerPort", "_protobufServerPort", "_protobufServerID", "_protobufServerID"]
     _config_template = """
     newServer{address="127.0.0.1:%d", useClientSubnet=true}
     key = makeIPCipherKey("some 16-byte key")
@@ -872,24 +896,16 @@ class TestProtobufIPCipher(DNSDistProtobufTest):
         """
         Protobuf: Send data to a protobuf server, with pseudonymization
         """
-        name = 'query.protobuf-ipcipher.tests.powerdns.com.'
+        name = "query.protobuf-ipcipher.tests.powerdns.com."
 
-        target = 'target.protobuf-ipcipher.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        target = "target.protobuf-ipcipher.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    target)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(target,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -907,19 +923,21 @@ class TestProtobufIPCipher(DNSDistProtobufTest):
         msg = self.getFirstProtobufMessage()
 
         # 108.41.239.98 is 127.0.0.1 pseudonymized with ipcipher and the current key
-        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '108.41.239.98')
+        self.checkProtobufQuery(
+            msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, "108.41.239.98"
+        )
 
         # check the protobuf message corresponding to the UDP response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response, '108.41.239.98')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response, "108.41.239.98")
 
         self.assertEqual(len(msg.response.rrs), 2)
         rr = msg.response.rrs[0]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 3600)
-        self.assertEqual(rr.rdata.decode('ascii'), target)
+        self.assertEqual(rr.rdata.decode("ascii"), target)
         rr = msg.response.rrs[1]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "127.0.0.1")
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
         self.assertTrue(receivedQuery)
@@ -935,21 +953,24 @@ class TestProtobufIPCipher(DNSDistProtobufTest):
         # check the protobuf message corresponding to the TCP query
         msg = self.getFirstProtobufMessage()
         # 108.41.239.98 is 127.0.0.1 pseudonymized with ipcipher and the current key
-        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.TCP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '108.41.239.98')
+        self.checkProtobufQuery(
+            msg, dnsmessage_pb2.PBDNSMessage.TCP, query, dns.rdataclass.IN, dns.rdatatype.A, name, "108.41.239.98"
+        )
 
         # check the protobuf message corresponding to the TCP response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response, '108.41.239.98')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response, "108.41.239.98")
         self.assertEqual(len(msg.response.rrs), 2)
         rr = msg.response.rrs[0]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 3600)
-        self.assertEqual(rr.rdata.decode('ascii'), target)
+        self.assertEqual(rr.rdata.decode("ascii"), target)
         rr = msg.response.rrs[1]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "127.0.0.1")
+
 
 class TestProtobufIPCrypt2PFX(DNSDistProtobufTest):
-    _config_params = ['_testServerPort', '_protobufServerPort', '_protobufServerID', '_protobufServerID']
+    _config_params = ["_testServerPort", "_protobufServerPort", "_protobufServerID", "_protobufServerID"]
     _config_template = """
     newServer{address="127.0.0.1:%d", useClientSubnet=true}
     rl = newRemoteLogger('127.0.0.1:%d')
@@ -963,24 +984,16 @@ class TestProtobufIPCrypt2PFX(DNSDistProtobufTest):
         """
         Protobuf: Send data to a protobuf server, with pseudonymization
         """
-        name = 'query.protobuf-ipcipher.tests.powerdns.com.'
+        name = "query.protobuf-ipcipher.tests.powerdns.com."
 
-        target = 'target.protobuf-ipcipher.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        target = "target.protobuf-ipcipher.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    target)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.CNAME, target)
         response.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(target,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(target, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
@@ -998,19 +1011,21 @@ class TestProtobufIPCrypt2PFX(DNSDistProtobufTest):
         msg = self.getFirstProtobufMessage()
 
         # 108.41.239.98 is 127.0.0.1 pseudonymized with ipcrypt2-pfx and the current key
-        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '109.33.15.148')
+        self.checkProtobufQuery(
+            msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, "109.33.15.148"
+        )
 
         # check the protobuf message corresponding to the UDP response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response, '109.33.15.148')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response, "109.33.15.148")
 
         self.assertEqual(len(msg.response.rrs), 2)
         rr = msg.response.rrs[0]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 3600)
-        self.assertEqual(rr.rdata.decode('ascii'), target)
+        self.assertEqual(rr.rdata.decode("ascii"), target)
         rr = msg.response.rrs[1]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "127.0.0.1")
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
         self.assertTrue(receivedQuery)
@@ -1026,29 +1041,30 @@ class TestProtobufIPCrypt2PFX(DNSDistProtobufTest):
         # check the protobuf message corresponding to the TCP query
         msg = self.getFirstProtobufMessage()
         # 108.41.239.98 is 127.0.0.1 pseudonymized with ipcrypt2-pfx and the current key
-        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.TCP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '109.33.15.148')
+        self.checkProtobufQuery(
+            msg, dnsmessage_pb2.PBDNSMessage.TCP, query, dns.rdataclass.IN, dns.rdatatype.A, name, "109.33.15.148"
+        )
 
         # check the protobuf message corresponding to the TCP response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response, '109.33.15.148')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, response, "109.33.15.148")
         self.assertEqual(len(msg.response.rrs), 2)
         rr = msg.response.rrs[0]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 3600)
-        self.assertEqual(rr.rdata.decode('ascii'), target)
+        self.assertEqual(rr.rdata.decode("ascii"), target)
         rr = msg.response.rrs[1]
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "127.0.0.1")
 
 
 class TestProtobufQUIC(DNSDistProtobufTest):
-
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _doqServerPort = pickAvailablePort()
     _doh3ServerPort = pickAvailablePort()
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doh3ServerPort)
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     rl = newRemoteLogger('127.0.0.1:%d')
@@ -1058,20 +1074,25 @@ class TestProtobufQUIC(DNSDistProtobufTest):
 
     addAction(AllRule(), RemoteLogAction(rl, nil, {serverID='dnsdist-server-1'}))
     """
-    _config_params = ['_testServerPort', '_protobufServerPort', '_doqServerPort', '_serverCert', '_serverKey', '_doh3ServerPort', '_serverCert', '_serverKey']
+    _config_params = [
+        "_testServerPort",
+        "_protobufServerPort",
+        "_doqServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_doh3ServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
 
     def testProtobufMetaDoH(self):
         """
         Protobuf: Test logged protocol for QUIC and DOH3
         """
-        name = 'quic.protobuf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "quic.protobuf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendDOQQueryWrapper", "sendDOH3QueryWrapper"):
@@ -1099,6 +1120,7 @@ class TestProtobufQUIC(DNSDistProtobufTest):
 
             self.checkProtobufQuery(msg, pbMessageType, query, dns.rdataclass.IN, dns.rdatatype.A, name)
 
+
 class TestProtobufAXFR(DNSDistProtobufTest):
     # this test suite uses a different responder port
     # because, contrary to the other ones, its
@@ -1110,13 +1132,23 @@ class TestProtobufAXFR(DNSDistProtobufTest):
     def startResponders(cls):
         print("Launching responders..")
 
-        cls._UDPResponder = threading.Thread(name='UDP Protobuf AXFR Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Protobuf AXFR Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._TCPResponder = threading.Thread(name='TCP Protobuf AXFR Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, True, None, None, True])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Protobuf AXFR Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, True, None, None, True],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
-        cls._protobufListener = threading.Thread(name='Protobuf Listener', target=cls.ProtobufListener, args=[cls._protobufServerPort])
+        cls._protobufListener = threading.Thread(
+            name="Protobuf Listener", target=cls.ProtobufListener, args=[cls._protobufServerPort]
+        )
         cls._protobufListener.daemon = True
         cls._protobufListener.start()
 
@@ -1126,22 +1158,18 @@ class TestProtobufAXFR(DNSDistProtobufTest):
 
     addXFRResponseAction(AllRule(), RemoteLogResponseAction(rl, nil, false, {serverID='dnsdist-server-1'}))
     """
-    _config_params = ['_testServerPort', '_protobufServerPort']
+    _config_params = ["_testServerPort", "_protobufServerPort"]
 
     def testProtobufAXFR(self):
         """
         Protobuf: Check the logging of multiple messages for AXFR responses
         """
         # first query is NOT an AXFR, we should not log anything
-        name = 'axfr.protobuf.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "axfr.protobuf.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         ttl = 60
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1156,40 +1184,30 @@ class TestProtobufAXFR(DNSDistProtobufTest):
 
         self.assertTrue(self._protobufQueue.empty())
 
-        query = dns.message.make_query(name, 'AXFR', 'IN')
+        query = dns.message.make_query(name, "AXFR", "IN")
         responses = []
-        soa = dns.rrset.from_text(name,
-                                  ttl,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            ttl,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
         response = dns.message.make_response(query)
         response.answer.append(soa)
         responses.append(response)
 
         response = dns.message.make_response(query)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   ttl,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '192.0.2.1'))
+        response.answer.append(dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"))
         responses.append(response)
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:db8::1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::1")
         response.answer.append(rrset)
         responses.append(response)
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'dummy')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.TXT, "dummy")
         response.answer.append(rrset)
         responses.append(response)
 
@@ -1215,21 +1233,21 @@ class TestProtobufAXFR(DNSDistProtobufTest):
         while not self._protobufQueue.empty():
             msg = self.getFirstProtobufMessage()
             count = count + 1
-            self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, responses[count-1])
+            self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, responses[count - 1])
 
-            expected = responses[count-1].answer[0]
+            expected = responses[count - 1].answer[0]
             if expected.rdtype in [dns.rdatatype.A, dns.rdatatype.AAAA]:
                 rr = msg.response.rrs[0]
                 self.checkProtobufResponseRecord(rr, expected.rdclass, expected.rdtype, name, ttl)
                 if expected.rdtype == dns.rdatatype.A:
-                    self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.1')
+                    self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.1")
                 else:
-                    self.assertEqual(socket.inet_ntop(socket.AF_INET6, rr.rdata), '2001:db8::1')
+                    self.assertEqual(socket.inet_ntop(socket.AF_INET6, rr.rdata), "2001:db8::1")
 
         self.assertEqual(count, len(responses))
 
-class TestYamlProtobuf(DNSDistProtobufTest):
 
+class TestYamlProtobuf(DNSDistProtobufTest):
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -1261,22 +1279,18 @@ query_rules:
 """
     _dnsDistPort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort', '_protobufServerPort', '_protobufServerID']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort", "_protobufServerPort", "_protobufServerID"]
     _config_params = []
 
     def testProtobuf(self):
         """
         Yaml: Remote logging via protobuf
         """
-        name = 'remote-logging.protobuf.yaml.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "remote-logging.protobuf.yaml.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
@@ -1287,7 +1301,6 @@ query_rules:
             self.assertEqual(receivedQuery, query)
             self.assertEqual(receivedResponse, response)
 
-
         if self._protobufQueue.empty():
             # let the protobuf messages the time to get there
             time.sleep(1)
@@ -1336,22 +1349,18 @@ response_rules:
 """
     _dnsDistPort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort', '_protobufServerPort', '_protobufServerID']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort", "_protobufServerPort", "_protobufServerID"]
     _config_params = []
 
     def testProtobuf(self):
         """
         Yaml: Remote logging via protobuf
         """
-        name = 'remote-logging.protobuf.yaml.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "remote-logging.protobuf.yaml.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
@@ -1380,7 +1389,6 @@ response_rules:
 
 
 class TestTimeoutResponseRuleProtobuf(DNSDistProtobufTest):
-
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -1410,22 +1418,18 @@ timeout_response_rules:
     _dnsDistPort = pickAvailablePort()
     _testServerPortNotListening = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_dnsDistPort', '_testServerPortNotListening', '_protobufServerPort', '_protobufServerID']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPortNotListening", "_protobufServerPort", "_protobufServerID"]
     _config_params = []
 
     def testProtobuf(self):
         """
         Yaml: Remote logging via protobuf of timeouts
         """
-        name = 'remote-logging-timeout.protobuf.yaml.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "remote-logging-timeout.protobuf.yaml.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
@@ -1435,7 +1439,6 @@ timeout_response_rules:
             self.assertEqual(receivedQuery, None)
             self.assertEqual(receivedResponse, None)
 
-
         # the UDP timeout usually takes longer to be detected
         # than the TCP one
         gotUDP = False
@@ -1459,18 +1462,19 @@ timeout_response_rules:
                 protocol = dnsmessage_pb2.PBDNSMessage.TCP
 
             self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSResponseType)
-            self.checkProtobufBase(msg, protocol, response, '127.0.0.1', normalQueryResponse=False, v6=False)
-            self.assertTrue(msg.HasField('response'))
-            self.assertTrue(msg.response.HasField('queryTimeSec'))
-            self.assertTrue(msg.HasField('question'))
-            self.assertTrue(msg.question.HasField('qClass'))
-            self.assertTrue(msg.question.HasField('qType'))
-            self.assertTrue(msg.question.HasField('qName'))
+            self.checkProtobufBase(msg, protocol, response, "127.0.0.1", normalQueryResponse=False, v6=False)
+            self.assertTrue(msg.HasField("response"))
+            self.assertTrue(msg.response.HasField("queryTimeSec"))
+            self.assertTrue(msg.HasField("question"))
+            self.assertTrue(msg.question.HasField("qClass"))
+            self.assertTrue(msg.question.HasField("qType"))
+            self.assertTrue(msg.question.HasField("qName"))
             self.assertEqual(msg.question.qName, name)
 
         self.assertTrue(gotUDP)
         self.assertTrue(gotTCP)
 
+
 class TestProtobufGlobalServerIDYaml(TestYamlProtobuf):
     _yaml_config_template = """---
 binds:
@@ -1505,8 +1509,9 @@ query_rules:
         - "tag-2"
 """
 
+
 class TestProtobufGlobalServerIDLua(DNSDistProtobufTest):
-    _config_params = ['_protobufServerID', '_testServerPort', '_protobufServerPort']
+    _config_params = ["_protobufServerID", "_testServerPort", "_protobufServerPort"]
     _config_template = """
     setServerID("%s")
     luasmn = newSuffixMatchNode()
index 9f6a4327580d1165ee8335e49f14e8ca77bdf246..df844facec531280242afd5bd5dca5e27fa45003 100644 (file)
@@ -14,28 +14,36 @@ import requests
 from dnsdistdohtests import DNSDistDOHTest
 from dnsdisttests import DNSDistTest, pickAvailablePort
 from proxyprotocol import ProxyProtocol
-from proxyprotocolutils import (ProxyProtocolTCPResponder,
-                                ProxyProtocolUDPResponder)
+from proxyprotocolutils import ProxyProtocolTCPResponder, ProxyProtocolUDPResponder
 
 # Python2/3 compatibility hacks
 try:
-  from queue import Queue
+    from queue import Queue
 except ImportError:
-  from Queue import Queue
+    from Queue import Queue
 
 toProxyQueue = Queue()
 fromProxyQueue = Queue()
 proxyResponderPort = pickAvailablePort()
 
-udpResponder = threading.Thread(name='UDP Proxy Protocol Responder', target=ProxyProtocolUDPResponder, args=[proxyResponderPort, toProxyQueue, fromProxyQueue])
+udpResponder = threading.Thread(
+    name="UDP Proxy Protocol Responder",
+    target=ProxyProtocolUDPResponder,
+    args=[proxyResponderPort, toProxyQueue, fromProxyQueue],
+)
 udpResponder.daemon = True
 udpResponder.start()
-tcpResponder = threading.Thread(name='TCP Proxy Protocol Responder', target=ProxyProtocolTCPResponder, args=[proxyResponderPort, toProxyQueue, fromProxyQueue])
+tcpResponder = threading.Thread(
+    name="TCP Proxy Protocol Responder",
+    target=ProxyProtocolTCPResponder,
+    args=[proxyResponderPort, toProxyQueue, fromProxyQueue],
+)
 tcpResponder.daemon = True
 tcpResponder.start()
 
 backgroundThreads = {}
 
+
 def MockTCPReverseProxyAddingProxyProtocol(listeningPort, forwardingPort, serverCtx=None, ca=None, sni=None):
     # this responder accepts TCP connections on the listening port,
     # and relay the raw content to a second TCP connection to the
@@ -67,39 +75,49 @@ def MockTCPReverseProxyAddingProxyProtocol(listeningPort, forwardingPort, server
                 del backgroundThreads[threading.get_native_id()]
                 break
             else:
-              continue
+                continue
 
         incoming.settimeout(5.0)
-        payload = ProxyProtocol.getPayload(False, True, False, '127.0.0.1', '127.0.0.1', incoming.getpeername()[1], listeningPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
+        payload = ProxyProtocol.getPayload(
+            False,
+            True,
+            False,
+            "127.0.0.1",
+            "127.0.0.1",
+            incoming.getpeername()[1],
+            listeningPort,
+            [[2, b"foo"], [3, b"proxy"]],
+        )
 
         outgoing = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         outgoing.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
         outgoing.settimeout(2.0)
         if sni:
-            if hasattr(ssl, 'create_default_context'):
+            if hasattr(ssl, "create_default_context"):
                 sslctx = ssl.create_default_context(cafile=ca)
-                if hasattr(sslctx, 'set_alpn_protocols'):
-                    sslctx.set_alpn_protocols(['h2'])
+                if hasattr(sslctx, "set_alpn_protocols"):
+                    sslctx.set_alpn_protocols(["h2"])
                 outgoing = sslctx.wrap_socket(outgoing, server_hostname=sni)
             else:
                 outgoing = ssl.wrap_socket(outgoing, ca_certs=ca, cert_reqs=ssl.CERT_REQUIRED)
 
-        outgoing.connect(('127.0.0.1', forwardingPort))
+        outgoing.connect(("127.0.0.1", forwardingPort))
 
         outgoing.send(payload)
 
         sel = selectors.DefaultSelector()
+
         def readFromClient(conn):
             data = conn.recv(512)
             if not data or len(data) == 0:
-              return False
+                return False
             outgoing.send(data)
             return True
 
         def readFromBackend(conn):
             data = conn.recv(512)
             if not data or len(data) == 0:
-              return False
+                return False
             incoming.send(data)
             return True
 
@@ -107,25 +125,27 @@ def MockTCPReverseProxyAddingProxyProtocol(listeningPort, forwardingPort, server
         sel.register(outgoing, selectors.EVENT_READ, readFromBackend)
         done = False
         while not done:
-          try:
-            events = sel.select()
-            for key, mask in events:
-              if not (key.data)(key.fileobj):
-                done = True
+            try:
+                events = sel.select()
+                for key, mask in events:
+                    if not (key.data)(key.fileobj):
+                        done = True
+                        break
+            except socket.timeout:
+                break
+            except Exception:
                 break
-          except socket.timeout:
-            break
-          except Exception:
-            break
 
         incoming.close()
         outgoing.close()
 
     sock.close()
 
+
 class ProxyProtocolTest(DNSDistTest):
     _proxyResponderPort = proxyResponderPort
-    _config_params = ['_proxyResponderPort']
+    _config_params = ["_proxyResponderPort"]
+
 
 class TestProxyProtocol(ProxyProtocolTest):
     """
@@ -156,28 +176,37 @@ class TestProxyProtocol(ProxyProtocolTest):
     addAction("random-values.proxy.tests.powerdns.com.", LuaAction(addRandomValue))
     """
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
-    _config_params = ['_proxyResponderPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _webServerBasicAuthPassword = "secret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
+    _config_params = [
+        "_proxyResponderPort",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
 
     def getServerStats(self):
-      headers = {'x-api-key': self._webServerAPIKey}
-      url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost'
-      r = requests.get(url, headers=headers, timeout=1)
-      self.assertTrue(r)
-      self.assertEqual(r.status_code, 200)
-      self.assertTrue(r.json())
-      content = r.json()
-      return content['servers']
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
+        r = requests.get(url, headers=headers, timeout=1)
+        self.assertTrue(r)
+        self.assertEqual(r.status_code, 200)
+        self.assertTrue(r.json())
+        content = r.json()
+        return content["servers"]
 
     def testProxyUDP(self):
         """
         Proxy Protocol: no value (UDP)
         """
-        name = 'simple-udp.proxy.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "simple-udp.proxy.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         toProxyQueue.put(response, True, 2.0)
@@ -189,7 +218,7 @@ class TestProxyProtocol(ProxyProtocolTest):
             self._sock.settimeout(2.0)
             data = self._sock.recv(4096)
         except socket.timeout:
-            print('timeout')
+            print("timeout")
             data = None
         if data:
             receivedResponse = dns.message.from_wire(data)
@@ -204,45 +233,45 @@ class TestProxyProtocol(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', False)
+        self.checkMessageProxyProtocol(receivedProxyPayload, "127.0.0.1", "127.0.0.1", False)
 
     def testProxyTCP(self):
-      """
+        """
         Proxy Protocol: no value (TCP)
-      """
-      name = 'simple-tcp.proxy.tests.powerdns.com.'
-      query = dns.message.make_query(name, 'A', 'IN')
-      response = dns.message.make_response(query)
-
-      toProxyQueue.put(response, True, 2.0)
-
-      conn = self.openTCPConnection(2.0)
-      data = query.to_wire()
-      self.sendTCPQueryOverConnection(conn, data, rawQuery=True)
-      receivedResponse = None
-      try:
-        receivedResponse = self.recvTCPResponseOverConnection(conn)
-      except socket.timeout:
-            print('timeout')
+        """
+        name = "simple-tcp.proxy.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        response = dns.message.make_response(query)
 
-      (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
-      self.assertTrue(receivedProxyPayload)
-      self.assertTrue(receivedDNSData)
-      self.assertTrue(receivedResponse)
+        toProxyQueue.put(response, True, 2.0)
 
-      receivedQuery = dns.message.from_wire(receivedDNSData)
-      receivedQuery.id = query.id
-      receivedResponse.id = response.id
-      self.assertEqual(receivedQuery, query)
-      self.assertEqual(receivedResponse, response)
-      self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True)
+        conn = self.openTCPConnection(2.0)
+        data = query.to_wire()
+        self.sendTCPQueryOverConnection(conn, data, rawQuery=True)
+        receivedResponse = None
+        try:
+            receivedResponse = self.recvTCPResponseOverConnection(conn)
+        except socket.timeout:
+            print("timeout")
+
+        (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+        self.assertTrue(receivedProxyPayload)
+        self.assertTrue(receivedDNSData)
+        self.assertTrue(receivedResponse)
+
+        receivedQuery = dns.message.from_wire(receivedDNSData)
+        receivedQuery.id = query.id
+        receivedResponse.id = response.id
+        self.assertEqual(receivedQuery, query)
+        self.assertEqual(receivedResponse, response)
+        self.checkMessageProxyProtocol(receivedProxyPayload, "127.0.0.1", "127.0.0.1", True)
 
     def testProxyUDPWithValuesFromLua(self):
         """
         Proxy Protocol: values from Lua (UDP)
         """
-        name = 'values-lua.proxy.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "values-lua.proxy.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         toProxyQueue.put(response, True, 2.0)
@@ -254,7 +283,7 @@ class TestProxyProtocol(ProxyProtocolTest):
             self._sock.settimeout(2.0)
             data = self._sock.recv(4096)
         except socket.timeout:
-            print('timeout')
+            print("timeout")
             data = None
         if data:
             receivedResponse = dns.message.from_wire(data)
@@ -269,45 +298,49 @@ class TestProxyProtocol(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', False, [ [0, b'foo'] , [ 42, b'bar'] ])
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload, "127.0.0.1", "127.0.0.1", False, [[0, b"foo"], [42, b"bar"]]
+        )
 
     def testProxyTCPWithValuesFromLua(self):
-      """
+        """
         Proxy Protocol: values from Lua (TCP)
-      """
-      name = 'values-lua.proxy.tests.powerdns.com.'
-      query = dns.message.make_query(name, 'A', 'IN')
-      response = dns.message.make_response(query)
-
-      toProxyQueue.put(response, True, 2.0)
-
-      conn = self.openTCPConnection(2.0)
-      data = query.to_wire()
-      self.sendTCPQueryOverConnection(conn, data, rawQuery=True)
-      receivedResponse = None
-      try:
-        receivedResponse = self.recvTCPResponseOverConnection(conn)
-      except socket.timeout:
-            print('timeout')
+        """
+        name = "values-lua.proxy.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        response = dns.message.make_response(query)
+
+        toProxyQueue.put(response, True, 2.0)
+
+        conn = self.openTCPConnection(2.0)
+        data = query.to_wire()
+        self.sendTCPQueryOverConnection(conn, data, rawQuery=True)
+        receivedResponse = None
+        try:
+            receivedResponse = self.recvTCPResponseOverConnection(conn)
+        except socket.timeout:
+            print("timeout")
 
-      (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
-      self.assertTrue(receivedProxyPayload)
-      self.assertTrue(receivedDNSData)
-      self.assertTrue(receivedResponse)
+        (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+        self.assertTrue(receivedProxyPayload)
+        self.assertTrue(receivedDNSData)
+        self.assertTrue(receivedResponse)
 
-      receivedQuery = dns.message.from_wire(receivedDNSData)
-      receivedQuery.id = query.id
-      receivedResponse.id = response.id
-      self.assertEqual(receivedQuery, query)
-      self.assertEqual(receivedResponse, response)
-      self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'] , [ 42, b'bar'] ])
+        receivedQuery = dns.message.from_wire(receivedDNSData)
+        receivedQuery.id = query.id
+        receivedResponse.id = response.id
+        self.assertEqual(receivedQuery, query)
+        self.assertEqual(receivedResponse, response)
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload, "127.0.0.1", "127.0.0.1", True, [[0, b"foo"], [42, b"bar"]]
+        )
 
     def testProxyUDPWithValuesFromAction(self):
         """
         Proxy Protocol: values from Action (UDP)
         """
-        name = 'values-action.proxy.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "values-action.proxy.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         toProxyQueue.put(response, True, 2.0)
@@ -319,7 +352,7 @@ class TestProxyProtocol(ProxyProtocolTest):
             self._sock.settimeout(2.0)
             data = self._sock.recv(4096)
         except socket.timeout:
-            print('timeout')
+            print("timeout")
             data = None
         if data:
             receivedResponse = dns.message.from_wire(data)
@@ -334,62 +367,28 @@ class TestProxyProtocol(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', False, [ [1, b'dnsdist'] , [ 255, b'proxy-protocol'] ])
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload, "127.0.0.1", "127.0.0.1", False, [[1, b"dnsdist"], [255, b"proxy-protocol"]]
+        )
 
     def testProxyTCPWithValuesFromAction(self):
-      """
+        """
         Proxy Protocol: values from Action (TCP)
-      """
-      name = 'values-action.proxy.tests.powerdns.com.'
-      query = dns.message.make_query(name, 'A', 'IN')
-      response = dns.message.make_response(query)
-
-      toProxyQueue.put(response, True, 2.0)
-
-      conn = self.openTCPConnection(2.0)
-      data = query.to_wire()
-      self.sendTCPQueryOverConnection(conn, data, rawQuery=True)
-      receivedResponse = None
-      try:
-        receivedResponse = self.recvTCPResponseOverConnection(conn)
-      except socket.timeout:
-            print('timeout')
-
-      (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
-      self.assertTrue(receivedProxyPayload)
-      self.assertTrue(receivedDNSData)
-      self.assertTrue(receivedResponse)
-
-      receivedQuery = dns.message.from_wire(receivedDNSData)
-      receivedQuery.id = query.id
-      receivedResponse.id = response.id
-      self.assertEqual(receivedQuery, query)
-      self.assertEqual(receivedResponse, response)
-      self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [1, b'dnsdist'] , [ 255, b'proxy-protocol'] ])
-
-    def testProxyTCPSeveralQueriesOnSameConnection(self):
-      """
-        Proxy Protocol: Several queries on the same TCP connection
-      """
-      name = 'several-queries-same-conn.proxy.tests.powerdns.com.'
-      query = dns.message.make_query(name, 'A', 'IN')
-      response = dns.message.make_response(query)
-
-      new_conn_before = self.getServerStats()[0]['tcpNewConnections']
-      reused_conn_before = self.getServerStats()[0]['tcpReusedConnections']
-      max_conn_before = self.getServerStats()[0]['tcpMaxConcurrentConnections']
-
-      conn = self.openTCPConnection(2.0)
-      data = query.to_wire()
+        """
+        name = "values-action.proxy.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        response = dns.message.make_response(query)
 
-      for idx in range(10):
         toProxyQueue.put(response, True, 2.0)
+
+        conn = self.openTCPConnection(2.0)
+        data = query.to_wire()
         self.sendTCPQueryOverConnection(conn, data, rawQuery=True)
         receivedResponse = None
         try:
-          receivedResponse = self.recvTCPResponseOverConnection(conn)
+            receivedResponse = self.recvTCPResponseOverConnection(conn)
         except socket.timeout:
-          print('timeout')
+            print("timeout")
 
         (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
         self.assertTrue(receivedProxyPayload)
@@ -401,76 +400,117 @@ class TestProxyProtocol(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [])
-
-      # check:
-      # - only one concurrent connection to the backend
-      # - no more than 1 new connection to the backend was opened
-      server = self.getServerStats()[0]
-      self.assertEqual(server['tcpNewConnections'], new_conn_before + 1)
-      self.assertEqual(server['tcpReusedConnections'], reused_conn_before + 9)
-      # we can only check that we did not open more than one new connection
-      # compared to the connections that existed before, because connections
-      # triggered by a different test can still be around
-      self.assertLessEqual(server['tcpMaxConcurrentConnections'], max_conn_before + 1)
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload, "127.0.0.1", "127.0.0.1", True, [[1, b"dnsdist"], [255, b"proxy-protocol"]]
+        )
+
+    def testProxyTCPSeveralQueriesOnSameConnection(self):
+        """
+        Proxy Protocol: Several queries on the same TCP connection
+        """
+        name = "several-queries-same-conn.proxy.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        response = dns.message.make_response(query)
+
+        new_conn_before = self.getServerStats()[0]["tcpNewConnections"]
+        reused_conn_before = self.getServerStats()[0]["tcpReusedConnections"]
+        max_conn_before = self.getServerStats()[0]["tcpMaxConcurrentConnections"]
+
+        conn = self.openTCPConnection(2.0)
+        data = query.to_wire()
+
+        for idx in range(10):
+            toProxyQueue.put(response, True, 2.0)
+            self.sendTCPQueryOverConnection(conn, data, rawQuery=True)
+            receivedResponse = None
+            try:
+                receivedResponse = self.recvTCPResponseOverConnection(conn)
+            except socket.timeout:
+                print("timeout")
+
+            (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+            self.assertTrue(receivedProxyPayload)
+            self.assertTrue(receivedDNSData)
+            self.assertTrue(receivedResponse)
+
+            receivedQuery = dns.message.from_wire(receivedDNSData)
+            receivedQuery.id = query.id
+            receivedResponse.id = response.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)
+            self.checkMessageProxyProtocol(receivedProxyPayload, "127.0.0.1", "127.0.0.1", True, [])
+
+        # check:
+        # - only one concurrent connection to the backend
+        # - no more than 1 new connection to the backend was opened
+        server = self.getServerStats()[0]
+        self.assertEqual(server["tcpNewConnections"], new_conn_before + 1)
+        self.assertEqual(server["tcpReusedConnections"], reused_conn_before + 9)
+        # we can only check that we did not open more than one new connection
+        # compared to the connections that existed before, because connections
+        # triggered by a different test can still be around
+        self.assertLessEqual(server["tcpMaxConcurrentConnections"], max_conn_before + 1)
 
     def testProxyTCPSeveralQueriesWithRandomTLVOnSameConnection(self):
-      """
+        """
         Proxy Protocol: Several queries with random TLV on the same TCP connection
-      """
-      name = 'random-values.proxy.tests.powerdns.com.'
-      query = dns.message.make_query(name, 'A', 'IN')
-      response = dns.message.make_response(query)
-
-      stats = self.getServerStats()[0]
-      max_conns_before = stats['tcpMaxConcurrentConnections']
-      current_conns_before = stats['tcpCurrentConnections']
-      new_conn_before = stats['tcpNewConnections']
-      reused_conn_before = stats['tcpReusedConnections']
-
-      conn = self.openTCPConnection(2.0)
-      data = query.to_wire()
-
-      number_of_queries = 10
-      for idx in range(number_of_queries):
-        toProxyQueue.put(response, True, 2.0)
-        self.sendTCPQueryOverConnection(conn, data, rawQuery=True)
-        receivedResponse = None
-        try:
-          receivedResponse = self.recvTCPResponseOverConnection(conn)
-        except socket.timeout:
-          print('timeout')
+        """
+        name = "random-values.proxy.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        response = dns.message.make_response(query)
 
-        (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
-        self.assertTrue(receivedProxyPayload)
-        self.assertTrue(receivedDNSData)
-        self.assertTrue(receivedResponse)
+        stats = self.getServerStats()[0]
+        max_conns_before = stats["tcpMaxConcurrentConnections"]
+        current_conns_before = stats["tcpCurrentConnections"]
+        new_conn_before = stats["tcpNewConnections"]
+        reused_conn_before = stats["tcpReusedConnections"]
+
+        conn = self.openTCPConnection(2.0)
+        data = query.to_wire()
+
+        number_of_queries = 10
+        for idx in range(number_of_queries):
+            toProxyQueue.put(response, True, 2.0)
+            self.sendTCPQueryOverConnection(conn, data, rawQuery=True)
+            receivedResponse = None
+            try:
+                receivedResponse = self.recvTCPResponseOverConnection(conn)
+            except socket.timeout:
+                print("timeout")
+
+            (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+            self.assertTrue(receivedProxyPayload)
+            self.assertTrue(receivedDNSData)
+            self.assertTrue(receivedResponse)
+
+            receivedQuery = dns.message.from_wire(receivedDNSData)
+            receivedQuery.id = query.id
+            receivedResponse.id = response.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)
+            self.checkMessageProxyProtocol(
+                receivedProxyPayload, "127.0.0.1", "127.0.0.1", True, [[238, str(idx + 1).encode("UTF-8")]]
+            )
+
+        # check:
+        # - only one concurrent connection to the backend
+        # - no more than number_of_queries connections to the backend were opened
+        server = self.getServerStats()[0]
+        self.assertEqual(server["tcpNewConnections"], new_conn_before + number_of_queries)
+        self.assertEqual(server["tcpReusedConnections"], reused_conn_before)
+        # in some cases existing (established before this test) connections to the backend might still
+        # exist, so we cannot enforce a strict "only 1 connection" check
+        self.assertLessEqual(server["tcpMaxConcurrentConnections"], max_conns_before + 1)
+        # but if we managed to add more than two connections to the existing ones, something is
+        # wrong!
+        # why two and not one? when a query arrives we retrieve the "owned" outgoing connection to the backend,
+        # and we notice that the TLVs are different than the previous ones, so we discard the outgoing connection
+        # and create a new one. This should lead to only one concurrent connection, except that if we read the
+        # new query while being called from the function handling the response from the backend, we might still
+        # hold a shared reference to the previous connection. It will be released when we come back to the calling
+        # function, but for a short time we will have two concurrent connections.
+        self.assertLessEqual(server["tcpMaxConcurrentConnections"], current_conns_before + 2)
 
-        receivedQuery = dns.message.from_wire(receivedDNSData)
-        receivedQuery.id = query.id
-        receivedResponse.id = response.id
-        self.assertEqual(receivedQuery, query)
-        self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [[238, str(idx + 1).encode('UTF-8')]])
-
-      # check:
-      # - only one concurrent connection to the backend
-      # - no more than number_of_queries connections to the backend were opened
-      server = self.getServerStats()[0]
-      self.assertEqual(server['tcpNewConnections'], new_conn_before + number_of_queries)
-      self.assertEqual(server['tcpReusedConnections'], reused_conn_before)
-      # in some cases existing (established before this test) connections to the backend might still
-      # exist, so we cannot enforce a strict "only 1 connection" check
-      self.assertLessEqual(server['tcpMaxConcurrentConnections'], max_conns_before + 1)
-      # but if we managed to add more than two connections to the existing ones, something is
-      # wrong!
-      # why two and not one? when a query arrives we retrieve the "owned" outgoing connection to the backend,
-      # and we notice that the TLVs are different than the previous ones, so we discard the outgoing connection
-      # and create a new one. This should lead to only one concurrent connection, except that if we read the
-      # new query while being called from the function handling the response from the backend, we might still
-      # hold a shared reference to the previous connection. It will be released when we come back to the calling
-      # function, but for a short time we will have two concurrent connections.
-      self.assertLessEqual(server['tcpMaxConcurrentConnections'], current_conns_before + 2)
 
 class TestProxyProtocolTraceParent(TestProxyProtocol):
     # dnsdist adds a TRACEPARENT EDNS option.
@@ -501,6 +541,7 @@ class TestProxyProtocolTraceParent(TestProxyProtocol):
     addAction("random-values.proxy.tests.powerdns.com.", LuaAction(addRandomValue))
     """
 
+
 class TestProxyProtocolIncoming(ProxyProtocolTest):
     """
     dnsdist is configured to prepend a Proxy Protocol header to the query and expect one on incoming queries
@@ -547,38 +588,52 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
     -- override all existing values
     addAction("override.proxy-protocol-incoming.tests.powerdns.com.", SetProxyProtocolValuesAction({["50"]="overridden"}))
     """
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohServerPPOutsidePort = pickAvailablePort()
     _dohServerPPInsidePort = pickAvailablePort()
     _dotServerPPOutsidePort = pickAvailablePort()
     _dotServerPPInsidePort = pickAvailablePort()
-    _config_params = ['_dohServerPPOutsidePort', '_serverCert', '_serverKey', '_dohServerPPInsidePort', '_serverCert', '_serverKey', '_dotServerPPOutsidePort', '_serverCert', '_serverKey', '_dotServerPPInsidePort', '_serverCert', '_serverKey', '_proxyResponderPort']
+    _config_params = [
+        "_dohServerPPOutsidePort",
+        "_serverCert",
+        "_serverKey",
+        "_dohServerPPInsidePort",
+        "_serverCert",
+        "_serverKey",
+        "_dotServerPPOutsidePort",
+        "_serverCert",
+        "_serverKey",
+        "_dotServerPPInsidePort",
+        "_serverCert",
+        "_serverKey",
+        "_proxyResponderPort",
+    ]
 
     def testNoHeader(self):
         """
         Incoming Proxy Protocol: no header
         """
         # no proxy protocol header while one is expected, should be dropped
-        name = 'no-header.incoming-proxy-protocol.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "no-header.incoming-proxy-protocol.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery", "sendDOHQueryWrapper"):
-          sender = getattr(self, method)
-          try:
-            (_, receivedResponse) = sender(query, response=None)
-          except Exception:
-            receivedResponse = None
-          self.assertEqual(receivedResponse, None)
+            sender = getattr(self, method)
+            try:
+                (_, receivedResponse) = sender(query, response=None)
+            except Exception:
+                receivedResponse = None
+            self.assertEqual(receivedResponse, None)
 
     def testIncomingProxyDest(self):
         """
         Incoming Proxy Protocol: get forwarded destination
         """
-        name = 'get-forwarded-dest.proxy-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "get-forwarded-dest.proxy-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
@@ -587,37 +642,45 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         srcAddr = "2001:db8::8"
         srcPort = 8888
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    "address-was-{}-port-was-{}.proxy-protocol-incoming.tests.powerdns.com.".format(destAddr, destPort))
+        rrset = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.CNAME,
+            "address-was-{}-port-was-{}.proxy-protocol-incoming.tests.powerdns.com.".format(destAddr, destPort),
+        )
         response.answer.append(rrset)
 
-        udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
-        (_, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True)
+        udpPayload = ProxyProtocol.getPayload(
+            False, False, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [3, b"proxy"]]
+        )
+        (_, receivedResponse) = self.sendUDPQuery(
+            udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True
+        )
         self.assertEqual(receivedResponse, response)
 
-        tcpPayload = ProxyProtocol.getPayload(False, True, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
+        tcpPayload = ProxyProtocol.getPayload(
+            False, True, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [3, b"proxy"]]
+        )
         wire = query.to_wire()
 
         receivedResponse = None
         try:
-          conn = self.openTCPConnection(2.0)
-          conn.send(tcpPayload)
-          conn.send(struct.pack("!H", len(wire)))
-          conn.send(wire)
-          receivedResponse = self.recvTCPResponseOverConnection(conn)
+            conn = self.openTCPConnection(2.0)
+            conn.send(tcpPayload)
+            conn.send(struct.pack("!H", len(wire)))
+            conn.send(wire)
+            receivedResponse = self.recvTCPResponseOverConnection(conn)
         except socket.timeout:
-          print('timeout')
+            print("timeout")
         self.assertEqual(receivedResponse, response)
 
     def testProxyUDPWithValuesFromLua(self):
         """
         Incoming Proxy Protocol: values from Lua (UDP)
         """
-        name = 'values-lua.proxy-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "values-lua.proxy-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         destAddr = "2001:db8::9"
@@ -625,9 +688,13 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         srcAddr = "2001:db8::8"
         srcPort = 8888
 
-        udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
+        udpPayload = ProxyProtocol.getPayload(
+            False, False, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [3, b"proxy"]]
+        )
         toProxyQueue.put(response, True, 2.0)
-        (_, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True)
+        (_, receivedResponse) = self.sendUDPQuery(
+            udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True
+        )
 
         (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
         self.assertTrue(receivedProxyPayload)
@@ -639,14 +706,23 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, srcAddr, destAddr, False, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [ 42, b'bar'], [255, b'proxy-protocol'] ], True, srcPort, destPort)
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload,
+            srcAddr,
+            destAddr,
+            False,
+            [[0, b"foo"], [1, b"dnsdist"], [2, b"foo"], [3, b"proxy"], [42, b"bar"], [255, b"proxy-protocol"]],
+            True,
+            srcPort,
+            destPort,
+        )
 
     def testProxyTCPWithValuesFromLua(self):
         """
         Incoming Proxy Protocol: values from Lua (TCP)
         """
-        name = 'values-lua.proxy-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "values-lua.proxy-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         destAddr = "2001:db8::9"
@@ -654,7 +730,9 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         srcAddr = "2001:db8::8"
         srcPort = 8888
 
-        tcpPayload = ProxyProtocol.getPayload(False, True, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
+        tcpPayload = ProxyProtocol.getPayload(
+            False, True, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [3, b"proxy"]]
+        )
 
         toProxyQueue.put(response, True, 2.0)
 
@@ -662,13 +740,13 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
 
         receivedResponse = None
         try:
-          conn = self.openTCPConnection(2.0)
-          conn.send(tcpPayload)
-          conn.send(struct.pack("!H", len(wire)))
-          conn.send(wire)
-          receivedResponse = self.recvTCPResponseOverConnection(conn)
+            conn = self.openTCPConnection(2.0)
+            conn.send(tcpPayload)
+            conn.send(struct.pack("!H", len(wire)))
+            conn.send(wire)
+            receivedResponse = self.recvTCPResponseOverConnection(conn)
         except socket.timeout:
-          print('timeout')
+            print("timeout")
         self.assertEqual(receivedResponse, response)
 
         (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
@@ -680,14 +758,23 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         receivedQuery.id = query.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, srcAddr, destAddr, True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [ 42, b'bar'], [255, b'proxy-protocol'] ], True, srcPort, destPort)
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload,
+            srcAddr,
+            destAddr,
+            True,
+            [[0, b"foo"], [1, b"dnsdist"], [2, b"foo"], [3, b"proxy"], [42, b"bar"], [255, b"proxy-protocol"]],
+            True,
+            srcPort,
+            destPort,
+        )
 
     def testProxyUDPWithValueOverride(self):
         """
         Incoming Proxy Protocol: override existing value (UDP)
         """
-        name = 'override.proxy-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "override.proxy-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         destAddr = "2001:db8::9"
@@ -695,9 +782,20 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         srcAddr = "2001:db8::8"
         srcPort = 8888
 
-        udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [ [2, b'foo'], [3, b'proxy'], [ 50, b'initial-value']])
+        udpPayload = ProxyProtocol.getPayload(
+            False,
+            False,
+            True,
+            srcAddr,
+            destAddr,
+            srcPort,
+            destPort,
+            [[2, b"foo"], [3, b"proxy"], [50, b"initial-value"]],
+        )
         toProxyQueue.put(response, True, 2.0)
-        (_, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True)
+        (_, receivedResponse) = self.sendUDPQuery(
+            udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True
+        )
 
         (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
         self.assertTrue(receivedProxyPayload)
@@ -709,14 +807,16 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, srcAddr, destAddr, False, [ [50, b'overridden'] ], True, srcPort, destPort)
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload, srcAddr, destAddr, False, [[50, b"overridden"]], True, srcPort, destPort
+        )
 
     def testProxyTCPSeveralQueriesOverConnection(self):
         """
         Incoming Proxy Protocol: Several queries over the same connection (TCP)
         """
-        name = 'several-queries.proxy-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "several-queries.proxy-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         destAddr = "2001:db8::9"
@@ -724,7 +824,9 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         srcAddr = "2001:db8::8"
         srcPort = 8888
 
-        tcpPayload = ProxyProtocol.getPayload(False, True, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
+        tcpPayload = ProxyProtocol.getPayload(
+            False, True, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [3, b"proxy"]]
+        )
 
         toProxyQueue.put(response, True, 2.0)
 
@@ -733,12 +835,12 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         receivedResponse = None
         conn = self.openTCPConnection(2.0)
         try:
-          conn.send(tcpPayload)
-          conn.send(struct.pack("!H", len(wire)))
-          conn.send(wire)
-          receivedResponse = self.recvTCPResponseOverConnection(conn)
+            conn.send(tcpPayload)
+            conn.send(struct.pack("!H", len(wire)))
+            conn.send(wire)
+            receivedResponse = self.recvTCPResponseOverConnection(conn)
         except socket.timeout:
-          print('timeout')
+            print("timeout")
         self.assertEqual(receivedResponse, response)
 
         (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
@@ -751,51 +853,81 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, srcAddr, destAddr, True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [ 42, b'bar'], [255, b'proxy-protocol'] ], True, srcPort, destPort)
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload,
+            srcAddr,
+            destAddr,
+            True,
+            [[0, b"foo"], [1, b"dnsdist"], [2, b"foo"], [3, b"proxy"], [42, b"bar"], [255, b"proxy-protocol"]],
+            True,
+            srcPort,
+            destPort,
+        )
 
         for idx in range(5):
-          receivedResponse = None
-          toProxyQueue.put(response, True, 2.0)
-          try:
-            conn.send(struct.pack("!H", len(wire)))
-            conn.send(wire)
-            receivedResponse = self.recvTCPResponseOverConnection(conn)
-          except socket.timeout:
-            print('timeout')
-
-          self.assertEqual(receivedResponse, response)
-
-          (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
-          self.assertTrue(receivedProxyPayload)
-          self.assertTrue(receivedDNSData)
-          self.assertTrue(receivedResponse)
-
-          receivedQuery = dns.message.from_wire(receivedDNSData)
-          receivedQuery.id = query.id
-          self.assertEqual(receivedQuery, query)
-          self.assertEqual(receivedResponse, response)
-          self.checkMessageProxyProtocol(receivedProxyPayload, srcAddr, destAddr, True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [ 42, b'bar'], [255, b'proxy-protocol'] ], True, srcPort, destPort)
+            receivedResponse = None
+            toProxyQueue.put(response, True, 2.0)
+            try:
+                conn.send(struct.pack("!H", len(wire)))
+                conn.send(wire)
+                receivedResponse = self.recvTCPResponseOverConnection(conn)
+            except socket.timeout:
+                print("timeout")
+
+            self.assertEqual(receivedResponse, response)
+
+            (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+            self.assertTrue(receivedProxyPayload)
+            self.assertTrue(receivedDNSData)
+            self.assertTrue(receivedResponse)
+
+            receivedQuery = dns.message.from_wire(receivedDNSData)
+            receivedQuery.id = query.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)
+            self.checkMessageProxyProtocol(
+                receivedProxyPayload,
+                srcAddr,
+                destAddr,
+                True,
+                [[0, b"foo"], [1, b"dnsdist"], [2, b"foo"], [3, b"proxy"], [42, b"bar"], [255, b"proxy-protocol"]],
+                True,
+                srcPort,
+                destPort,
+            )
 
     def testProxyDoHSeveralQueriesOverConnectionPPOutside(self):
         """
         Incoming Proxy Protocol: Several queries over the same connection (DoH, PP outside TLS)
         """
-        name = 'several-queries.doh-outside.proxy-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "several-queries.doh-outside.proxy-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         toProxyQueue.put(response, True, 2.0)
 
         reverseProxyPort = pickAvailablePort()
-        reverseProxy = threading.Thread(name='Mock Proxy Protocol Reverse Proxy', target=MockTCPReverseProxyAddingProxyProtocol, args=[reverseProxyPort, self._dohServerPPOutsidePort])
+        reverseProxy = threading.Thread(
+            name="Mock Proxy Protocol Reverse Proxy",
+            target=MockTCPReverseProxyAddingProxyProtocol,
+            args=[reverseProxyPort, self._dohServerPPOutsidePort],
+        )
         reverseProxy.start()
         time.sleep(1)
 
         receivedResponse = None
         conn = self.openDOHConnection(reverseProxyPort, self._caCert, timeout=2.0)
 
-        reverseProxyBaseURL = ("https://%s:%d/" % (self._serverName, reverseProxyPort))
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
+        reverseProxyBaseURL = "https://%s:%d/" % (self._serverName, reverseProxyPort)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            reverseProxyPort,
+            self._serverName,
+            reverseProxyBaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            conn=conn,
+        )
         (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
         self.assertTrue(receivedProxyPayload)
         self.assertTrue(receivedDNSData)
@@ -806,30 +938,72 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload,
+            "127.0.0.1",
+            "127.0.0.1",
+            True,
+            [
+                [0, b"foo"],
+                [1, b"dnsdist"],
+                [2, b"foo"],
+                [3, b"proxy"],
+                [32, ""],
+                [42, b"bar"],
+                [255, b"proxy-protocol"],
+            ],
+            v6=False,
+            sourcePort=None,
+            destinationPort=reverseProxyPort,
+        )
 
         for idx in range(5):
-          receivedResponse = None
-          toProxyQueue.put(response, True, 2.0)
-          (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
-          (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
-          self.assertTrue(receivedProxyPayload)
-          self.assertTrue(receivedDNSData)
-          self.assertTrue(receivedResponse)
-
-          receivedQuery = dns.message.from_wire(receivedDNSData)
-          receivedQuery.id = query.id
-          receivedResponse.id = response.id
-          self.assertEqual(receivedQuery, query)
-          self.assertEqual(receivedResponse, response)
-          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+            receivedResponse = None
+            toProxyQueue.put(response, True, 2.0)
+            (receivedQuery, receivedResponse) = self.sendDOHQuery(
+                reverseProxyPort,
+                self._serverName,
+                reverseProxyBaseURL,
+                query,
+                response=response,
+                caFile=self._caCert,
+                conn=conn,
+            )
+            (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+            self.assertTrue(receivedProxyPayload)
+            self.assertTrue(receivedDNSData)
+            self.assertTrue(receivedResponse)
+
+            receivedQuery = dns.message.from_wire(receivedDNSData)
+            receivedQuery.id = query.id
+            receivedResponse.id = response.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)
+            self.checkMessageProxyProtocol(
+                receivedProxyPayload,
+                "127.0.0.1",
+                "127.0.0.1",
+                True,
+                [
+                    [0, b"foo"],
+                    [1, b"dnsdist"],
+                    [2, b"foo"],
+                    [3, b"proxy"],
+                    [32, ""],
+                    [42, b"bar"],
+                    [255, b"proxy-protocol"],
+                ],
+                v6=False,
+                sourcePort=None,
+                destinationPort=reverseProxyPort,
+            )
 
     def testProxyDoHSeveralQueriesOverConnectionPPInside(self):
         """
         Incoming Proxy Protocol: Several queries over the same connection (DoH, PP inside TLS)
         """
-        name = 'several-queries.doh-inside.proxy-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "several-queries.doh-inside.proxy-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         toProxyQueue.put(response, True, 2.0)
@@ -837,16 +1011,28 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         reverseProxyPort = pickAvailablePort()
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
         tlsContext.load_cert_chain(self._serverCert, self._serverKey)
-        tlsContext.set_alpn_protocols(['h2'])
-        reverseProxy = threading.Thread(name='Mock Proxy Protocol Reverse Proxy', target=MockTCPReverseProxyAddingProxyProtocol, args=[reverseProxyPort, self._dohServerPPInsidePort, tlsContext, self._caCert, self._serverName])
+        tlsContext.set_alpn_protocols(["h2"])
+        reverseProxy = threading.Thread(
+            name="Mock Proxy Protocol Reverse Proxy",
+            target=MockTCPReverseProxyAddingProxyProtocol,
+            args=[reverseProxyPort, self._dohServerPPInsidePort, tlsContext, self._caCert, self._serverName],
+        )
         reverseProxy.start()
 
         receivedResponse = None
         time.sleep(1)
         conn = self.openDOHConnection(reverseProxyPort, self._caCert, timeout=2.0)
 
-        reverseProxyBaseURL = ("https://%s:%d/" % (self._serverName, reverseProxyPort))
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
+        reverseProxyBaseURL = "https://%s:%d/" % (self._serverName, reverseProxyPort)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(
+            reverseProxyPort,
+            self._serverName,
+            reverseProxyBaseURL,
+            query,
+            response=response,
+            caFile=self._caCert,
+            conn=conn,
+        )
         (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
         self.assertTrue(receivedProxyPayload)
         self.assertTrue(receivedDNSData)
@@ -857,36 +1043,82 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [ 42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload,
+            "127.0.0.1",
+            "127.0.0.1",
+            True,
+            [
+                [0, b"foo"],
+                [1, b"dnsdist"],
+                [2, b"foo"],
+                [3, b"proxy"],
+                [32, ""],
+                [42, b"bar"],
+                [255, b"proxy-protocol"],
+            ],
+            v6=False,
+            sourcePort=None,
+            destinationPort=reverseProxyPort,
+        )
 
         for idx in range(5):
-          receivedResponse = None
-          toProxyQueue.put(response, True, 2.0)
-          (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
-          (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
-          self.assertTrue(receivedProxyPayload)
-          self.assertTrue(receivedDNSData)
-          self.assertTrue(receivedResponse)
-
-          receivedQuery = dns.message.from_wire(receivedDNSData)
-          receivedQuery.id = query.id
-          receivedResponse.id = response.id
-          self.assertEqual(receivedQuery, query)
-          self.assertEqual(receivedResponse, response)
-          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [ 42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+            receivedResponse = None
+            toProxyQueue.put(response, True, 2.0)
+            (receivedQuery, receivedResponse) = self.sendDOHQuery(
+                reverseProxyPort,
+                self._serverName,
+                reverseProxyBaseURL,
+                query,
+                response=response,
+                caFile=self._caCert,
+                conn=conn,
+            )
+            (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+            self.assertTrue(receivedProxyPayload)
+            self.assertTrue(receivedDNSData)
+            self.assertTrue(receivedResponse)
+
+            receivedQuery = dns.message.from_wire(receivedDNSData)
+            receivedQuery.id = query.id
+            receivedResponse.id = response.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)
+            self.checkMessageProxyProtocol(
+                receivedProxyPayload,
+                "127.0.0.1",
+                "127.0.0.1",
+                True,
+                [
+                    [0, b"foo"],
+                    [1, b"dnsdist"],
+                    [2, b"foo"],
+                    [3, b"proxy"],
+                    [32, ""],
+                    [42, b"bar"],
+                    [255, b"proxy-protocol"],
+                ],
+                v6=False,
+                sourcePort=None,
+                destinationPort=reverseProxyPort,
+            )
 
     def testProxyDoTSeveralQueriesOverConnectionPPOutside(self):
         """
         Incoming Proxy Protocol: Several queries over the same connection (DoT, PP outside TLS)
         """
-        name = 'several-queries.dot-outside.proxy-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "several-queries.dot-outside.proxy-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         toProxyQueue.put(response, True, 2.0)
 
         reverseProxyPort = pickAvailablePort()
-        reverseProxy = threading.Thread(name='Mock Proxy Protocol Reverse Proxy', target=MockTCPReverseProxyAddingProxyProtocol, args=[reverseProxyPort, self._dotServerPPOutsidePort])
+        reverseProxy = threading.Thread(
+            name="Mock Proxy Protocol Reverse Proxy",
+            target=MockTCPReverseProxyAddingProxyProtocol,
+            args=[reverseProxyPort, self._dotServerPPOutsidePort],
+        )
         reverseProxy.start()
         time.sleep(1)
 
@@ -904,31 +1136,65 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+        self.checkMessageProxyProtocol(
+            receivedProxyPayload,
+            "127.0.0.1",
+            "127.0.0.1",
+            True,
+            [
+                [0, b"foo"],
+                [1, b"dnsdist"],
+                [2, b"foo"],
+                [3, b"proxy"],
+                [32, ""],
+                [42, b"bar"],
+                [255, b"proxy-protocol"],
+            ],
+            v6=False,
+            sourcePort=None,
+            destinationPort=reverseProxyPort,
+        )
 
         for idx in range(5):
-          receivedResponse = None
-          toProxyQueue.put(response, True, 2.0)
-          self.sendTCPQueryOverConnection(conn, query, response=response)
-          receivedResponse = self.recvTCPResponseOverConnection(conn)
-          (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
-          self.assertTrue(receivedProxyPayload)
-          self.assertTrue(receivedDNSData)
-          self.assertTrue(receivedResponse)
-
-          receivedQuery = dns.message.from_wire(receivedDNSData)
-          receivedQuery.id = query.id
-          receivedResponse.id = response.id
-          self.assertEqual(receivedQuery, query)
-          self.assertEqual(receivedResponse, response)
-          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+            receivedResponse = None
+            toProxyQueue.put(response, True, 2.0)
+            self.sendTCPQueryOverConnection(conn, query, response=response)
+            receivedResponse = self.recvTCPResponseOverConnection(conn)
+            (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+            self.assertTrue(receivedProxyPayload)
+            self.assertTrue(receivedDNSData)
+            self.assertTrue(receivedResponse)
+
+            receivedQuery = dns.message.from_wire(receivedDNSData)
+            receivedQuery.id = query.id
+            receivedResponse.id = response.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)
+            self.checkMessageProxyProtocol(
+                receivedProxyPayload,
+                "127.0.0.1",
+                "127.0.0.1",
+                True,
+                [
+                    [0, b"foo"],
+                    [1, b"dnsdist"],
+                    [2, b"foo"],
+                    [3, b"proxy"],
+                    [32, ""],
+                    [42, b"bar"],
+                    [255, b"proxy-protocol"],
+                ],
+                v6=False,
+                sourcePort=None,
+                destinationPort=reverseProxyPort,
+            )
 
     def testProxyDoTSeveralQueriesOverConnectionPPInside(self):
         """
         Incoming Proxy Protocol: Several queries over the same connection (DoT, PP inside TLS)
         """
-        name = 'several-queries.dot-inside.proxy-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "several-queries.dot-inside.proxy-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         toProxyQueue.put(response, True, 2.0)
@@ -936,8 +1202,12 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         reverseProxyPort = pickAvailablePort()
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
         tlsContext.load_cert_chain(self._serverCert, self._serverKey)
-        tlsContext.set_alpn_protocols(['dot'])
-        reverseProxy = threading.Thread(name='Mock Proxy Protocol Reverse Proxy', target=MockTCPReverseProxyAddingProxyProtocol, args=[reverseProxyPort, self._dotServerPPInsidePort, tlsContext, self._caCert, self._serverName])
+        tlsContext.set_alpn_protocols(["dot"])
+        reverseProxy = threading.Thread(
+            name="Mock Proxy Protocol Reverse Proxy",
+            target=MockTCPReverseProxyAddingProxyProtocol,
+            args=[reverseProxyPort, self._dotServerPPInsidePort, tlsContext, self._caCert, self._serverName],
+        )
         reverseProxy.start()
 
         receivedResponse = None
@@ -958,20 +1228,20 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         self.assertEqual(receivedResponse, response)
 
         for idx in range(5):
-          receivedResponse = None
-          toProxyQueue.put(response, True, 2.0)
-          self.sendTCPQueryOverConnection(conn, query, response=response)
-          receivedResponse = self.recvTCPResponseOverConnection(conn)
-          (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
-          self.assertTrue(receivedProxyPayload)
-          self.assertTrue(receivedDNSData)
-          self.assertTrue(receivedResponse)
-
-          receivedQuery = dns.message.from_wire(receivedDNSData)
-          receivedQuery.id = query.id
-          receivedResponse.id = response.id
-          self.assertEqual(receivedQuery, query)
-          self.assertEqual(receivedResponse, response)
+            receivedResponse = None
+            toProxyQueue.put(response, True, 2.0)
+            self.sendTCPQueryOverConnection(conn, query, response=response)
+            receivedResponse = self.recvTCPResponseOverConnection(conn)
+            (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+            self.assertTrue(receivedProxyPayload)
+            self.assertTrue(receivedDNSData)
+            self.assertTrue(receivedResponse)
+
+            receivedQuery = dns.message.from_wire(receivedDNSData)
+            receivedQuery.id = query.id
+            receivedResponse.id = response.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)
 
     @classmethod
     def tearDownClass(cls):
@@ -982,6 +1252,7 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
             backgroundThreads[backgroundThread] = False
         cls.killProcess(cls._dnsdist)
 
+
 class TestProxyProtocolIncomingValuesViaLua(DNSDistTest):
     """
     Check that dnsdist can retrieve incoming Proxy Protocol TLV values via Lua
@@ -989,7 +1260,8 @@ class TestProxyProtocolIncomingValuesViaLua(DNSDistTest):
 
     af_inet6 = str(socket.AF_INET6)
 
-    _config_template = """
+    _config_template = (
+        """
     setProxyProtocolACL( { "127.0.0.1/32" } )
 
     function checkValues(dq)
@@ -1034,12 +1306,16 @@ class TestProxyProtocolIncomingValuesViaLua(DNSDistTest):
 
     function checkValuesFFI(dqffi)
       C.dnsdist_ffi_dnsquestion_get_localaddr(dqffi, ret_ptr_param, ret_size_param)
-      local addr = C.inet_ntop("""+af_inet6+""", ret_ptr[0], inet_buffer, 256)
+      local addr = C.inet_ntop("""
+        + af_inet6
+        + """, ret_ptr[0], inet_buffer, 256)
       if addr == nil or ffi.string(addr) ~= '2001:db8::9' then
         return sendResult(dqffi, "invalid.local.addr.")
       end
       C.dnsdist_ffi_dnsquestion_get_remoteaddr(dqffi, ret_ptr_param, ret_size_param)
-      local addr = C.inet_ntop("""+af_inet6+""", ret_ptr[0], inet_buffer, 256)
+      local addr = C.inet_ntop("""
+        + af_inet6
+        + """, ret_ptr[0], inet_buffer, 256)
       if addr == nil or ffi.string(addr) ~= '2001:db8::8' then
         return sendResult(dqffi, "invalid.remote.addr.")
       end
@@ -1074,6 +1350,7 @@ class TestProxyProtocolIncomingValuesViaLua(DNSDistTest):
 
     newServer{address="127.0.0.1:%d"}
     """
+    )
 
     def testProxyUDPWithValuesFromLua(self):
         """
@@ -1083,24 +1360,25 @@ class TestProxyProtocolIncomingValuesViaLua(DNSDistTest):
         destPort = 9999
         srcAddr = "2001:db8::8"
         srcPort = 8888
-        names = ['proxy-protocol-incoming-values-via-lua.tests.powerdns.com.',
-                 'proxy-protocol-incoming-values-via-lua-ffi.tests.powerdns.com.'
-                 ]
+        names = [
+            "proxy-protocol-incoming-values-via-lua.tests.powerdns.com.",
+            "proxy-protocol-incoming-values-via-lua-ffi.tests.powerdns.com.",
+        ]
         for name in names:
-            query = dns.message.make_query(name, 'A', 'IN')
+            query = dns.message.make_query(name, "A", "IN")
             # dnsdist set RA = RD for spoofed responses
             query.flags &= ~dns.flags.RD
 
             expectedResponse = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(name,
-                                        60,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.CNAME,
-                                        'ok.')
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "ok.")
             expectedResponse.answer.append(rrset)
 
-            udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
-            (_, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True)
+            udpPayload = ProxyProtocol.getPayload(
+                False, False, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [3, b"proxy"]]
+            )
+            (_, receivedResponse) = self.sendUDPQuery(
+                udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True
+            )
             self.assertEqual(expectedResponse, receivedResponse)
 
             conn = self.openTCPConnection(2.0)
@@ -1110,9 +1388,10 @@ class TestProxyProtocolIncomingValuesViaLua(DNSDistTest):
                 conn.send(query.to_wire())
                 receivedResponse = self.recvTCPResponseOverConnection(conn)
             except socket.timeout:
-                print('timeout')
+                print("timeout")
             self.assertEqual(expectedResponse, receivedResponse)
 
+
 class TestProxyProtocolNotExpected(DNSDistTest):
     """
     dnsdist is configured to expect a Proxy Protocol header on incoming queries but not from 127.0.0.1
@@ -1123,37 +1402,33 @@ class TestProxyProtocolNotExpected(DNSDistTest):
     newServer{address="127.0.0.1:%d"}
     """
     # NORMAL responder, does not expect a proxy protocol payload!
-    _config_params = ['_testServerPort']
+    _config_params = ["_testServerPort"]
 
     def testNoHeader(self):
         """
         Unexpected Proxy Protocol: no header
         """
         # no proxy protocol header and none is expected from this source, should be passed on
-        name = 'no-header.unexpected-proxy-protocol.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "no-header.unexpected-proxy-protocol.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
-          sender = getattr(self, method)
-          (receivedQuery, receivedResponse) = sender(query, response)
-          receivedQuery.id = query.id
-          self.assertEqual(query, receivedQuery)
-          self.assertEqual(response, receivedResponse)
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, response)
+            receivedQuery.id = query.id
+            self.assertEqual(query, receivedQuery)
+            self.assertEqual(response, receivedResponse)
 
     def testIncomingProxyDest(self):
         """
         Unexpected Proxy Protocol: should be dropped
         """
-        name = 'with-proxy-payload.unexpected-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "with-proxy-payload.unexpected-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         # Make sure that the proxy payload does NOT turn into a legal qname
         destAddr = "ff:db8::ffff"
@@ -1161,28 +1436,36 @@ class TestProxyProtocolNotExpected(DNSDistTest):
         srcAddr = "ff:db8::ffff"
         srcPort = 65535
 
-        udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
-        (_, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True)
+        udpPayload = ProxyProtocol.getPayload(
+            False, False, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [3, b"proxy"]]
+        )
+        (_, receivedResponse) = self.sendUDPQuery(
+            udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True
+        )
         self.assertEqual(receivedResponse, None)
 
-        tcpPayload = ProxyProtocol.getPayload(False, True, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
+        tcpPayload = ProxyProtocol.getPayload(
+            False, True, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [3, b"proxy"]]
+        )
         wire = query.to_wire()
 
         receivedResponse = None
         try:
-          conn = self.openTCPConnection(2.0)
-          conn.send(tcpPayload)
-          conn.send(struct.pack("!H", len(wire)))
-          conn.send(wire)
-          receivedResponse = self.recvTCPResponseOverConnection(conn)
+            conn = self.openTCPConnection(2.0)
+            conn.send(tcpPayload)
+            conn.send(struct.pack("!H", len(wire)))
+            conn.send(wire)
+            receivedResponse = self.recvTCPResponseOverConnection(conn)
         except socket.timeout:
-          print('timeout')
+            print("timeout")
         self.assertEqual(receivedResponse, None)
 
+
 class TestProxyProtocolNotAllowedOnBind(DNSDistTest):
     """
     dnsdist is configured to expect a Proxy Protocol header on incoming queries but not on the 127.0.0.1 bind
     """
+
     _skipListeningOnCL = True
     _config_template = """
     -- proxy protocol payloads are not allowed on this bind address!
@@ -1191,37 +1474,33 @@ class TestProxyProtocolNotAllowedOnBind(DNSDistTest):
     newServer{address="127.0.0.1:%d"}
     """
     # NORMAL responder, does not expect a proxy protocol payload!
-    _config_params = ['_dnsDistPort', '_testServerPort']
+    _config_params = ["_dnsDistPort", "_testServerPort"]
 
     def testNoHeader(self):
         """
         Unexpected Proxy Protocol: no header
         """
         # no proxy protocol header and none is expected from this source, should be passed on
-        name = 'no-header.unexpected-proxy-protocol.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "no-header.unexpected-proxy-protocol.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
-          sender = getattr(self, method)
-          (receivedQuery, receivedResponse) = sender(query, response)
-          receivedQuery.id = query.id
-          self.assertEqual(query, receivedQuery)
-          self.assertEqual(response, receivedResponse)
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, response)
+            receivedQuery.id = query.id
+            self.assertEqual(query, receivedQuery)
+            self.assertEqual(response, receivedResponse)
 
     def testIncomingProxyDest(self):
         """
         Unexpected Proxy Protocol: should be dropped
         """
-        name = 'with-proxy-payload.unexpected-protocol-incoming.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "with-proxy-payload.unexpected-protocol-incoming.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         # Make sure that the proxy payload does NOT turn into a legal qname
         destAddr = "ff:db8::ffff"
@@ -1229,39 +1508,45 @@ class TestProxyProtocolNotAllowedOnBind(DNSDistTest):
         srcAddr = "ff:db8::ffff"
         srcPort = 65535
 
-        udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
-        (_, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True)
+        udpPayload = ProxyProtocol.getPayload(
+            False, False, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [3, b"proxy"]]
+        )
+        (_, receivedResponse) = self.sendUDPQuery(
+            udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True
+        )
         self.assertEqual(receivedResponse, None)
 
-        tcpPayload = ProxyProtocol.getPayload(False, True, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
+        tcpPayload = ProxyProtocol.getPayload(
+            False, True, True, srcAddr, destAddr, srcPort, destPort, [[2, b"foo"], [3, b"proxy"]]
+        )
         wire = query.to_wire()
 
         receivedResponse = None
         try:
-          conn = self.openTCPConnection(2.0)
-          conn.send(tcpPayload)
-          conn.send(struct.pack("!H", len(wire)))
-          conn.send(wire)
-          receivedResponse = self.recvTCPResponseOverConnection(conn)
+            conn = self.openTCPConnection(2.0)
+            conn.send(tcpPayload)
+            conn.send(struct.pack("!H", len(wire)))
+            conn.send(wire)
+            receivedResponse = self.recvTCPResponseOverConnection(conn)
         except socket.timeout:
-          print('timeout')
+            print("timeout")
         self.assertEqual(receivedResponse, None)
 
-class TestDOHWithOutgoingProxyProtocol(DNSDistDOHTest):
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+class TestDOHWithOutgoingProxyProtocol(DNSDistDOHTest):
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
-    _dohWithNGHTTP2BaseURL = ("https://%s:%d/dns-query" % (_serverName, _dohWithNGHTTP2ServerPort))
+    _dohWithNGHTTP2BaseURL = "https://%s:%d/dns-query" % (_serverName, _dohWithNGHTTP2ServerPort)
     _proxyResponderPort = proxyResponderPort
     _config_template = """
     newServer{address="127.0.0.1:%d", useProxyProtocol=true}
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { '/dns-query' }, { trustForwardedForHeader=true, library='nghttp2' })
     setACL( { "::1/128", "127.0.0.0/8" } )
     """
-    _config_params = ['_proxyResponderPort', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey']
+    _config_params = ["_proxyResponderPort", "_dohWithNGHTTP2ServerPort", "_serverCert", "_serverKey"]
 
     def testTruncation(self):
         """
@@ -1269,91 +1554,110 @@ class TestDOHWithOutgoingProxyProtocol(DNSDistDOHTest):
         """
         # the query is first forwarded over UDP, leading to a TC=1 answer from the
         # backend, then over TCP
-        name = 'truncated-udp.doh.proxy-protocol.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "truncated-udp.doh.proxy-protocol.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.id = 42
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 42
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        for (port,url) in [(self._dohWithNGHTTP2ServerPort, self._dohWithNGHTTP2BaseURL)]:
-          # first response is a TC=1
-          tcResponse = dns.message.make_response(query)
-          tcResponse.flags |= dns.flags.TC
-          toProxyQueue.put(tcResponse, True, 2.0)
-
-          ((receivedProxyPayload, receivedDNSData), receivedResponse) = self.sendDOHQuery(port, self._serverName, url, query, caFile=self._caCert, response=response, fromQueue=fromProxyQueue, toQueue=toProxyQueue)
-          # first query, received by the responder over UDP
-          self.assertTrue(receivedProxyPayload)
-          self.assertTrue(receivedDNSData)
-          receivedQuery = dns.message.from_wire(receivedDNSData)
-          self.assertTrue(receivedQuery)
-          receivedQuery.id = expectedQuery.id
-          self.assertEqual(expectedQuery, receivedQuery)
-          self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
-          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, destinationPort=port)
-
-          # check the response
-          self.assertTrue(receivedResponse)
-          self.assertEqual(response, receivedResponse)
-
-          # check the second query, received by the responder over TCP
-          (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
-          self.assertTrue(receivedDNSData)
-          receivedQuery = dns.message.from_wire(receivedDNSData)
-          self.assertTrue(receivedQuery)
-          receivedQuery.id = expectedQuery.id
-          self.assertEqual(expectedQuery, receivedQuery)
-          self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
-          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, destinationPort=port)
-
-          # make sure we consumed everything
-          self.assertTrue(toProxyQueue.empty())
-          self.assertTrue(fromProxyQueue.empty())
+        for port, url in [(self._dohWithNGHTTP2ServerPort, self._dohWithNGHTTP2BaseURL)]:
+            # first response is a TC=1
+            tcResponse = dns.message.make_response(query)
+            tcResponse.flags |= dns.flags.TC
+            toProxyQueue.put(tcResponse, True, 2.0)
+
+            ((receivedProxyPayload, receivedDNSData), receivedResponse) = self.sendDOHQuery(
+                port,
+                self._serverName,
+                url,
+                query,
+                caFile=self._caCert,
+                response=response,
+                fromQueue=fromProxyQueue,
+                toQueue=toProxyQueue,
+            )
+            # first query, received by the responder over UDP
+            self.assertTrue(receivedProxyPayload)
+            self.assertTrue(receivedDNSData)
+            receivedQuery = dns.message.from_wire(receivedDNSData)
+            self.assertTrue(receivedQuery)
+            receivedQuery.id = expectedQuery.id
+            self.assertEqual(expectedQuery, receivedQuery)
+            self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
+            self.checkMessageProxyProtocol(receivedProxyPayload, "127.0.0.1", "127.0.0.1", True, destinationPort=port)
+
+            # check the response
+            self.assertTrue(receivedResponse)
+            self.assertEqual(response, receivedResponse)
+
+            # check the second query, received by the responder over TCP
+            (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+            self.assertTrue(receivedDNSData)
+            receivedQuery = dns.message.from_wire(receivedDNSData)
+            self.assertTrue(receivedQuery)
+            receivedQuery.id = expectedQuery.id
+            self.assertEqual(expectedQuery, receivedQuery)
+            self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
+            self.checkMessageProxyProtocol(receivedProxyPayload, "127.0.0.1", "127.0.0.1", True, destinationPort=port)
+
+            # make sure we consumed everything
+            self.assertTrue(toProxyQueue.empty())
+            self.assertTrue(fromProxyQueue.empty())
 
     def testAddressFamilyMismatch(self):
         """
         DOH with IPv6 X-Forwarded-For to an IPv4 endpoint
         """
-        name = 'x-forwarded-for-af-mismatch.doh.outgoing-proxy-protocol.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "x-forwarded-for-af-mismatch.doh.outgoing-proxy-protocol.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        for (port,url) in [(self._dohWithNGHTTP2ServerPort, self._dohWithNGHTTP2BaseURL)]:
-          # the query should be dropped
-          (receivedQuery, receivedResponse) = self.sendDOHQuery(port, self._serverName, url, query, caFile=self._caCert, customHeaders=['x-forwarded-for: [::1]:8080'], useQueue=False)
-          self.assertFalse(receivedQuery)
-          self.assertFalse(receivedResponse)
-
-          # make sure the timeout is detected, if any
-          time.sleep(4)
-
-          # this one should not
-          ((receivedProxyPayload, receivedDNSData), receivedResponse) = self.sendDOHQuery(port, self._serverName, url, query, caFile=self._caCert, customHeaders=['x-forwarded-for: 127.0.0.42:8080'], response=response, fromQueue=fromProxyQueue, toQueue=toProxyQueue)
-          self.assertTrue(receivedProxyPayload)
-          self.assertTrue(receivedDNSData)
-          receivedQuery = dns.message.from_wire(receivedDNSData)
-          self.assertTrue(receivedQuery)
-          receivedQuery.id = expectedQuery.id
-          self.assertEqual(expectedQuery, receivedQuery)
-          self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
-          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.42', '127.0.0.1', True, destinationPort=port)
-          # check the response
-          self.assertTrue(receivedResponse)
-          receivedResponse.id = response.id
-          self.assertEqual(response, receivedResponse)
+        for port, url in [(self._dohWithNGHTTP2ServerPort, self._dohWithNGHTTP2BaseURL)]:
+            # the query should be dropped
+            (receivedQuery, receivedResponse) = self.sendDOHQuery(
+                port,
+                self._serverName,
+                url,
+                query,
+                caFile=self._caCert,
+                customHeaders=["x-forwarded-for: [::1]:8080"],
+                useQueue=False,
+            )
+            self.assertFalse(receivedQuery)
+            self.assertFalse(receivedResponse)
+
+            # make sure the timeout is detected, if any
+            time.sleep(4)
+
+            # this one should not
+            ((receivedProxyPayload, receivedDNSData), receivedResponse) = self.sendDOHQuery(
+                port,
+                self._serverName,
+                url,
+                query,
+                caFile=self._caCert,
+                customHeaders=["x-forwarded-for: 127.0.0.42:8080"],
+                response=response,
+                fromQueue=fromProxyQueue,
+                toQueue=toProxyQueue,
+            )
+            self.assertTrue(receivedProxyPayload)
+            self.assertTrue(receivedDNSData)
+            receivedQuery = dns.message.from_wire(receivedDNSData)
+            self.assertTrue(receivedQuery)
+            receivedQuery.id = expectedQuery.id
+            self.assertEqual(expectedQuery, receivedQuery)
+            self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
+            self.checkMessageProxyProtocol(receivedProxyPayload, "127.0.0.42", "127.0.0.1", True, destinationPort=port)
+            # check the response
+            self.assertTrue(receivedResponse)
+            receivedResponse.id = response.id
+            self.assertEqual(response, receivedResponse)
index 4a658bfed513ff294ff5a935950c38167ce398dd..6a865245b222c0fdcd8c00a874f3d3ebb6e678ea 100644 (file)
@@ -2,6 +2,7 @@
 import dns
 from dnsdisttests import DNSDistTest
 
+
 class TestRE2(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -15,8 +16,8 @@ class TestRE2(DNSDistTest):
         """
         RE2: Match
         """
-        name = 're2.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "re2.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -30,15 +31,11 @@ class TestRE2(DNSDistTest):
         """
         RE2: No match
         """
-        name = 'sub.re2.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "sub.re2.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
 
index 6954d37fc697695b1abe2612ec9b9df85191fab5..f573bee425074bbac71828a28aaf57e17da336dc 100644 (file)
@@ -3,13 +3,14 @@ import dns
 import socket
 from dnsdisttests import DNSDistTest
 
+
 class RandomizedIDs:
     def testRandomizedIDOverUDPFromLuaConfig(self):
         """
         Randomized IDs over UDP: Lua config
         """
-        name = 'lua-config.randomizedids.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "lua-config.randomizedids.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         randomized = False
@@ -24,12 +25,14 @@ class RandomizedIDs:
 
         self.assertTrue(randomized)
 
+
 class RandomizedIDsLuaConfig(DNSDistTest, RandomizedIDs):
     _config_template = """
     setRandomizedIdsOverUDP(true)
     newServer{address="127.0.0.1:%d"}
     """
 
+
 class RandomizedIDsYAMLConfig(DNSDistTest, RandomizedIDs):
     _yaml_config_template = """
 backends:
@@ -39,5 +42,5 @@ tuning:
   udp:
     randomize_ids_to_backend: true
     """
-    _yaml_config_params = ['_testServerPort']
+    _yaml_config_params = ["_testServerPort"]
     _config_params = []
index a4285bb705338529883905f5265f6a726b9996ee..7032450a847addb75eda27902608396af5dfec07 100644 (file)
@@ -2,8 +2,8 @@
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestRecordsCountOnlyOneAR(DNSDistTest):
 
+class TestRecordsCountOnlyOneAR(DNSDistTest):
     _config_template = """
     addAction(NotRule(RecordsCountRule(DNSSection.Additional, 1, 1)), RCodeAction(DNSRCode.REFUSED))
     newServer{address="127.0.0.1:%d"}
@@ -16,8 +16,8 @@ class TestRecordsCountOnlyOneAR(DNSDistTest):
         Send a query to "refuseemptyar.recordscount.tests.powerdns.com.",
         check that we are getting a REFUSED response.
         """
-        name = 'refuseemptyar.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "refuseemptyar.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -34,14 +34,10 @@ class TestRecordsCountOnlyOneAR(DNSDistTest):
         Send a query to "allowonear.recordscount.tests.powerdns.com.",
         check that we are getting a valid response.
         """
-        name = 'allowonear.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "allowonear.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         response = dns.message.make_response(query)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   3600,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '127.0.0.1'))
+        response.answer.append(dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1"))
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -59,14 +55,10 @@ class TestRecordsCountOnlyOneAR(DNSDistTest):
         Send a query to "refusetwoar.recordscount.tests.powerdns.com.",
         check that we are getting a REFUSED response.
         """
-        name = 'refusetwoar.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "refusetwoar.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         query.flags &= ~dns.flags.RD
-        query.additional.append(dns.rrset.from_text(name,
-                                                    3600,
-                                                    dns.rdataclass.IN,
-                                                    dns.rdatatype.A,
-                                                    '127.0.0.1'))
+        query.additional.append(dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1"))
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
 
@@ -75,8 +67,8 @@ class TestRecordsCountOnlyOneAR(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestRecordsCountMoreThanOneLessThanFour(DNSDistTest):
 
+class TestRecordsCountMoreThanOneLessThanFour(DNSDistTest):
     _config_template = """
     addAction(RecordsCountRule(DNSSection.Answer, 2, 3), AllowAction())
     addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
@@ -90,8 +82,8 @@ class TestRecordsCountMoreThanOneLessThanFour(DNSDistTest):
         Send a query to "refusenoan.recordscount.tests.powerdns.com.",
         check that we are getting a REFUSED response.
         """
-        name = 'refusenoan.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "refusenoan.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -108,13 +100,9 @@ class TestRecordsCountMoreThanOneLessThanFour(DNSDistTest):
         Send a query to "allowtwoan.recordscount.tests.powerdns.com.",
         check that we are getting a valid response.
         """
-        name = 'allowtwoan.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
-        rrset = dns.rrset.from_text_list(name,
-                                         3600,
-                                         dns.rdataclass.IN,
-                                         dns.rdatatype.A,
-                                         ['127.0.0.1', '127.0.0.2'])
+        name = "allowtwoan.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
+        rrset = dns.rrset.from_text_list(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, ["127.0.0.1", "127.0.0.2"])
         query.answer.append(rrset)
         response = dns.message.make_response(query)
         response.answer.append(rrset)
@@ -135,14 +123,12 @@ class TestRecordsCountMoreThanOneLessThanFour(DNSDistTest):
         Send a query to "refusefouran.recordscount.tests.powerdns.com.",
         check that we are getting a REFUSED response.
         """
-        name = 'refusefouran.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "refusefouran.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         query.flags &= ~dns.flags.RD
-        rrset = dns.rrset.from_text_list(name,
-                                         3600,
-                                         dns.rdataclass.IN,
-                                         dns.rdatatype.A,
-                                         ['127.0.0.1', '127.0.0.2', '127.0.0.3', '127.0.0.4'])
+        rrset = dns.rrset.from_text_list(
+            name, 3600, dns.rdataclass.IN, dns.rdatatype.A, ["127.0.0.1", "127.0.0.2", "127.0.0.3", "127.0.0.4"]
+        )
         query.answer.append(rrset)
 
         expectedResponse = dns.message.make_response(query)
@@ -153,8 +139,8 @@ class TestRecordsCountMoreThanOneLessThanFour(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestRecordsCountNothingInNS(DNSDistTest):
 
+class TestRecordsCountNothingInNS(DNSDistTest):
     _config_template = """
     addAction(RecordsCountRule(DNSSection.Authority, 0, 0), AllowAction())
     addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
@@ -168,13 +154,9 @@ class TestRecordsCountNothingInNS(DNSDistTest):
         Send a query to "refusens.recordscount.tests.powerdns.com.",
         check that we are getting a REFUSED response.
         """
-        name = 'refusens.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.NS,
-                                    'ns.tests.powerdns.com.')
+        name = "refusens.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.NS, "ns.tests.powerdns.com.")
         query.authority.append(rrset)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
@@ -185,7 +167,6 @@ class TestRecordsCountNothingInNS(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-
     def testRecordsCountAllowEmptyNS(self):
         """
         RecordsCount: Allow nscount == 0
@@ -193,14 +174,10 @@ class TestRecordsCountNothingInNS(DNSDistTest):
         Send a query to "allowns.recordscount.tests.powerdns.com.",
         check that we are getting a valid response.
         """
-        name = 'allowns.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "allowns.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   3600,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '127.0.0.1'))
+        response.answer.append(dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1"))
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -211,8 +188,8 @@ class TestRecordsCountNothingInNS(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-class TestRecordsCountNoOPTInAR(DNSDistTest):
 
+class TestRecordsCountNoOPTInAR(DNSDistTest):
     _config_template = """
     addAction(NotRule(RecordsTypeCountRule(DNSSection.Additional, DNSQType.OPT, 0, 0)), RCodeAction(DNSRCode.REFUSED))
     newServer{address="127.0.0.1:%d"}
@@ -225,8 +202,8 @@ class TestRecordsCountNoOPTInAR(DNSDistTest):
         Send a query to "refuseoptinar.recordscount.tests.powerdns.com.",
         check that we are getting a REFUSED response.
         """
-        name = 'refuseoptinar.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "refuseoptinar.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -243,14 +220,10 @@ class TestRecordsCountNoOPTInAR(DNSDistTest):
         Send a query to "allownooptinar.recordscount.tests.powerdns.com.",
         check that we are getting a valid response.
         """
-        name = 'allowwnooptinar.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "allowwnooptinar.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   3600,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '127.0.0.1'))
+        response.answer.append(dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1"))
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -268,25 +241,13 @@ class TestRecordsCountNoOPTInAR(DNSDistTest):
         Send a query to "allowtwoarnoopt.recordscount.tests.powerdns.com.",
         check that we are getting a valid response.
         """
-        name = 'allowtwoarnoopt.recordscount.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        query.additional.append(dns.rrset.from_text(name,
-                                                    3600,
-                                                    dns.rdataclass.IN,
-                                                    dns.rdatatype.A,
-                                                    '127.0.0.1'))
-        query.additional.append(dns.rrset.from_text(name,
-                                                    3600,
-                                                    dns.rdataclass.IN,
-                                                    dns.rdatatype.A,
-                                                    '127.0.0.1'))
+        name = "allowtwoarnoopt.recordscount.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        query.additional.append(dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1"))
+        query.additional.append(dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1"))
 
         response = dns.message.make_response(query)
-        response.answer.append(dns.rrset.from_text(name,
-                                                   3600,
-                                                   dns.rdataclass.IN,
-                                                   dns.rdatatype.A,
-                                                   '127.0.0.1'))
+        response.answer.append(dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1"))
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
index b894a86e2d342f68bad6a36a5c1ce11704ef2ab6..da4dd12f33b466ea1c7a92513b3e31ca7c2c0f6e 100644 (file)
@@ -4,8 +4,8 @@ import dns
 import cookiesoption
 from dnsdisttests import DNSDistTest
 
-class TestResponseRuleNXDelayed(DNSDistTest):
 
+class TestResponseRuleNXDelayed(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addResponseAction(RCodeRule(DNSRCode.NXDOMAIN), DelayResponseAction(1000))
@@ -19,8 +19,8 @@ class TestResponseRuleNXDelayed(DNSDistTest):
         check that the response delay is longer than 1000 ms
         for a NXDomain response over UDP, shorter for a NoError one.
         """
-        name = 'delayed.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "delayed.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         # NX over UDP
@@ -53,8 +53,8 @@ class TestResponseRuleNXDelayed(DNSDistTest):
         self.assertEqual(response, receivedResponse)
         self.assertLess(end - begin, timedelta(0, 1))
 
-class TestResponseRuleERCode(DNSDistTest):
 
+class TestResponseRuleERCode(DNSDistTest):
     _extraStartupSleep = 1
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -69,8 +69,8 @@ class TestResponseRuleERCode(DNSDistTest):
         check that the response delay is longer than 1000 ms
         for a BADVERS response over UDP, shorter for BADKEY and NoError.
         """
-        name = 'delayed.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "delayed.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.use_edns(edns=True)
 
@@ -105,8 +105,8 @@ class TestResponseRuleERCode(DNSDistTest):
         self.assertEqual(response, receivedResponse)
         self.assertLess(end - begin, timedelta(0, 1))
 
-class TestResponseRuleQNameDropped(DNSDistTest):
 
+class TestResponseRuleQNameDropped(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addResponseAction("drop.responses.tests.powerdns.com.", DropResponseAction())
@@ -119,8 +119,8 @@ class TestResponseRuleQNameDropped(DNSDistTest):
         Send an A query to "drop.responses.tests.powerdns.com.",
         check that the response (not the query) is dropped.
         """
-        name = 'drop.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "drop.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -137,8 +137,8 @@ class TestResponseRuleQNameDropped(DNSDistTest):
         Send an A query to "dontdrop.responses.tests.powerdns.com.",
         check that the response is not dropped.
         """
-        name = 'dontdrop.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "dontdrop.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -148,8 +148,8 @@ class TestResponseRuleQNameDropped(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-class TestResponseRuleQNameAllowed(DNSDistTest):
 
+class TestResponseRuleQNameAllowed(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addResponseAction("allow.responses.tests.powerdns.com.", AllowResponseAction())
@@ -163,8 +163,8 @@ class TestResponseRuleQNameAllowed(DNSDistTest):
         Send an A query to "allow.responses.tests.powerdns.com.",
         check that the response is allowed.
         """
-        name = 'allow.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "allow.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -181,8 +181,8 @@ class TestResponseRuleQNameAllowed(DNSDistTest):
         Send an A query to "dontallow.responses.tests.powerdns.com.",
         check that the response is dropped.
         """
-        name = 'dontallow.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "dontallow.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -192,10 +192,10 @@ class TestResponseRuleQNameAllowed(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(receivedResponse, None)
 
-class TestResponseRuleEditTTL(DNSDistTest):
 
+class TestResponseRuleEditTTL(DNSDistTest):
     _ttl = 5
-    _config_params = ['_testServerPort', '_ttl']
+    _config_params = ["_testServerPort", "_ttl"]
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -215,14 +215,10 @@ class TestResponseRuleEditTTL(DNSDistTest):
         """
         Responses: Alter the TTLs
         """
-        name = 'editttl.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "editttl.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -234,12 +230,12 @@ class TestResponseRuleEditTTL(DNSDistTest):
             self.assertNotEqual(response.answer[0].ttl, receivedResponse.answer[0].ttl)
             self.assertEqual(receivedResponse.answer[0].ttl, self._ttl)
 
-class TestResponseRuleLimitTTL(DNSDistTest):
 
+class TestResponseRuleLimitTTL(DNSDistTest):
     _lowttl = 60
     _defaultttl = 3600
     _highttl = 18000
-    _config_params = ['_lowttl', '_highttl', '_testServerPort']
+    _config_params = ["_lowttl", "_highttl", "_testServerPort"]
     _config_template = """
     local ffi = require("ffi")
     local lowttl = %d
@@ -266,14 +262,10 @@ class TestResponseRuleLimitTTL(DNSDistTest):
         """
         Responses: Alter the TTLs via Limiter
         """
-        name = 'min.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "min.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -285,14 +277,10 @@ class TestResponseRuleLimitTTL(DNSDistTest):
             self.assertNotEqual(response.answer[0].ttl, receivedResponse.answer[0].ttl)
             self.assertEqual(receivedResponse.answer[0].ttl, self._highttl)
 
-        name = 'max.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "max.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -308,14 +296,10 @@ class TestResponseRuleLimitTTL(DNSDistTest):
         """
         Responses: Alter the TTLs via Limiter
         """
-        name = 'ffi.min.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "ffi.min.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -327,14 +311,10 @@ class TestResponseRuleLimitTTL(DNSDistTest):
             self.assertNotEqual(response.answer[0].ttl, receivedResponse.answer[0].ttl)
             self.assertEqual(receivedResponse.answer[0].ttl, self._highttl)
 
-        name = 'ffi.max.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "ffi.max.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -346,11 +326,11 @@ class TestResponseRuleLimitTTL(DNSDistTest):
             self.assertNotEqual(response.answer[0].ttl, receivedResponse.answer[0].ttl)
             self.assertEqual(receivedResponse.answer[0].ttl, self._lowttl)
 
-class TestSetReducedTTL(DNSDistTest):
 
+class TestSetReducedTTL(DNSDistTest):
     _percentage = 42
     _initialTTL = 100
-    _config_params = ['_percentage', '_testServerPort']
+    _config_params = ["_percentage", "_testServerPort"]
     _config_template = """
     addResponseAction(AllRule(), SetReducedTTLResponseAction(%d))
     newServer{address="127.0.0.1:%d"}
@@ -360,14 +340,10 @@ class TestSetReducedTTL(DNSDistTest):
         """
         Responses: Reduce TTL to 42%
         """
-        name = 'reduced-ttl.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "reduced-ttl.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    self._initialTTL,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, self._initialTTL, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -379,8 +355,8 @@ class TestSetReducedTTL(DNSDistTest):
             self.assertNotEqual(response.answer[0].ttl, receivedResponse.answer[0].ttl)
             self.assertEqual(receivedResponse.answer[0].ttl, self._percentage)
 
-class TestResponseLuaActionReturnSyntax(DNSDistTest):
 
+class TestResponseLuaActionReturnSyntax(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     function customDelay(dr)
@@ -401,8 +377,8 @@ class TestResponseLuaActionReturnSyntax(DNSDistTest):
         check that the response delay is longer than 1000 ms
         for a NXDomain response over UDP, shorter for a NoError one.
         """
-        name = 'delayed.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "delayed.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         # NX over UDP
@@ -422,8 +398,8 @@ class TestResponseLuaActionReturnSyntax(DNSDistTest):
         Send an A query to "drop.responses.tests.powerdns.com.",
         check that the response (not the query) is dropped.
         """
-        name = 'drop.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "drop.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -433,9 +409,9 @@ class TestResponseLuaActionReturnSyntax(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(receivedResponse, None)
 
-class TestResponseClearRecordsType(DNSDistTest):
 
-    _config_params = ['_testServerPort']
+class TestResponseClearRecordsType(DNSDistTest):
+    _config_params = ["_testServerPort"]
     _config_template = """
     local ffi = require("ffi")
 
@@ -454,22 +430,14 @@ class TestResponseClearRecordsType(DNSDistTest):
         """
         Responses: Removes records of a given type (FFI API)
         """
-        name = 'ffi.clear-records-type.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "ffi.clear-records-type.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
-        rrset = dns.rrset.from_text(name,
-                                    3660,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1', '2001:DB8::2')
+        rrset = dns.rrset.from_text(name, 3660, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1", "2001:DB8::2")
         response.answer.append(rrset)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -482,22 +450,14 @@ class TestResponseClearRecordsType(DNSDistTest):
         """
         Responses: Removes records of a given type
         """
-        name = 'clear-records-type.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "clear-records-type.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
-        rrset = dns.rrset.from_text(name,
-                                    3660,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1', '2001:DB8::2')
+        rrset = dns.rrset.from_text(name, 3660, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1", "2001:DB8::2")
         response.answer.append(rrset)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -506,9 +466,9 @@ class TestResponseClearRecordsType(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestResponseRewriteServFail(DNSDistTest):
 
-    _config_params = ['_testServerPort']
+class TestResponseRewriteServFail(DNSDistTest):
+    _config_params = ["_testServerPort"]
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -526,20 +486,16 @@ class TestResponseRewriteServFail(DNSDistTest):
         """
         Responses: Rewrite AAAA ServFails as NoError (don't ask)
         """
-        name = 'rewrite-servfail.responses.tests.powerdns.com.'
+        name = "rewrite-servfail.responses.tests.powerdns.com."
 
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
         expectedResponse = dns.message.make_response(query)
 
         response.set_rcode(dns.rcode.SERVFAIL)
         expectedResponse.set_rcode(dns.rcode.NOERROR)
 
-        rrset = dns.rrset.from_text(name,
-                                    3660,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1', '2001:DB8::2')
+        rrset = dns.rrset.from_text(name, 3660, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1", "2001:DB8::2")
         response.answer.append(rrset)
         expectedResponse.answer.append(rrset)
 
@@ -551,14 +507,10 @@ class TestResponseRewriteServFail(DNSDistTest):
             self.assertEqual(expectedResponse, receivedResponse)
 
         # but ServFail for a different type should stay the same
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.SERVFAIL)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -567,6 +519,7 @@ class TestResponseRewriteServFail(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
+
 class TestAdvancedSetEDNSOptionResponseAction(DNSDistTest):
     _config_template = """
     addResponseAction(AllRule(), SetEDNSOptionResponseAction(10, "deadbeefdeadc0de"))
@@ -577,18 +530,14 @@ class TestAdvancedSetEDNSOptionResponseAction(DNSDistTest):
         """
         Responses: Set EDNS Option in response
         """
-        name = 'setednsoptionresponse.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "setednsoptionresponse.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=512)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadc0de')
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadc0de")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=512, options=[eco])
         expectedResponse.answer.append(rrset)
@@ -606,19 +555,15 @@ class TestAdvancedSetEDNSOptionResponseAction(DNSDistTest):
         """
         Responses: Set EDNS Option in response replaces existing option
         """
-        name = 'setednsoptionresponse-overwrite.responses.tests.powerdns.com.'
-        initialECO = cookiesoption.CookiesOption(b'aaaaaaaa', b'bbbbbbbb')
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "setednsoptionresponse-overwrite.responses.tests.powerdns.com."
+        initialECO = cookiesoption.CookiesOption(b"aaaaaaaa", b"bbbbbbbb")
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=512, options=[initialECO])
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        replacementECO = cookiesoption.CookiesOption(b'deadbeef', b'deadc0de')
+        replacementECO = cookiesoption.CookiesOption(b"deadbeef", b"deadc0de")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=512, options=[replacementECO])
         expectedResponse.answer.append(rrset)
@@ -636,18 +581,14 @@ class TestAdvancedSetEDNSOptionResponseAction(DNSDistTest):
         """
         Responses: Set EDNS Option in response (DO bit set)
         """
-        name = 'setednsoptionresponse-do.responses.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, want_dnssec=True, payload=4096)
+        name = "setednsoptionresponse-do.responses.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, want_dnssec=True, payload=4096)
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=1024)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadc0de')
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadc0de")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=1024, options=[eco])
         expectedResponse.answer.append(rrset)
index 9723e95af35d3997fbae6fc263cb4cc7ae3112da..89f5ea45b6212d32bacb9ae3ca2dda9eda9488f9 100644 (file)
@@ -5,23 +5,21 @@ import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 from proxyprotocolutils import ProxyProtocolUDPResponder, ProxyProtocolTCPResponder
 
+
 def servFailResponseCallback(request):
     response = dns.message.make_response(request)
     response.set_rcode(dns.rcode.SERVFAIL)
     return response.to_wire()
 
+
 def normalResponseCallback(request):
     response = dns.message.make_response(request)
-    rrset = dns.rrset.from_text(request.question[0].name,
-                                3600,
-                                dns.rdataclass.IN,
-                                dns.rdatatype.A,
-                                '127.0.0.1')
+    rrset = dns.rrset.from_text(request.question[0].name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
     response.answer.append(rrset)
     return response.to_wire()
 
-class TestRestartQuery(DNSDistTest):
 
+class TestRestartQuery(DNSDistTest):
     # this test suite uses different responder ports
     _testNormalServerPort = pickAvailablePort()
     _testServfailServerPort = pickAvailablePort()
@@ -46,7 +44,7 @@ class TestRestartQuery(DNSDistTest):
     addAction(AllRule(), LuaAction(makeQueryRestartable))
     addResponseAction(AllRule(), LuaResponseAction(restartOnServFail))
     """
-    _config_params = ['_testNormalServerPort', '_testServfailServerPort']
+    _config_params = ["_testNormalServerPort", "_testServfailServerPort"]
     _verboseMode = True
 
     @classmethod
@@ -54,16 +52,58 @@ class TestRestartQuery(DNSDistTest):
         print("Launching responders..")
 
         # servfail
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServfailServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, servFailResponseCallback])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[
+                cls._testServfailServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                servFailResponseCallback,
+            ],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServfailServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, servFailResponseCallback])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._testServfailServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                servFailResponseCallback,
+            ],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
-        cls._UDPResponderNormal = threading.Thread(name='UDP ResponderNormal', target=cls.UDPResponder, args=[cls._testNormalServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, normalResponseCallback])
+        cls._UDPResponderNormal = threading.Thread(
+            name="UDP ResponderNormal",
+            target=cls.UDPResponder,
+            args=[
+                cls._testNormalServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                normalResponseCallback,
+            ],
+        )
         cls._UDPResponderNormal.daemon = True
         cls._UDPResponderNormal.start()
-        cls._TCPResponderNormal = threading.Thread(name='TCP ResponderNormal', target=cls.TCPResponder, args=[cls._testNormalServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, normalResponseCallback])
+        cls._TCPResponderNormal = threading.Thread(
+            name="TCP ResponderNormal",
+            target=cls.TCPResponder,
+            args=[
+                cls._testNormalServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                normalResponseCallback,
+            ],
+        )
         cls._TCPResponderNormal.daemon = True
         cls._TCPResponderNormal.start()
 
@@ -71,13 +111,9 @@ class TestRestartQuery(DNSDistTest):
         """
         Restart: ServFail then restarted to a second pool
         """
-        name = 'restart.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        name = "restart.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
 
@@ -92,15 +128,24 @@ toProxyQueue = Queue()
 fromProxyQueue = Queue()
 proxyResponderPort = pickAvailablePort()
 
-udpResponder = threading.Thread(name='UDP Proxy Protocol Responder', target=ProxyProtocolUDPResponder, args=[proxyResponderPort, toProxyQueue, fromProxyQueue])
+udpResponder = threading.Thread(
+    name="UDP Proxy Protocol Responder",
+    target=ProxyProtocolUDPResponder,
+    args=[proxyResponderPort, toProxyQueue, fromProxyQueue],
+)
 udpResponder.daemon = True
 udpResponder.start()
-tcpResponder = threading.Thread(name='TCP Proxy Protocol Responder', target=ProxyProtocolTCPResponder, args=[proxyResponderPort, toProxyQueue, fromProxyQueue])
+tcpResponder = threading.Thread(
+    name="TCP Proxy Protocol Responder",
+    target=ProxyProtocolTCPResponder,
+    args=[proxyResponderPort, toProxyQueue, fromProxyQueue],
+)
 tcpResponder.daemon = True
 tcpResponder.start()
 
+
 class TestRestartProxyProtocolThenNot(DNSDistTest):
-    _restartPool = 'restart-pool'
+    _restartPool = "restart-pool"
     _config_template = """
     fallbackPool = '%s'
     newServer{address="127.0.0.1:%d", useProxyProtocol=true}
@@ -124,14 +169,14 @@ class TestRestartProxyProtocolThenNot(DNSDistTest):
     addResponseAction(AllRule(), LuaResponseAction(restart))
     """
     _proxyResponderPort = proxyResponderPort
-    _config_params = ['_restartPool', '_proxyResponderPort', '_testServerPort']
+    _config_params = ["_restartPool", "_proxyResponderPort", "_testServerPort"]
 
     def testRestart(self):
         """
         Restart: queries is first forwarded to proxy-protocol enabled backend, then restarted to a non-PP backend
         """
-        name = 'proxy.restart.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "proxy.restart.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -153,8 +198,8 @@ class TestRestartProxyProtocolThenNot(DNSDistTest):
             self.assertTrue(receivedProxyPayload)
             self.assertTrue(receivedDNSData)
 
-class QueryCounter:
 
+class QueryCounter:
     def __init__(self, name):
         self.name = name
         self.qcnt = 0
@@ -168,10 +213,11 @@ class QueryCounter:
             response = dns.message.make_response(request)
             response.set_rcode(dns.rcode.REFUSED)
             return response.to_wire()
+
         return callback
 
-class TestRestartCount(DNSDistTest):
 
+class TestRestartCount(DNSDistTest):
     _queryCounts = {}
 
     _testServer1Port = pickAvailablePort()
@@ -179,7 +225,7 @@ class TestRestartCount(DNSDistTest):
     _testServer3Port = pickAvailablePort()
     _testServer4Port = pickAvailablePort()
     _serverPorts = [_testServer1Port, _testServer2Port, _testServer3Port, _testServer4Port]
-    _config_params = ['_testServer1Port', '_testServer2Port', '_testServer3Port', '_testServer4Port']
+    _config_params = ["_testServer1Port", "_testServer2Port", "_testServer3Port", "_testServer4Port"]
     _config_template = """
     MaxRestart = 2
     s0 = newServer{name="s0", address="127.0.0.1:%d"}
@@ -208,22 +254,27 @@ class TestRestartCount(DNSDistTest):
     addResponseAction(RCodeRule(DNSRCode.REFUSED), LuaResponseAction(restartQuery))
     addAction(AllRule(), PoolAction("pool0"))
     """
+
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
 
-        for i, name in enumerate(['s0', 's1', 's2', 's3']):
+        for i, name in enumerate(["s0", "s1", "s2", "s3"]):
             cls._queryCounts[name] = QueryCounter(name)
             cb = cls._queryCounts[name].create_cb()
-            responder = threading.Thread(name=name, target=cls.UDPResponder, args=[cls._serverPorts[i], cls._toResponderQueue, cls._fromResponderQueue, False, cb])
+            responder = threading.Thread(
+                name=name,
+                target=cls.UDPResponder,
+                args=[cls._serverPorts[i], cls._toResponderQueue, cls._fromResponderQueue, False, cb],
+            )
             responder.daemon = True
             responder.start()
 
     def testDefault(self):
 
         numberOfQueries = 100
-        name = 'restart.count.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "restart.count.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -234,7 +285,7 @@ class TestRestartCount(DNSDistTest):
             self.assertEqual(expectedResponse, receivedResponse)
 
         # if restart count is correct, s0/s1/s2 would get all the queies while s3 would get none
-        self.assertEqual(self._queryCounts['s0'](), numberOfQueries)
-        self.assertEqual(self._queryCounts['s1'](), numberOfQueries)
-        self.assertEqual(self._queryCounts['s2'](), numberOfQueries)
-        self.assertEqual(self._queryCounts['s3'](), 0)
+        self.assertEqual(self._queryCounts["s0"](), numberOfQueries)
+        self.assertEqual(self._queryCounts["s1"](), numberOfQueries)
+        self.assertEqual(self._queryCounts["s2"](), numberOfQueries)
+        self.assertEqual(self._queryCounts["s3"](), 0)
index f4458f24bc889ad3395999ab95e89297b94227e6..40747067febe73b996845b2bef1bad0f313f1a07 100644 (file)
@@ -5,8 +5,8 @@ import time
 import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class TestRoutingPoolRouting(DNSDistTest):
 
+class TestRoutingPoolRouting(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d", pool="real"}
     addAction(SuffixMatchNodeRule("poolaction.routing.tests.powerdns.com"), PoolAction("real"))
@@ -26,14 +26,10 @@ class TestRoutingPoolRouting(DNSDistTest):
         Send an A query to "poolaction.routing.tests.powerdns.com.",
         check that dnsdist routes the query to the "real" pool.
         """
-        name = 'poolaction.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "poolaction.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -47,14 +43,10 @@ class TestRoutingPoolRouting(DNSDistTest):
         """
         Routing: Set pool by qname via PoolAction (no stop)
         """
-        name = 'poolaction-nostop.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "poolaction-nostop.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -72,14 +64,15 @@ class TestRoutingPoolRouting(DNSDistTest):
         check that dnsdist sends no response (no servers
         in the default pool).
         """
-        name = 'notpool.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "notpool.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, None)
 
+
 class TestRoutingQPSPoolRouting(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d", pool="regular"}
@@ -95,14 +88,10 @@ class TestRoutingQPSPoolRouting(DNSDistTest):
         when the max QPS has been reached.
         """
         maxQPS = 10
-        name = 'qpspoolaction.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "qpspoolaction.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for _ in range(maxQPS):
@@ -125,10 +114,10 @@ class TestRoutingQPSPoolRouting(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-
         (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
 
+
 class RoundRobinTest(object):
     def doTestRR(self, name):
         """
@@ -138,13 +127,9 @@ class RoundRobinTest(object):
         check that dnsdist routes half of it to each backend.
         """
         numberOfQueries = 10
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         # the round robin counter is shared for UDP and TCP,
@@ -165,10 +150,10 @@ class RoundRobinTest(object):
             value = self._responsesCounter[key]
             self.assertEqual(value, numberOfQueries / 2)
 
-class TestRoutingRoundRobinLB(RoundRobinTest, DNSDistTest):
 
+class TestRoutingRoundRobinLB(RoundRobinTest, DNSDistTest):
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     setServerPolicy(roundrobin)
     s1 = newServer{address="127.0.0.1:%d"}
@@ -180,18 +165,34 @@ class TestRoutingRoundRobinLB(RoundRobinTest, DNSDistTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2 = threading.Thread(
+            name="UDP Responder 2",
+            target=cls.UDPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder2.daemon = True
         cls._UDPResponder2.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2 = threading.Thread(
+            name="TCP Responder 2",
+            target=cls.TCPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder2.daemon = True
         cls._TCPResponder2.start()
 
@@ -202,12 +203,12 @@ class TestRoutingRoundRobinLB(RoundRobinTest, DNSDistTest):
         Send 10 A queries to "rr.routing.tests.powerdns.com.",
         check that dnsdist routes half of it to each backend.
         """
-        self.doTestRR('rr.routing.tests.powerdns.com.')
+        self.doTestRR("rr.routing.tests.powerdns.com.")
 
-class TestRoutingRoundRobinLBViaPool(RoundRobinTest, DNSDistTest):
 
+class TestRoutingRoundRobinLBViaPool(RoundRobinTest, DNSDistTest):
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     s1 = newServer{address="127.0.0.1:%d"}
     s1:setUp()
@@ -219,18 +220,34 @@ class TestRoutingRoundRobinLBViaPool(RoundRobinTest, DNSDistTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2 = threading.Thread(
+            name="UDP Responder 2",
+            target=cls.UDPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder2.daemon = True
         cls._UDPResponder2.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2 = threading.Thread(
+            name="TCP Responder 2",
+            target=cls.TCPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder2.daemon = True
         cls._TCPResponder2.start()
 
@@ -241,12 +258,12 @@ class TestRoutingRoundRobinLBViaPool(RoundRobinTest, DNSDistTest):
         Send 10 A queries to "rr-pool.routing.tests.powerdns.com.",
         check that dnsdist routes half of it to each backend.
         """
-        self.doTestRR('rr-pool.routing.tests.powerdns.com.')
+        self.doTestRR("rr-pool.routing.tests.powerdns.com.")
 
-class TestRoutingRoundRobinLBOneDown(DNSDistTest):
 
+class TestRoutingRoundRobinLBOneDown(DNSDistTest):
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     setServerPolicy(roundrobin)
     s1 = newServer{address="127.0.0.1:%d"}
@@ -263,14 +280,10 @@ class TestRoutingRoundRobinLBOneDown(DNSDistTest):
         check that dnsdist routes all of it to the only backend up.
         """
         numberOfQueries = 10
-        name = 'rr.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "rr.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         # the round robin counter is shared for UDP and TCP,
@@ -295,10 +308,10 @@ class TestRoutingRoundRobinLBOneDown(DNSDistTest):
 
         self.assertEqual(total, numberOfQueries * 2)
 
-class TestRoutingRoundRobinLBAllDown(DNSDistTest):
 
+class TestRoutingRoundRobinLBAllDown(DNSDistTest):
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     setServerPolicy(roundrobin)
     setRoundRobinFailOnNoServer(true)
@@ -312,14 +325,10 @@ class TestRoutingRoundRobinLBAllDown(DNSDistTest):
         """
         Routing: Round Robin with all servers down
         """
-        name = 'alldown.rr.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "alldown.rr.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -327,10 +336,10 @@ class TestRoutingRoundRobinLBAllDown(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, None)
 
-class TestRoutingLuaFFIPerThreadRoundRobinLB(RoundRobinTest, DNSDistTest):
 
+class TestRoutingLuaFFIPerThreadRoundRobinLB(RoundRobinTest, DNSDistTest):
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     -- otherwise we start too many TCP workers, and as each thread
     -- uses it own counter this makes the TCP queries distribution hard to predict
@@ -360,18 +369,34 @@ class TestRoutingLuaFFIPerThreadRoundRobinLB(RoundRobinTest, DNSDistTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2 = threading.Thread(
+            name="UDP Responder 2",
+            target=cls.UDPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder2.daemon = True
         cls._UDPResponder2.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2 = threading.Thread(
+            name="TCP Responder 2",
+            target=cls.TCPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder2.daemon = True
         cls._TCPResponder2.start()
 
@@ -379,12 +404,12 @@ class TestRoutingLuaFFIPerThreadRoundRobinLB(RoundRobinTest, DNSDistTest):
         """
         Routing: Round Robin (LuaFFI)
         """
-        self.doTestRR('rr-luaffi.routing.tests.powerdns.com.')
+        self.doTestRR("rr-luaffi.routing.tests.powerdns.com.")
 
-class TestRoutingCustomLuaRoundRobinLB(RoundRobinTest, DNSDistTest):
 
+class TestRoutingCustomLuaRoundRobinLB(RoundRobinTest, DNSDistTest):
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     -- otherwise we start too many TCP workers, and as each thread
     -- uses it own counter this makes the TCP queries distribution hard to predict
@@ -406,18 +431,34 @@ class TestRoutingCustomLuaRoundRobinLB(RoundRobinTest, DNSDistTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2 = threading.Thread(
+            name="UDP Responder 2",
+            target=cls.UDPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder2.daemon = True
         cls._UDPResponder2.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2 = threading.Thread(
+            name="TCP Responder 2",
+            target=cls.TCPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder2.daemon = True
         cls._TCPResponder2.start()
 
@@ -425,12 +466,12 @@ class TestRoutingCustomLuaRoundRobinLB(RoundRobinTest, DNSDistTest):
         """
         Routing: Round Robin (Lua)
         """
-        self.doTestRR('rr-lua.routing.tests.powerdns.com.')
+        self.doTestRR("rr-lua.routing.tests.powerdns.com.")
 
-class TestRoutingOrder(DNSDistTest):
 
+class TestRoutingOrder(DNSDistTest):
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     setServerPolicy(firstAvailable)
     s1 = newServer{address="127.0.0.1:%d", order=2}
@@ -442,18 +483,34 @@ class TestRoutingOrder(DNSDistTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2 = threading.Thread(
+            name="UDP Responder 2",
+            target=cls.UDPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder2.daemon = True
         cls._UDPResponder2.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2 = threading.Thread(
+            name="TCP Responder 2",
+            target=cls.TCPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder2.daemon = True
         cls._TCPResponder2.start()
 
@@ -466,14 +523,10 @@ class TestRoutingOrder(DNSDistTest):
         because it has the lower order value.
         """
         numberOfQueries = 50
-        name = 'order.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "order.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for _ in range(numberOfQueries):
@@ -484,18 +537,18 @@ class TestRoutingOrder(DNSDistTest):
                 self.assertEqual(query, receivedQuery)
                 self.assertEqual(response, receivedResponse)
 
-        if 'UDP Responder' in self._responsesCounter:
-            self.assertEqual(self._responsesCounter['UDP Responder'], 0)
-        self.assertEqual(self._responsesCounter['UDP Responder 2'], numberOfQueries)
-        if 'TCP Responder' in self._responsesCounter:
-            self.assertEqual(self._responsesCounter['TCP Responder'], 0)
-        self.assertEqual(self._responsesCounter['TCP Responder 2'], numberOfQueries)
+        if "UDP Responder" in self._responsesCounter:
+            self.assertEqual(self._responsesCounter["UDP Responder"], 0)
+        self.assertEqual(self._responsesCounter["UDP Responder 2"], numberOfQueries)
+        if "TCP Responder" in self._responsesCounter:
+            self.assertEqual(self._responsesCounter["TCP Responder"], 0)
+        self.assertEqual(self._responsesCounter["TCP Responder 2"], numberOfQueries)
 
-class TestFirstAvailableQPSPacketCacheHits(DNSDistTest):
 
+class TestFirstAvailableQPSPacketCacheHits(DNSDistTest):
     _verboseMode = True
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     setServerPolicy(firstAvailable)
     s1 = newServer{address="127.0.0.1:%d", order=2}
@@ -509,18 +562,34 @@ class TestFirstAvailableQPSPacketCacheHits(DNSDistTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2 = threading.Thread(
+            name="UDP Responder 2",
+            target=cls.UDPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder2.daemon = True
         cls._UDPResponder2.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2 = threading.Thread(
+            name="TCP Responder 2",
+            target=cls.TCPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder2.daemon = True
         cls._TCPResponder2.start()
 
@@ -534,14 +603,10 @@ class TestFirstAvailableQPSPacketCacheHits(DNSDistTest):
         and the QPS should only be counted for cache misses.
         """
         numberOfQueries = 50
-        name = 'order-qps-cache.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "order-qps-cache.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         # first queries to fill the cache
@@ -565,14 +630,10 @@ class TestFirstAvailableQPSPacketCacheHits(DNSDistTest):
                 self.assertEqual(receivedResponse, response)
 
         numberOfQueries = 10
-        name = 'order-qps-cache-2.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "order-qps-cache-2.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         # first queries to fill the cache
@@ -596,19 +657,19 @@ class TestFirstAvailableQPSPacketCacheHits(DNSDistTest):
                 self.assertEqual(receivedResponse, response)
 
         # 4 queries should made it through, 2 UDP and 2 TCP
-        #for k,v in self._responsesCounter.items():
+        # for k,v in self._responsesCounter.items():
         #    print(k)
         #    print(v)
 
-        if 'UDP Responder' in self._responsesCounter:
-            self.assertEqual(self._responsesCounter['UDP Responder'], 0)
-        self.assertEqual(self._responsesCounter['UDP Responder 2'], 2)
-        if 'TCP Responder' in self._responsesCounter:
-            self.assertEqual(self._responsesCounter['TCP Responder'], 0)
-        self.assertEqual(self._responsesCounter['TCP Responder 2'], 2)
+        if "UDP Responder" in self._responsesCounter:
+            self.assertEqual(self._responsesCounter["UDP Responder"], 0)
+        self.assertEqual(self._responsesCounter["UDP Responder 2"], 2)
+        if "TCP Responder" in self._responsesCounter:
+            self.assertEqual(self._responsesCounter["TCP Responder"], 0)
+        self.assertEqual(self._responsesCounter["TCP Responder 2"], 2)
 
-class TestRoutingNoServer(DNSDistTest):
 
+class TestRoutingNoServer(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d", pool="real"}
     setServFailWhenNoServer(true)
@@ -619,8 +680,8 @@ class TestRoutingNoServer(DNSDistTest):
         Routing: No server should return ServFail
         """
         # without EDNS
-        name = 'noserver.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "noserver.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -630,7 +691,7 @@ class TestRoutingNoServer(DNSDistTest):
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
         # now with EDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096, want_dnssec=False)
         expectedResponse = dns.message.make_response(query, our_payload=1232)
         expectedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -641,10 +702,10 @@ class TestRoutingNoServer(DNSDistTest):
             self.assertFalse(receivedResponse.ednsflags & dns.flags.DO)
             self.assertEqual(receivedResponse.payload, 1232)
 
-class TestRoutingWRandom(DNSDistTest):
 
+class TestRoutingWRandom(DNSDistTest):
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     setServerPolicy(wrandom)
     setWeightedBalancingFactor(1.5)
@@ -659,18 +720,34 @@ class TestRoutingWRandom(DNSDistTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2 = threading.Thread(
+            name="UDP Responder 2",
+            target=cls.UDPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder2.daemon = True
         cls._UDPResponder2.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2 = threading.Thread(
+            name="TCP Responder 2",
+            target=cls.TCPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder2.daemon = True
         cls._TCPResponder2.start()
 
@@ -682,14 +759,10 @@ class TestRoutingWRandom(DNSDistTest):
         check that dnsdist routes less than half to one, more to the other.
         """
         numberOfQueries = 100
-        name = 'wrandom.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "wrandom.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         # the counter is shared for UDP and TCP,
@@ -707,20 +780,19 @@ class TestRoutingWRandom(DNSDistTest):
             self.assertEqual(response, receivedResponse)
 
         # The lower weight downstream should receive less than half the queries
-        self.assertLess(self._responsesCounter['UDP Responder'], numberOfQueries * 0.50)
-        self.assertLess(self._responsesCounter['TCP Responder'], numberOfQueries * 0.50)
+        self.assertLess(self._responsesCounter["UDP Responder"], numberOfQueries * 0.50)
+        self.assertLess(self._responsesCounter["TCP Responder"], numberOfQueries * 0.50)
 
         # The higher weight downstream should receive more than half the queries
-        self.assertGreater(self._responsesCounter['UDP Responder 2'], numberOfQueries * 0.50)
-        self.assertGreater(self._responsesCounter['TCP Responder 2'], numberOfQueries * 0.50)
+        self.assertGreater(self._responsesCounter["UDP Responder 2"], numberOfQueries * 0.50)
+        self.assertGreater(self._responsesCounter["TCP Responder 2"], numberOfQueries * 0.50)
 
 
 class TestRoutingHighValueWRandom(DNSDistTest):
-
     _testServer2Port = pickAvailablePort()
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_testServer2Port']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort", "_testServer2Port"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -734,18 +806,34 @@ class TestRoutingHighValueWRandom(DNSDistTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2 = threading.Thread(
+            name="UDP Responder 2",
+            target=cls.UDPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder2.daemon = True
         cls._UDPResponder2.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2 = threading.Thread(
+            name="TCP Responder 2",
+            target=cls.TCPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder2.daemon = True
         cls._TCPResponder2.start()
 
@@ -758,14 +846,10 @@ class TestRoutingHighValueWRandom(DNSDistTest):
         no-policy.
         """
         numberOfQueries = 100
-        name = 'wrandom-overflow.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "wrandom-overflow.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         # the counter is shared for UDP and TCP,
@@ -788,27 +872,31 @@ class TestRoutingHighValueWRandom(DNSDistTest):
         # Map to a dict with every other element being the value to the previous one
         for i, x in enumerate(stats):
             if not i % 2:
-                stats_dict[x] = stats[i+1]
+                stats_dict[x] = stats[i + 1]
 
         # There should be no queries getting "no-policy" responses
-        self.assertEqual(stats_dict['no-policy'], '0')
+        self.assertEqual(stats_dict["no-policy"], "0")
 
         # Each downstream should receive some queries, but it will be unbalanced
         # because the sum of the weights is higher than INT_MAX.
         # The first downstream will receive more than half the queries
-        self.assertGreater(self._responsesCounter['UDP Responder'], numberOfQueries / 2)
-        self.assertGreater(self._responsesCounter['TCP Responder'], numberOfQueries / 2)
+        self.assertGreater(self._responsesCounter["UDP Responder"], numberOfQueries / 2)
+        self.assertGreater(self._responsesCounter["TCP Responder"], numberOfQueries / 2)
 
         # The second downstream will receive the remainder of the queries, but it might very well be 0
-        if 'UDP Responder 2' in self._responsesCounter:
-            self.assertEqual(self._responsesCounter['UDP Responder 2'], numberOfQueries - self._responsesCounter['UDP Responder'])
-        if 'TCP Responder 2' in self._responsesCounter:
-            self.assertEqual(self._responsesCounter['TCP Responder 2'], numberOfQueries - self._responsesCounter['TCP Responder'])
+        if "UDP Responder 2" in self._responsesCounter:
+            self.assertEqual(
+                self._responsesCounter["UDP Responder 2"], numberOfQueries - self._responsesCounter["UDP Responder"]
+            )
+        if "TCP Responder 2" in self._responsesCounter:
+            self.assertEqual(
+                self._responsesCounter["TCP Responder 2"], numberOfQueries - self._responsesCounter["TCP Responder"]
+            )
 
-class TestRoutingWHashed(DNSDistTest):
 
+class TestRoutingWHashed(DNSDistTest):
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     setServerPolicy(whashed)
     setWeightedBalancingFactor(1.5)
@@ -823,18 +911,34 @@ class TestRoutingWHashed(DNSDistTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2 = threading.Thread(
+            name="UDP Responder 2",
+            target=cls.UDPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder2.daemon = True
         cls._UDPResponder2.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2 = threading.Thread(
+            name="TCP Responder 2",
+            target=cls.TCPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder2.daemon = True
         cls._TCPResponder2.start()
 
@@ -847,19 +951,15 @@ class TestRoutingWHashed(DNSDistTest):
         will not be perfect, especially with so few datapoints, but still).
         """
         numberOfQueries = 100
-        suffix = 'whashed.routing.tests.powerdns.com.'
+        suffix = "whashed.routing.tests.powerdns.com."
 
         # the counter is shared for UDP and TCP,
         # so we need to do UDP then TCP to have a clean count
         for idx in range(numberOfQueries):
-            name = str(idx) + '.udp.' + suffix
-            query = dns.message.make_query(name, 'A', 'IN')
+            name = str(idx) + ".udp." + suffix
+            query = dns.message.make_query(name, "A", "IN")
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(name,
-                                        60,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.A,
-                                        '192.0.2.1')
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
             response.answer.append(rrset)
             (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
             receivedQuery.id = query.id
@@ -867,29 +967,25 @@ class TestRoutingWHashed(DNSDistTest):
             self.assertEqual(response, receivedResponse)
 
         for idx in range(numberOfQueries):
-            name = str(idx) + '.tcp.' + suffix
-            query = dns.message.make_query(name, 'A', 'IN')
+            name = str(idx) + ".tcp." + suffix
+            query = dns.message.make_query(name, "A", "IN")
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(name,
-                                        60,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.A,
-                                        '192.0.2.1')
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
             response.answer.append(rrset)
             (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
             receivedQuery.id = query.id
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-        self.assertGreater(self._responsesCounter['UDP Responder'], numberOfQueries * 0.25)
-        self.assertGreater(self._responsesCounter['TCP Responder'], numberOfQueries * 0.25)
-        self.assertGreater(self._responsesCounter['UDP Responder 2'], numberOfQueries * 0.25)
-        self.assertGreater(self._responsesCounter['TCP Responder 2'], numberOfQueries * 0.25)
+        self.assertGreater(self._responsesCounter["UDP Responder"], numberOfQueries * 0.25)
+        self.assertGreater(self._responsesCounter["TCP Responder"], numberOfQueries * 0.25)
+        self.assertGreater(self._responsesCounter["UDP Responder 2"], numberOfQueries * 0.25)
+        self.assertGreater(self._responsesCounter["TCP Responder 2"], numberOfQueries * 0.25)
 
-class TestRoutingCHashed(DNSDistTest):
 
+class TestRoutingCHashed(DNSDistTest):
     _testServer2Port = pickAvailablePort()
-    _config_params = ['_testServerPort', '_testServer2Port']
+    _config_params = ["_testServerPort", "_testServer2Port"]
     _config_template = """
     setServerPolicy(chashed)
     setConsistentHashingBalancingFactor(1.5)
@@ -904,18 +1000,34 @@ class TestRoutingCHashed(DNSDistTest):
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder2 = threading.Thread(
+            name="UDP Responder 2",
+            target=cls.UDPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder2.daemon = True
         cls._UDPResponder2.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._TCPResponder2 = threading.Thread(
+            name="TCP Responder 2",
+            target=cls.TCPResponder,
+            args=[cls._testServer2Port, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._TCPResponder2.daemon = True
         cls._TCPResponder2.start()
 
@@ -928,19 +1040,15 @@ class TestRoutingCHashed(DNSDistTest):
         will not be perfect, especially with so few datapoints, but still).
         """
         numberOfQueries = 100
-        suffix = 'chashed.routing.tests.powerdns.com.'
+        suffix = "chashed.routing.tests.powerdns.com."
 
         # the counter is shared for UDP and TCP,
         # so we need to do UDP then TCP to have a clean count
         for idx in range(numberOfQueries):
-            name = str(idx) + '.udp.' + suffix
-            query = dns.message.make_query(name, 'A', 'IN')
+            name = str(idx) + ".udp." + suffix
+            query = dns.message.make_query(name, "A", "IN")
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(name,
-                                        60,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.A,
-                                        '192.0.2.1')
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
             response.answer.append(rrset)
             (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
             receivedQuery.id = query.id
@@ -948,27 +1056,23 @@ class TestRoutingCHashed(DNSDistTest):
             self.assertEqual(response, receivedResponse)
 
         for idx in range(numberOfQueries):
-            name = str(idx) + '.tcp.' + suffix
-            query = dns.message.make_query(name, 'A', 'IN')
+            name = str(idx) + ".tcp." + suffix
+            query = dns.message.make_query(name, "A", "IN")
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(name,
-                                        60,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.A,
-                                        '192.0.2.1')
+            rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
             response.answer.append(rrset)
             (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
             receivedQuery.id = query.id
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-        self.assertGreater(self._responsesCounter['UDP Responder'], numberOfQueries * 0.25)
-        self.assertGreater(self._responsesCounter['TCP Responder'], numberOfQueries * 0.25)
-        self.assertGreater(self._responsesCounter['UDP Responder 2'], numberOfQueries * 0.25)
-        self.assertGreater(self._responsesCounter['TCP Responder 2'], numberOfQueries * 0.25)
+        self.assertGreater(self._responsesCounter["UDP Responder"], numberOfQueries * 0.25)
+        self.assertGreater(self._responsesCounter["TCP Responder"], numberOfQueries * 0.25)
+        self.assertGreater(self._responsesCounter["UDP Responder 2"], numberOfQueries * 0.25)
+        self.assertGreater(self._responsesCounter["TCP Responder 2"], numberOfQueries * 0.25)
 
-class TestRoutingLuaFFILBNoServer(DNSDistTest):
 
+class TestRoutingLuaFFILBNoServer(DNSDistTest):
     _config_template = """
     -- we want a ServFail answer when all servers are down
     setServFailWhenNoServer(true)
@@ -991,8 +1095,8 @@ class TestRoutingLuaFFILBNoServer(DNSDistTest):
         """
         Routing: LuaFFI policy, all servers are down
         """
-        name = 'lua-ffi-no-servers.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "lua-ffi-no-servers.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -1003,7 +1107,6 @@ class TestRoutingLuaFFILBNoServer(DNSDistTest):
 
 
 class QueryCounter:
-
     def __init__(self, name):
         self.name = name
         self.refuse = False
@@ -1022,27 +1125,31 @@ class QueryCounter:
         def callback(request):
             self.qcnt += 1
             response = dns.message.make_response(request)
-            rrset = dns.rrset.from_text(request.question[0].name,
-                                3600,
-                                dns.rdataclass.IN,
-                                dns.rdatatype.A,
-                                '127.0.0.1')
+            rrset = dns.rrset.from_text(request.question[0].name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
             response.set_rcode(dns.rcode.REFUSED) if self.refuse else response.answer.append(rrset)
             return response.to_wire()
+
         return callback
 
-class TestRoutingOrderedWRandUntag(DNSDistTest):
 
+class TestRoutingOrderedWRandUntag(DNSDistTest):
     _queryCounts = {}
 
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _testServer1Port = pickAvailablePort()
     _testServer2Port = pickAvailablePort()
     _testServer3Port = pickAvailablePort()
     _testServer4Port = pickAvailablePort()
     _serverPorts = [_testServer1Port, _testServer2Port, _testServer3Port, _testServer4Port]
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServer1Port', '_testServer2Port', '_testServer3Port', '_testServer4Port']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServer1Port",
+        "_testServer2Port",
+        "_testServer3Port",
+        "_testServer4Port",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -1076,10 +1183,14 @@ class TestRoutingOrderedWRandUntag(DNSDistTest):
     def startResponders(cls):
         print("Launching responders..")
 
-        for i, name in enumerate(['s11', 's12', 's21', 's22']):
+        for i, name in enumerate(["s11", "s12", "s21", "s22"]):
             cls._queryCounts[name] = QueryCounter(name)
             cb = cls._queryCounts[name].create_cb()
-            responder = threading.Thread(name=name, target=cls.UDPResponder, args=[cls._serverPorts[i], cls._toResponderQueue, cls._fromResponderQueue, False, cb])
+            responder = threading.Thread(
+                name=name,
+                target=cls.UDPResponder,
+                args=[cls._serverPorts[i], cls._toResponderQueue, cls._fromResponderQueue, False, cb],
+            )
             responder.daemon = True
             responder.start()
 
@@ -1097,14 +1208,10 @@ class TestRoutingOrderedWRandUntag(DNSDistTest):
         check that dnsdist routes based on order first then weighted.
         """
         numberOfQueries = 100
-        name = 'ordered.wrand.routing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "ordered.wrand.routing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         ### test normal first ordered then random weighted routing ###
@@ -1116,19 +1223,19 @@ class TestRoutingOrderedWRandUntag(DNSDistTest):
             self.assertEqual(expectedResponse, receivedResponse)
 
         # Only order 1 servers get queries and weighted
-        self.assertGreater(self._queryCounts['s12'](),  numberOfQueries * 0.50)
-        self.assertLess(self._queryCounts['s11'](),  numberOfQueries * 0.50)
-        self.assertEqual(self._queryCounts['s21'](),  0)
-        self.assertEqual(self._queryCounts['s22'](),  0)
+        self.assertGreater(self._queryCounts["s12"](), numberOfQueries * 0.50)
+        self.assertLess(self._queryCounts["s11"](), numberOfQueries * 0.50)
+        self.assertEqual(self._queryCounts["s21"](), 0)
+        self.assertEqual(self._queryCounts["s22"](), 0)
 
         ### test tagged servers for restart
 
         # reset counters
-        for name in ['s11', 's12', 's21', 's22']:
+        for name in ["s11", "s12", "s21", "s22"]:
             self._queryCounts[name].reset()
 
-        self._queryCounts['s11'].set_refuse(True)
-        self.setServerDown('s12')
+        self._queryCounts["s11"].set_refuse(True)
+        self.setServerDown("s12")
 
         # send 100 queries
         for _ in range(numberOfQueries):
@@ -1139,20 +1246,20 @@ class TestRoutingOrderedWRandUntag(DNSDistTest):
         # s11 receives all 100 initial queries and always refuse to trigger restart
         # s12 is not selected for both initial and restarted queries
         # s21+s22 shall receive all the 100 restarted queries
-        self.assertEqual(self._queryCounts['s11'](),  numberOfQueries)
-        self.assertEqual(self._queryCounts['s12'](),  0)
-        self.assertEqual(self._queryCounts['s21']()+self._queryCounts['s22'](), numberOfQueries)
+        self.assertEqual(self._queryCounts["s11"](), numberOfQueries)
+        self.assertEqual(self._queryCounts["s12"](), 0)
+        self.assertEqual(self._queryCounts["s21"]() + self._queryCounts["s22"](), numberOfQueries)
 
-        self._queryCounts['s11'].set_refuse(False)
-        self.setServerUp('s12')
+        self._queryCounts["s11"].set_refuse(False)
+        self.setServerUp("s12")
 
         ### further test server down conditions ###
 
         # reset counters
-        for name in ['s11', 's12', 's21', 's22']:
+        for name in ["s11", "s12", "s21", "s22"]:
             self._queryCounts[name].reset()
 
-        self.setServerDown('s11')
+        self.setServerDown("s11")
 
         # send 100 queries
         for _ in range(numberOfQueries):
@@ -1161,16 +1268,16 @@ class TestRoutingOrderedWRandUntag(DNSDistTest):
             self.assertEqual(expectedResponse, receivedResponse)
 
         # queries shall arrive 's12' only
-        self.assertEqual(self._queryCounts['s11'](),  0)
-        self.assertEqual(self._queryCounts['s12'](),  numberOfQueries)
-        self.assertEqual(self._queryCounts['s21'](),  0)
-        self.assertEqual(self._queryCounts['s22'](),  0)
+        self.assertEqual(self._queryCounts["s11"](), 0)
+        self.assertEqual(self._queryCounts["s12"](), numberOfQueries)
+        self.assertEqual(self._queryCounts["s21"](), 0)
+        self.assertEqual(self._queryCounts["s22"](), 0)
 
         # reset counters
-        for name in ['s11', 's12', 's21', 's22']:
+        for name in ["s11", "s12", "s21", "s22"]:
             self._queryCounts[name].reset()
 
-        self.setServerDown('s12')
+        self.setServerDown("s12")
 
         # send 100 queries
         for _ in range(numberOfQueries):
@@ -1179,7 +1286,7 @@ class TestRoutingOrderedWRandUntag(DNSDistTest):
             self.assertEqual(expectedResponse, receivedResponse)
 
         # queries now shall be sent to order 2 servers and weighted
-        self.assertEqual(self._queryCounts['s11'](),  0)
-        self.assertEqual(self._queryCounts['s12'](),  0)
-        self.assertLess(self._queryCounts['s21'](),  numberOfQueries * 0.50)
-        self.assertGreater(self._queryCounts['s22'](),  numberOfQueries * 0.50)
+        self.assertEqual(self._queryCounts["s11"](), 0)
+        self.assertEqual(self._queryCounts["s12"](), 0)
+        self.assertLess(self._queryCounts["s21"](), numberOfQueries * 0.50)
+        self.assertGreater(self._queryCounts["s22"](), numberOfQueries * 0.50)
index 1fd48b21b4f732c21280e6bf312bce11d8eb5532..011ed671b4dfbcacddaf2c957f022b65e5e040fe 100644 (file)
@@ -10,8 +10,8 @@ import clientsubnetoption
 import cookiesoption
 from dnsdisttests import DNSDistTest
 
-class TestAdvancedAllow(DNSDistTest):
 
+class TestAdvancedAllow(DNSDistTest):
     _config_template = """
     addAction(AllRule(), NoneAction())
     addAction(QNameSuffixRule("allowed.advanced.tests.powerdns.com."), AllowAction())
@@ -26,14 +26,10 @@ class TestAdvancedAllow(DNSDistTest):
         A query for allowed.advanced.tests.powerdns.com. should be allowed
         while others should be dropped.
         """
-        name = 'allowed.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "allowed.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -51,16 +47,16 @@ class TestAdvancedAllow(DNSDistTest):
 
         A query for notallowed.advanced.tests.powerdns.com. should be dropped.
         """
-        name = 'notallowed.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "notallowed.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, None)
 
-class TestAdvancedRemoveRD(DNSDistTest):
 
+class TestAdvancedRemoveRD(DNSDistTest):
     _config_template = """
     addAction("norecurse.advanced.tests.powerdns.com.", SetNoRecurseAction())
     newServer{address="127.0.0.1:%d"}
@@ -73,17 +69,13 @@ class TestAdvancedRemoveRD(DNSDistTest):
         Send a query with RD,
         check that dnsdist clears the RD flag.
         """
-        name = 'norecurse.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        name = "norecurse.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN")
         expectedQuery.flags &= ~dns.flags.RD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -102,15 +94,11 @@ class TestAdvancedRemoveRD(DNSDistTest):
         Send a query with RD for a canary domain,
         check that dnsdist does not clear the RD flag.
         """
-        name = 'keeprecurse.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "keeprecurse.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -122,8 +110,8 @@ class TestAdvancedRemoveRD(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-class TestAdvancedAddCD(DNSDistTest):
 
+class TestAdvancedAddCD(DNSDistTest):
     _config_template = """
     addAction("setcd.advanced.tests.powerdns.com.", SetDisableValidationAction())
     newServer{address="127.0.0.1:%d"}
@@ -136,17 +124,13 @@ class TestAdvancedAddCD(DNSDistTest):
         Send a query with CD cleared,
         check that dnsdist set the CD flag.
         """
-        name = 'setcd.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        name = "setcd.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN")
         expectedQuery.flags |= dns.flags.CD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -165,15 +149,11 @@ class TestAdvancedAddCD(DNSDistTest):
         Send a query without CD for a canary domain,
         check that dnsdist does not set the CD flag.
         """
-        name = 'keepnocd.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "keepnocd.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -185,8 +165,8 @@ class TestAdvancedAddCD(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-class TestAdvancedClearRD(DNSDistTest):
 
+class TestAdvancedClearRD(DNSDistTest):
     _config_template = """
     addAction("clearrd.advanced.tests.powerdns.com.", SetNoRecurseAction())
     newServer{address="127.0.0.1:%d"}
@@ -199,17 +179,13 @@ class TestAdvancedClearRD(DNSDistTest):
         Send a query with RD set,
         check that dnsdist clears the RD flag.
         """
-        name = 'clearrd.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        name = "clearrd.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN")
         expectedQuery.flags &= ~dns.flags.RD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -228,15 +204,11 @@ class TestAdvancedClearRD(DNSDistTest):
         Send a query with RD for a canary domain,
         check that dnsdist does not clear the RD flag.
         """
-        name = 'keeprd.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "keeprd.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -250,7 +222,6 @@ class TestAdvancedClearRD(DNSDistTest):
 
 
 class TestAdvancedDelay(DNSDistTest):
-
     _config_template = """
     addAction(AllRule(), DelayAction(1000))
     newServer{address="127.0.0.1:%d"}
@@ -264,14 +235,10 @@ class TestAdvancedDelay(DNSDistTest):
         check that the response delay is longer than 1000 ms
         over UDP, less than that over TCP.
         """
-        name = 'tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         begin = datetime.now()
@@ -290,12 +257,13 @@ class TestAdvancedDelay(DNSDistTest):
         self.assertEqual(response, receivedResponse)
         self.assertLess(end - begin, timedelta(0, 1))
 
-class TestAdvancedAndNot(DNSDistTest):
 
+class TestAdvancedAndNot(DNSDistTest):
     _config_template = """
     addAction(AndRule({NotRule(QTypeRule("A")), TCPRule(false)}), RCodeAction(DNSRCode.NOTIMP))
     newServer{address="127.0.0.1:%d"}
     """
+
     def testAOverUDPReturnsNotImplementedCanary(self):
         """
         Advanced: !A && UDP canary
@@ -305,14 +273,10 @@ class TestAdvancedAndNot(DNSDistTest):
         We send an A query over UDP and TCP, and check that the
         response is OK.
         """
-        name = 'andnot.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "andnot.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -333,8 +297,8 @@ class TestAdvancedAndNot(DNSDistTest):
         We send a TXT query over UDP and TCP, and check that the
         response is OK for TCP and 'not implemented' for UDP.
         """
-        name = 'andnot.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        name = "andnot.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "TXT", "IN")
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
 
@@ -345,11 +309,7 @@ class TestAdvancedAndNot(DNSDistTest):
         self.assertEqual(receivedResponse, expectedResponse)
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    'nothing to see here')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, "nothing to see here")
         response.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
@@ -359,12 +319,13 @@ class TestAdvancedAndNot(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-class TestAdvancedOr(DNSDistTest):
 
+class TestAdvancedOr(DNSDistTest):
     _config_template = """
     addAction(OrRule({QTypeRule("A"), TCPRule(false)}), RCodeAction(DNSRCode.NOTIMP))
     newServer{address="127.0.0.1:%d"}
     """
+
     def testAAAAOverUDPReturnsNotImplemented(self):
         """
         Advanced: A || UDP: AAAA
@@ -374,15 +335,11 @@ class TestAdvancedOr(DNSDistTest):
         We send an AAAA query over UDP and TCP, and check that the
         response is 'not implemented' for UDP and OK for TCP.
         """
-        name = 'aorudp.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "aorudp.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         expectedResponse = dns.message.make_response(query)
@@ -407,8 +364,8 @@ class TestAdvancedOr(DNSDistTest):
         We send an A query over UDP and TCP, and check that the
         response is 'not implemented' for both.
         """
-        name = 'aorudp.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "aorudp.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
 
         expectedResponse = dns.message.make_response(query)
@@ -421,25 +378,21 @@ class TestAdvancedOr(DNSDistTest):
 
 
 class TestAdvancedLogAction(DNSDistTest):
-
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addAction(AllRule(), LogAction("dnsdist.log", false))
     """
+
     def testAdvancedLogAction(self):
         """
         Advanced: Log all queries
 
         """
         count = 50
-        name = 'logaction.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "logaction.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for _ in range(count):
@@ -450,29 +403,26 @@ class TestAdvancedLogAction(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-        self.assertTrue(os.path.isfile('dnsdist.log'))
-        self.assertGreater(os.stat('dnsdist.log').st_size, 0)
+        self.assertTrue(os.path.isfile("dnsdist.log"))
+        self.assertGreater(os.stat("dnsdist.log").st_size, 0)
 
-class TestAdvancedDNSSEC(DNSDistTest):
 
+class TestAdvancedDNSSEC(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addAction(DNSSECRule(), DropAction())
     """
+
     def testAdvancedDNSSECDrop(self):
         """
         Advanced: DNSSEC Rule
 
         """
-        name = 'dnssec.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        doquery = dns.message.make_query(name, 'A', 'IN', want_dnssec=True)
+        name = "dnssec.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        doquery = dns.message.make_query(name, "A", "IN", want_dnssec=True)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -489,19 +439,20 @@ class TestAdvancedDNSSEC(DNSDistTest):
             (_, receivedResponse) = sender(doquery, response=None, useQueue=False)
             self.assertEqual(receivedResponse, None)
 
-class TestAdvancedQClass(DNSDistTest):
 
+class TestAdvancedQClass(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addAction(QClassRule(DNSClass.CHAOS), DropAction())
     """
+
     def testAdvancedQClassChaosDrop(self):
         """
         Advanced: Drop QClass CHAOS
 
         """
-        name = 'qclasschaos.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'TXT', 'CHAOS')
+        name = "qclasschaos.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "TXT", "CHAOS")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -513,14 +464,10 @@ class TestAdvancedQClass(DNSDistTest):
         Advanced: Allow QClass IN
 
         """
-        name = 'qclassin.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "qclassin.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -532,19 +479,20 @@ class TestAdvancedQClass(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-class TestAdvancedOpcode(DNSDistTest):
 
+class TestAdvancedOpcode(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addAction(OpcodeRule(DNSOpcode.Notify), DropAction())
     """
+
     def testAdvancedOpcodeNotifyDrop(self):
         """
         Advanced: Drop Opcode NOTIFY
 
         """
-        name = 'opcodenotify.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "opcodenotify.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.set_opcode(dns.opcode.NOTIFY)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -557,15 +505,11 @@ class TestAdvancedOpcode(DNSDistTest):
         Advanced: Allow Opcode UPDATE
 
         """
-        name = 'opcodeupdate.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'SOA', 'IN')
+        name = "opcodeupdate.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "SOA", "IN")
         query.set_opcode(dns.opcode.UPDATE)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -577,14 +521,15 @@ class TestAdvancedOpcode(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-class TestAdvancedNonTerminalRule(DNSDistTest):
 
+class TestAdvancedNonTerminalRule(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d", pool="real"}
     addAction(AllRule(), SetDisableValidationAction())
     addAction(AllRule(), PoolAction("real"))
     addAction(AllRule(), DropAction())
     """
+
     def testAdvancedNonTerminalRules(self):
         """
         Advanced: Non terminal rules
@@ -593,16 +538,12 @@ class TestAdvancedNonTerminalRule(DNSDistTest):
         but does not stop the processing, then that
         PoolAction() is applied _and_ stop the processing.
         """
-        name = 'nonterminal.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        name = "nonterminal.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN")
         expectedQuery.flags |= dns.flags.CD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -614,8 +555,8 @@ class TestAdvancedNonTerminalRule(DNSDistTest):
             self.assertEqual(expectedQuery, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-class TestAdvancedRestoreFlagsOnSelfResponse(DNSDistTest):
 
+class TestAdvancedRestoreFlagsOnSelfResponse(DNSDistTest):
     _config_template = """
     addAction(AllRule(), SetDisableValidationAction())
     addAction(AllRule(), SpoofAction("192.0.2.1"))
@@ -630,17 +571,13 @@ class TestAdvancedRestoreFlagsOnSelfResponse(DNSDistTest):
         instructed to set it, then to spoof the response,
         check that response has the flag cleared.
         """
-        name = 'spoofed.restoreflags.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "spoofed.restoreflags.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -649,8 +586,8 @@ class TestAdvancedRestoreFlagsOnSelfResponse(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(response, receivedResponse)
 
-class TestAdvancedQPS(DNSDistTest):
 
+class TestAdvancedQPS(DNSDistTest):
     _config_template = """
     addAction("qps.advanced.tests.powerdns.com", QPSAction(10))
     newServer{address="127.0.0.1:%d"}
@@ -664,14 +601,10 @@ class TestAdvancedQPS(DNSDistTest):
         check that dnsdist drops queries when the max QPS has been reached.
         """
         maxQPS = 10
-        name = 'qps.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "qps.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for _ in range(maxQPS):
@@ -693,12 +626,11 @@ class TestAdvancedQPS(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-
         (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
 
-class TestAdvancedQPSNone(DNSDistTest):
 
+class TestAdvancedQPSNone(DNSDistTest):
     _config_template = """
     addAction("qpsnone.advanced.tests.powerdns.com", QPSAction(100))
     addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
@@ -713,8 +645,8 @@ class TestAdvancedQPSNone(DNSDistTest):
         check that the rule returns None when the QPS has not been
         reached, not Allow.
         """
-        name = 'qpsnone.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "qpsnone.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -724,8 +656,8 @@ class TestAdvancedQPSNone(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestAdvancedNMGRule(DNSDistTest):
 
+class TestAdvancedNMGRule(DNSDistTest):
     _config_template = """
     allowed = newNMG()
     allowed:addMask("192.0.2.1/32")
@@ -740,8 +672,8 @@ class TestAdvancedNMGRule(DNSDistTest):
         Send queries to "nmgrule.advanced.tests.powerdns.com.",
         check that we are getting a REFUSED response.
         """
-        name = 'nmgrule.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nmgrule.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -751,6 +683,7 @@ class TestAdvancedNMGRule(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
+
 class TestAdvancedNMGAddNMG(DNSDistTest):
     _config_template = """
     oneNMG = newNMG()
@@ -766,24 +699,20 @@ class TestAdvancedNMGAddNMG(DNSDistTest):
         """
         Advanced: NMGRule:addNMG()
         """
-        name = 'nmgrule-addnmg.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nmgrule-addnmg.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
-            (_,receivedResponse) = sender(query, response=expectedResponse, useQueue=False)
+            (_, receivedResponse) = sender(query, response=expectedResponse, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestAdvancedNMGRuleFromString(DNSDistTest):
 
+class TestAdvancedNMGRuleFromString(DNSDistTest):
     _config_template = """
     addAction(NotRule(NetmaskGroupRule('192.0.2.1')), RCodeAction(DNSRCode.REFUSED))
     newServer{address="127.0.0.1:%d"}
@@ -793,8 +722,8 @@ class TestAdvancedNMGRuleFromString(DNSDistTest):
         """
         Advanced: NMGRule (from string) should refuse our queries
         """
-        name = 'nmgrule-from-string.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nmgrule-from-string.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -804,8 +733,8 @@ class TestAdvancedNMGRuleFromString(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestAdvancedNMGRuleFromMultipleStrings(DNSDistTest):
 
+class TestAdvancedNMGRuleFromMultipleStrings(DNSDistTest):
     _config_template = """
     addAction(NotRule(NetmaskGroupRule({'192.0.2.1', '192.0.2.128/25'})), RCodeAction(DNSRCode.REFUSED))
     newServer{address="127.0.0.1:%d"}
@@ -815,8 +744,8 @@ class TestAdvancedNMGRuleFromMultipleStrings(DNSDistTest):
         """
         Advanced: NMGRule (from multiple strings) should refuse our queries
         """
-        name = 'nmgrule-from-multiple-strings.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nmgrule-from-multiple-strings.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -826,9 +755,9 @@ class TestAdvancedNMGRuleFromMultipleStrings(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestDSTPortRule(DNSDistTest):
 
-    _config_params = ['_dnsDistPort', '_testServerPort']
+class TestDSTPortRule(DNSDistTest):
+    _config_params = ["_dnsDistPort", "_testServerPort"]
     _config_template = """
     addAction(DSTPortRule(%d), RCodeAction(DNSRCode.REFUSED))
     newServer{address="127.0.0.1:%d"}
@@ -842,8 +771,8 @@ class TestDSTPortRule(DNSDistTest):
         check that we are getting a REFUSED response.
         """
 
-        name = 'dstportrule.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "dstportrule.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -853,8 +782,8 @@ class TestDSTPortRule(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestAdvancedLabelsCountRule(DNSDistTest):
 
+class TestAdvancedLabelsCountRule(DNSDistTest):
     _config_template = """
     addAction(QNameLabelsCountRule(5,6), RCodeAction(DNSRCode.REFUSED))
     newServer{address="127.0.0.1:%d"}
@@ -865,14 +794,10 @@ class TestAdvancedLabelsCountRule(DNSDistTest):
         Advanced: QNameLabelsCountRule(5,6)
         """
         # 6 labels, we should be fine
-        name = 'ok.labelscount.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "ok.labelscount.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -885,8 +810,8 @@ class TestAdvancedLabelsCountRule(DNSDistTest):
             self.assertEqual(response, receivedResponse)
 
         # more than 6 labels, the query should be refused
-        name = 'not.ok.labelscount.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "not.ok.labelscount.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -897,8 +822,8 @@ class TestAdvancedLabelsCountRule(DNSDistTest):
             self.assertEqual(receivedResponse, expectedResponse)
 
         # less than 5 labels, the query should be refused
-        name = 'labelscountadvanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "labelscountadvanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -908,8 +833,8 @@ class TestAdvancedLabelsCountRule(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestAdvancedWireLengthRule(DNSDistTest):
 
+class TestAdvancedWireLengthRule(DNSDistTest):
     _config_template = """
     addAction(QNameWireLengthRule(54,56), RCodeAction(DNSRCode.REFUSED))
     newServer{address="127.0.0.1:%d"}
@@ -919,14 +844,10 @@ class TestAdvancedWireLengthRule(DNSDistTest):
         """
         Advanced: QNameWireLengthRule(54,56)
         """
-        name = 'longenough.qnamewirelength.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "longenough.qnamewirelength.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -939,8 +860,8 @@ class TestAdvancedWireLengthRule(DNSDistTest):
             self.assertEqual(response, receivedResponse)
 
         # too short, the query should be refused
-        name = 'short.qnamewirelength.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "short.qnamewirelength.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -951,8 +872,8 @@ class TestAdvancedWireLengthRule(DNSDistTest):
             self.assertEqual(receivedResponse, expectedResponse)
 
         # too long, the query should be refused
-        name = 'toolongtobevalid.qnamewirelength.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "toolongtobevalid.qnamewirelength.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -962,8 +883,8 @@ class TestAdvancedWireLengthRule(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestAdvancedLuaDO(DNSDistTest):
 
+class TestAdvancedLuaDO(DNSDistTest):
     _config_template = """
     function nxDOLua(dq)
         if dq:getDO() then
@@ -979,16 +900,12 @@ class TestAdvancedLuaDO(DNSDistTest):
         """
         Advanced: Nx DO queries via Lua
         """
-        name = 'nxdo.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nxdo.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
-        queryWithDO = dns.message.make_query(name, 'A', 'IN', want_dnssec=True)
+        queryWithDO = dns.message.make_query(name, "A", "IN", want_dnssec=True)
         doResponse = dns.message.make_response(queryWithDO)
         doResponse.set_rcode(dns.rcode.NXDOMAIN)
 
@@ -1010,8 +927,8 @@ class TestAdvancedLuaDO(DNSDistTest):
             doResponse.id = receivedResponse.id
             self.assertEqual(receivedResponse, doResponse)
 
-class TestAdvancedLuaRefused(DNSDistTest):
 
+class TestAdvancedLuaRefused(DNSDistTest):
     _config_template = """
     function refuse(dq)
         return DNSAction.Refused, ""
@@ -1024,14 +941,10 @@ class TestAdvancedLuaRefused(DNSDistTest):
         """
         Advanced: Refused via Lua
         """
-        name = 'refused.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "refused.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
         refusedResponse = dns.message.make_response(query)
         refusedResponse.set_rcode(dns.rcode.REFUSED)
@@ -1043,8 +956,8 @@ class TestAdvancedLuaRefused(DNSDistTest):
             refusedResponse.id = receivedResponse.id
             self.assertEqual(receivedResponse, refusedResponse)
 
-class TestAdvancedLuaActionReturnSyntax(DNSDistTest):
 
+class TestAdvancedLuaActionReturnSyntax(DNSDistTest):
     _config_template = """
     function refuse(dq)
         return DNSAction.Refused
@@ -1057,14 +970,10 @@ class TestAdvancedLuaActionReturnSyntax(DNSDistTest):
         """
         Advanced: Short syntax for LuaAction return values
         """
-        name = 'short.refused.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "short.refused.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
         refusedResponse = dns.message.make_response(query)
         refusedResponse.set_rcode(dns.rcode.REFUSED)
@@ -1076,8 +985,8 @@ class TestAdvancedLuaActionReturnSyntax(DNSDistTest):
             refusedResponse.id = receivedResponse.id
             self.assertEqual(receivedResponse, refusedResponse)
 
-class TestAdvancedLuaTruncated(DNSDistTest):
 
+class TestAdvancedLuaTruncated(DNSDistTest):
     _config_template = """
     function trunc(dq)
         if not dq.tcp then
@@ -1093,16 +1002,12 @@ class TestAdvancedLuaTruncated(DNSDistTest):
         """
         Advanced: TC via Lua
         """
-        name = 'tc.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tc.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         truncatedResponse = dns.message.make_response(query)
@@ -1121,8 +1026,8 @@ class TestAdvancedLuaTruncated(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, response)
 
-class TestAdvancedRD(DNSDistTest):
 
+class TestAdvancedRD(DNSDistTest):
     _config_template = """
     addAction(RDRule(), RCodeAction(DNSRCode.REFUSED))
     newServer{address="127.0.0.1:%d"}
@@ -1132,8 +1037,8 @@ class TestAdvancedRD(DNSDistTest):
         """
         Advanced: RD query is refused
         """
-        name = 'rd.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "rd.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
         expectedResponse.flags |= dns.flags.RA
@@ -1147,8 +1052,8 @@ class TestAdvancedRD(DNSDistTest):
         """
         Advanced: No-RD query is allowed
         """
-        name = 'no-rd.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "no-rd.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
 
@@ -1159,8 +1064,8 @@ class TestAdvancedRD(DNSDistTest):
             self.assertEqual(receivedQuery, query)
             self.assertEqual(receivedResponse, response)
 
-class TestAdvancedLuaTempFailureTTL(DNSDistTest):
 
+class TestAdvancedLuaTempFailureTTL(DNSDistTest):
     _config_template = """
     function testAction(dq)
       if dq.tempFailureTTL ~= nil then
@@ -1184,14 +1089,10 @@ class TestAdvancedLuaTempFailureTTL(DNSDistTest):
         """
         Advanced: Exercise dq.tempFailureTTL Lua binding
         """
-        name = 'tempfailurettlbinding.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tempfailurettlbinding.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1203,8 +1104,8 @@ class TestAdvancedLuaTempFailureTTL(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(receivedResponse, response)
 
-class TestAdvancedEDNSOptionRule(DNSDistTest):
 
+class TestAdvancedEDNSOptionRule(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addAction(EDNSOptionRule(EDNSOptionCode.ECS), DropAction())
@@ -1215,10 +1116,10 @@ class TestAdvancedEDNSOptionRule(DNSDistTest):
         Advanced: A question with ECS is dropped
         """
 
-        name = 'ednsoptionrule.advanced.tests.powerdns.com.'
+        name = "ednsoptionrule.advanced.tests.powerdns.com."
 
-        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -1230,10 +1131,10 @@ class TestAdvancedEDNSOptionRule(DNSDistTest):
         Advanced: A question without ECS is answered
         """
 
-        name = 'ednsoptionrule.advanced.tests.powerdns.com.'
+        name = "ednsoptionrule.advanced.tests.powerdns.com."
 
         # both with EDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[], payload=512)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, options=[], payload=512)
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1247,7 +1148,7 @@ class TestAdvancedEDNSOptionRule(DNSDistTest):
             self.assertEqual(receivedResponse, response)
 
         # and with no EDNS at all
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1260,8 +1161,8 @@ class TestAdvancedEDNSOptionRule(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(receivedResponse, response)
 
-class TestAdvancedEDNSVersionRule(DNSDistTest):
 
+class TestAdvancedEDNSVersionRule(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     addAction(EDNSVersionRule(0), ERCodeAction(DNSRCode.BADVERS))
@@ -1275,9 +1176,9 @@ class TestAdvancedEDNSVersionRule(DNSDistTest):
         if sys.version_info >= (3, 11) and sys.version_info < (3, 12):
             raise unittest.SkipTest("Test skipped, see https://github.com/PowerDNS/pdns/pull/12912")
 
-        name = 'ednsversionrule.advanced.tests.powerdns.com.'
+        name = "ednsversionrule.advanced.tests.powerdns.com."
 
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=1)
+        query = dns.message.make_query(name, "A", "IN", use_edns=1)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.BADVERS)
@@ -1292,9 +1193,9 @@ class TestAdvancedEDNSVersionRule(DNSDistTest):
         Advanced: A question with ECS version 0 goes through
         """
 
-        name = 'ednsversionrule.advanced.tests.powerdns.com.'
+        name = "ednsversionrule.advanced.tests.powerdns.com."
 
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1309,9 +1210,9 @@ class TestAdvancedEDNSVersionRule(DNSDistTest):
         Advanced: A question without ECS goes through
         """
 
-        name = 'ednsoptionrule.advanced.tests.powerdns.com.'
+        name = "ednsoptionrule.advanced.tests.powerdns.com."
 
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1321,11 +1222,11 @@ class TestAdvancedEDNSVersionRule(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(receivedResponse, response)
 
-class TestSetRules(DNSDistTest):
 
+class TestSetRules(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -1338,16 +1239,12 @@ class TestSetRules(DNSDistTest):
         Advanced: Clear rules, set rules
 
         """
-        name = 'clearthensetrules.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "clearthensetrules.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1371,14 +1268,10 @@ class TestSetRules(DNSDistTest):
             self.assertEqual(expectedResponse, receivedResponse)
 
         # insert a new spoofing rule
-        self.sendConsoleCommand("setRules({ newRuleAction(AllRule(), SpoofAction(\"192.0.2.2\")) })")
+        self.sendConsoleCommand('setRules({ newRuleAction(AllRule(), SpoofAction("192.0.2.2")) })')
 
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1388,10 +1281,11 @@ class TestSetRules(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(expectedResponse, receivedResponse)
 
+
 class TestRmRules(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -1408,15 +1302,15 @@ class TestRmRules(DNSDistTest):
         """
         lines = self.sendConsoleCommand("showRules({showUUIDs=true})").splitlines()
         self.assertEqual(len(lines), 3)
-        self.assertIn('myFirstRule', lines[1])
-        self.assertIn('mySecondRule', lines[2])
-        self.assertIn('090736ca-2fb6-41e7-a836-58efaca3d71e', lines[1])
+        self.assertIn("myFirstRule", lines[1])
+        self.assertIn("mySecondRule", lines[2])
+        self.assertIn("090736ca-2fb6-41e7-a836-58efaca3d71e", lines[1])
 
         lines = self.sendConsoleCommand("showResponseRules({showUUIDs=true})").splitlines()
         self.assertEqual(len(lines), 3)
-        self.assertIn('myFirstResponseRule', lines[1])
-        self.assertIn('mySecondResponseRule', lines[2])
-        self.assertIn('745a03b5-89e0-4eee-a6bf-c9700b0d31f0', lines[1])
+        self.assertIn("myFirstResponseRule", lines[1])
+        self.assertIn("mySecondResponseRule", lines[2])
+        self.assertIn("745a03b5-89e0-4eee-a6bf-c9700b0d31f0", lines[1])
 
         self.sendConsoleCommand("rmRule('090736ca-2fb6-41e7-a836-58efaca3d71e')")
         self.sendConsoleCommand("rmRule('mySecondRule')")
@@ -1428,8 +1322,8 @@ class TestRmRules(DNSDistTest):
         lines = self.sendConsoleCommand("showResponseRules({showUUIDs=true})").splitlines()
         self.assertEqual(len(lines), 1)
 
-class TestAdvancedContinueAction(DNSDistTest):
 
+class TestAdvancedContinueAction(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d", pool="mypool"}
     addAction("nocontinue.continue-action.advanced.tests.powerdns.com.", PoolAction("mypool"))
@@ -1442,10 +1336,10 @@ class TestAdvancedContinueAction(DNSDistTest):
         Advanced: Query routed to pool, PoolAction should be terminal
         """
 
-        name = 'nocontinue.continue-action.advanced.tests.powerdns.com.'
+        name = "nocontinue.continue-action.advanced.tests.powerdns.com."
 
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN")
 
         response = dns.message.make_response(query)
         expectedResponse = dns.message.make_response(query)
@@ -1462,10 +1356,10 @@ class TestAdvancedContinueAction(DNSDistTest):
         Advanced: Query routed to pool, ContinueAction() should not stop the processing
         """
 
-        name = 'continue.continue-action.advanced.tests.powerdns.com.'
+        name = "continue.continue-action.advanced.tests.powerdns.com."
 
-        query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
+        expectedQuery = dns.message.make_query(name, "A", "IN")
         expectedQuery.flags |= dns.flags.CD
 
         response = dns.message.make_response(query)
@@ -1478,8 +1372,8 @@ class TestAdvancedContinueAction(DNSDistTest):
             self.assertEqual(receivedQuery, expectedQuery)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestAdvancedNegativeAndSOA(DNSDistTest):
 
+class TestAdvancedNegativeAndSOA(DNSDistTest):
     _selfGeneratedPayloadSize = 1232
     _config_template = """
     addAction("nxd.negativeandsoa.advanced.tests.powerdns.com.", NegativeAndSOAAction(true, "auth.", 42, "mname", "rname", 5, 4, 3, 2, 1))
@@ -1487,24 +1381,19 @@ class TestAdvancedNegativeAndSOA(DNSDistTest):
     setPayloadSizeOnSelfGeneratedAnswers(%d)
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_selfGeneratedPayloadSize', '_testServerPort']
-
+    _config_params = ["_selfGeneratedPayloadSize", "_testServerPort"]
 
     def testAdvancedNegativeAndSOANXD(self):
         """
         Advanced: NegativeAndSOAAction NXD
         """
-        name = 'nxd.negativeandsoa.advanced.tests.powerdns.com.'
+        name = "nxd.negativeandsoa.advanced.tests.powerdns.com."
         # no EDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
-        soa = dns.rrset.from_text("auth.",
-                                  42,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'mname. rname. 5 4 3 2 1')
+        soa = dns.rrset.from_text("auth.", 42, dns.rdataclass.IN, dns.rdatatype.SOA, "mname. rname. 5 4 3 2 1")
         expectedResponse.additional.append(soa)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1513,15 +1402,11 @@ class TestAdvancedNegativeAndSOA(DNSDistTest):
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
         # withEDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=self._selfGeneratedPayloadSize)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
-        soa = dns.rrset.from_text("auth.",
-                                  42,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'mname. rname. 5 4 3 2 1')
+        soa = dns.rrset.from_text("auth.", 42, dns.rdataclass.IN, dns.rdatatype.SOA, "mname. rname. 5 4 3 2 1")
         expectedResponse.additional.append(soa)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1533,17 +1418,13 @@ class TestAdvancedNegativeAndSOA(DNSDistTest):
         """
         Advanced: NegativeAndSOAAction NoData
         """
-        name = 'nodata.negativeandsoa.advanced.tests.powerdns.com.'
+        name = "nodata.negativeandsoa.advanced.tests.powerdns.com."
         # no EDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NOERROR)
-        soa = dns.rrset.from_text("another-auth.",
-                                  42,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'mname. rname. 1 2 3 4 5')
+        soa = dns.rrset.from_text("another-auth.", 42, dns.rdataclass.IN, dns.rdatatype.SOA, "mname. rname. 1 2 3 4 5")
         expectedResponse.additional.append(soa)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1552,15 +1433,11 @@ class TestAdvancedNegativeAndSOA(DNSDistTest):
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
         # with EDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=self._selfGeneratedPayloadSize)
         expectedResponse.set_rcode(dns.rcode.NOERROR)
-        soa = dns.rrset.from_text("another-auth.",
-                                  42,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'mname. rname. 1 2 3 4 5')
+        soa = dns.rrset.from_text("another-auth.", 42, dns.rdataclass.IN, dns.rdatatype.SOA, "mname. rname. 1 2 3 4 5")
         expectedResponse.additional.append(soa)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1570,7 +1447,6 @@ class TestAdvancedNegativeAndSOA(DNSDistTest):
 
 
 class TestAdvancedNegativeAndSOAAuthSection(DNSDistTest):
-
     _selfGeneratedPayloadSize = 1232
     _config_template = """
     addAction("nxd.negativeandsoa.advanced.tests.powerdns.com.", NegativeAndSOAAction(true, "auth.", 42, "mname", "rname", 5, 4, 3, 2, 1, { soaInAuthoritySection=true }))
@@ -1578,24 +1454,19 @@ class TestAdvancedNegativeAndSOAAuthSection(DNSDistTest):
     setPayloadSizeOnSelfGeneratedAnswers(%d)
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_selfGeneratedPayloadSize', '_testServerPort']
-
+    _config_params = ["_selfGeneratedPayloadSize", "_testServerPort"]
 
     def testAdvancedNegativeAndSOANXD(self):
         """
         Advanced: NegativeAndSOAAction NXD
         """
-        name = 'nxd.negativeandsoa.advanced.tests.powerdns.com.'
+        name = "nxd.negativeandsoa.advanced.tests.powerdns.com."
         # no EDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
-        soa = dns.rrset.from_text("auth.",
-                                  42,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'mname. rname. 5 4 3 2 1')
+        soa = dns.rrset.from_text("auth.", 42, dns.rdataclass.IN, dns.rdatatype.SOA, "mname. rname. 5 4 3 2 1")
         expectedResponse.authority.append(soa)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1604,15 +1475,11 @@ class TestAdvancedNegativeAndSOAAuthSection(DNSDistTest):
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
         # withEDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=self._selfGeneratedPayloadSize)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
-        soa = dns.rrset.from_text("auth.",
-                                  42,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'mname. rname. 5 4 3 2 1')
+        soa = dns.rrset.from_text("auth.", 42, dns.rdataclass.IN, dns.rdatatype.SOA, "mname. rname. 5 4 3 2 1")
         expectedResponse.authority.append(soa)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1624,17 +1491,13 @@ class TestAdvancedNegativeAndSOAAuthSection(DNSDistTest):
         """
         Advanced: NegativeAndSOAAction NoData
         """
-        name = 'nodata.negativeandsoa.advanced.tests.powerdns.com.'
+        name = "nodata.negativeandsoa.advanced.tests.powerdns.com."
         # no EDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NOERROR)
-        soa = dns.rrset.from_text("another-auth.",
-                                  42,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'mname. rname. 1 2 3 4 5')
+        soa = dns.rrset.from_text("another-auth.", 42, dns.rdataclass.IN, dns.rdatatype.SOA, "mname. rname. 1 2 3 4 5")
         expectedResponse.authority.append(soa)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1643,15 +1506,11 @@ class TestAdvancedNegativeAndSOAAuthSection(DNSDistTest):
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
 
         # with EDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=self._selfGeneratedPayloadSize)
         expectedResponse.set_rcode(dns.rcode.NOERROR)
-        soa = dns.rrset.from_text("another-auth.",
-                                  42,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'mname. rname. 1 2 3 4 5')
+        soa = dns.rrset.from_text("another-auth.", 42, dns.rdataclass.IN, dns.rdatatype.SOA, "mname. rname. 1 2 3 4 5")
         expectedResponse.authority.append(soa)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1661,7 +1520,6 @@ class TestAdvancedNegativeAndSOAAuthSection(DNSDistTest):
 
 
 class TestAdvancedLuaRule(DNSDistTest):
-
     _config_template = """
 
     function luarulefunction(dq)
@@ -1688,8 +1546,8 @@ class TestAdvancedLuaRule(DNSDistTest):
         """
         Advanced: Test the LuaRule rule
         """
-        name = 'lua-rule.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "lua-rule.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         notimplResponse = dns.message.make_response(query)
@@ -1700,8 +1558,8 @@ class TestAdvancedLuaRule(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, notimplResponse)
 
-        name = 'not-lua-rule.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "not-lua-rule.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         refusedResponse = dns.message.make_response(query)
@@ -1712,8 +1570,8 @@ class TestAdvancedLuaRule(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, refusedResponse)
 
-class TestAdvancedSetEDNSOptionAction(DNSDistTest):
 
+class TestAdvancedSetEDNSOptionAction(DNSDistTest):
     _config_template = """
     addAction(AllRule(), SetEDNSOptionAction(10, "deadbeefdeadc0de"))
     newServer{address="127.0.0.1:%d"}
@@ -1723,18 +1581,14 @@ class TestAdvancedSetEDNSOptionAction(DNSDistTest):
         """
         Advanced: Set EDNS Option
         """
-        name = 'setednsoption.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "setednsoption.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadc0de')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[eco])
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadc0de")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=512, options=[eco])
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1751,19 +1605,15 @@ class TestAdvancedSetEDNSOptionAction(DNSDistTest):
         """
         Advanced: Set EDNS Option overwrites an existing option
         """
-        name = 'setednsoption-overwrite.advanced.tests.powerdns.com.'
-        initialECO = cookiesoption.CookiesOption(b'aaaaaaaa', b'bbbbbbbb')
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "setednsoption-overwrite.advanced.tests.powerdns.com."
+        initialECO = cookiesoption.CookiesOption(b"aaaaaaaa", b"bbbbbbbb")
+        query = dns.message.make_query(name, "A", "IN")
 
-        overWrittenECO = cookiesoption.CookiesOption(b'deadbeef', b'deadc0de')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[overWrittenECO])
+        overWrittenECO = cookiesoption.CookiesOption(b"deadbeef", b"deadc0de")
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=512, options=[overWrittenECO])
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1781,18 +1631,16 @@ class TestAdvancedSetEDNSOptionAction(DNSDistTest):
         Advanced: Set EDNS Option (DO bit set)
         """
         # check that the DO bit is correctly handled, as we messed that up once
-        name = 'setednsoption-do.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, want_dnssec=True, payload=4096)
+        name = "setednsoption-do.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True, want_dnssec=True, payload=4096)
 
-        eco = cookiesoption.CookiesOption(b'deadbeef', b'deadc0de')
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco], want_dnssec=True)
+        eco = cookiesoption.CookiesOption(b"deadbeef", b"deadc0de")
+        expectedQuery = dns.message.make_query(
+            name, "A", "IN", use_edns=True, payload=4096, options=[eco], want_dnssec=True
+        )
 
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1805,8 +1653,8 @@ class TestAdvancedSetEDNSOptionAction(DNSDistTest):
             self.checkResponseEDNSWithoutECS(response, receivedResponse)
             self.checkQueryEDNS(expectedQuery, receivedQuery)
 
-class TestAdvancedLuaGetContent(DNSDistTest):
 
+class TestAdvancedLuaGetContent(DNSDistTest):
     _config_template = """
     function accessContentLua(dq)
         local expectedSize = 57
@@ -1836,14 +1684,10 @@ class TestAdvancedLuaGetContent(DNSDistTest):
         """
         Advanced: Test getContent() via Lua
         """
-        name = 'get-content.advanced.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "get-content.advanced.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "::1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index e94a1930a16ceb876aa77103ea61b809d1fc74d6..6a4a8365e6ae2c018a10394dbff556f647d6e491 100644 (file)
@@ -6,23 +6,24 @@ import ssl
 
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
+
 class TestSNI(DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverKeyEC = 'server-ec.key'
-    _serverCertEC = 'server-ec.chain'
-    _serverKey2 = 'server2.key'
-    _serverCert2 = 'server2.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _serverName2 = 'tls2.tests.dnsdist.org'
-    _serverName3 = 'unknown.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverKeyEC = "server-ec.key"
+    _serverCertEC = "server-ec.chain"
+    _serverKey2 = "server2.key"
+    _serverCert2 = "server2.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _serverName2 = "tls2.tests.dnsdist.org"
+    _serverName3 = "unknown.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
     _doqServerPort = pickAvailablePort()
     _doh3ServerPort = pickAvailablePort()
-    _dohWithNGHTTP2BaseURL = ("https://%s:%d/" % (_serverName, _dohWithNGHTTP2ServerPort))
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
+    _dohWithNGHTTP2BaseURL = "https://%s:%d/" % (_serverName, _dohWithNGHTTP2ServerPort)
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doh3ServerPort)
 
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -57,18 +58,33 @@ class TestSNI(DNSDistTest):
     end
     addAction(AllRule(), LuaAction(checkSNI))
     """
-    _config_params = ['_testServerPort', '_serverCert', '_serverCertEC', '_serverCert2', '_serverKey', '_serverKeyEC', '_serverKey2', '_serverCert', '_serverKey', '_tlsServerPort', '_dohWithNGHTTP2ServerPort', '_doqServerPort', '_doh3ServerPort', '_serverName', '_serverName2', '_serverName3', '_serverName', '_serverName']
-
-    @unittest.skipUnless('ENABLE_SNI_TESTS_WITH_QUICHE' in os.environ, "SNI tests with Quiche are disabled")
+    _config_params = [
+        "_testServerPort",
+        "_serverCert",
+        "_serverCertEC",
+        "_serverCert2",
+        "_serverKey",
+        "_serverKeyEC",
+        "_serverKey2",
+        "_serverCert",
+        "_serverKey",
+        "_tlsServerPort",
+        "_dohWithNGHTTP2ServerPort",
+        "_doqServerPort",
+        "_doh3ServerPort",
+        "_serverName",
+        "_serverName2",
+        "_serverName3",
+        "_serverName",
+        "_serverName",
+    ]
+
+    @unittest.skipUnless("ENABLE_SNI_TESTS_WITH_QUICHE" in os.environ, "SNI tests with Quiche are disabled")
     def testServerNameIndicationWithQuiche(self):
-        name = 'simple.sni.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.sni.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         for method in ["sendDOQQueryWrapper", "sendDOH3QueryWrapper"]:
             sender = getattr(self, method)
@@ -77,20 +93,16 @@ class TestSNI(DNSDistTest):
             receivedQuery.id = query.id
             self.assertEqual(query, receivedQuery)
             self.assertTrue(receivedResponse)
-            if method == 'sendDOQQueryWrapper':
+            if method == "sendDOQQueryWrapper":
                 # dnspython sets the ID to 0
                 receivedResponse.id = response.id
             self.assertEqual(response, receivedResponse)
 
     def testServerNameIndication(self):
-        name = 'simple.sni.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "simple.sni.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         for method in ["sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper"]:
             sender = getattr(self, method)
@@ -102,15 +114,11 @@ class TestSNI(DNSDistTest):
             self.assertEqual(response, receivedResponse)
 
         # check second certificate
-        name = 'name2.sni.tests.powerdns.com.'
-        self._dohWithNGHTTP2BaseURL = ("https://%s:%d/" % (self._serverName2, self._dohWithNGHTTP2ServerPort))
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "name2.sni.tests.powerdns.com."
+        self._dohWithNGHTTP2BaseURL = "https://%s:%d/" % (self._serverName2, self._dohWithNGHTTP2ServerPort)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         for method in ["sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper"]:
             sender = getattr(self, method)
@@ -122,19 +130,15 @@ class TestSNI(DNSDistTest):
             self.assertEqual(response, receivedResponse)
 
         # check SNI for an unknown name, we should get the first certificate
-        name = 'unknown.sni.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "unknown.sni.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         sslctx = ssl.create_default_context(cafile=self._caCert)
         sslctx.check_hostname = False
-        if hasattr(sslctx, 'set_alpn_protocols'):
+        if hasattr(sslctx, "set_alpn_protocols"):
             sslctx.set_alpn_protocols(self._serverName3)
 
         conn = self.openTLSConnection(self._tlsServerPort, self._serverName3, self._caCert, timeout=1, sslctx=sslctx)
@@ -145,34 +149,30 @@ class TestSNI(DNSDistTest):
         self.assertEqual(receivedResponse, response)
 
         cert = conn.getpeercert()
-        subject = cert['subject']
-        altNames = cert['subjectAltName']
-        self.assertEqual(dict(subject[0])['commonName'], 'tls.tests.dnsdist.org')
-        self.assertEqual(dict(subject[1])['organizationalUnitName'], 'PowerDNS.com BV')
+        subject = cert["subject"]
+        altNames = cert["subjectAltName"]
+        self.assertEqual(dict(subject[0])["commonName"], "tls.tests.dnsdist.org")
+        self.assertEqual(dict(subject[1])["organizationalUnitName"], "PowerDNS.com BV")
         names = []
         for entry in altNames:
             names.append(entry[1])
-        self.assertEqual(names, ['tls.tests.dnsdist.org', 'powerdns.com', '127.0.0.1'])
+        self.assertEqual(names, ["tls.tests.dnsdist.org", "powerdns.com", "127.0.0.1"])
 
         # check that we provide the correct RSA/ECDSA certificate when requested
-        for algo in ['rsa', 'ecdsa']:
-            name = algo + '.sni.tests.powerdns.com.'
-            query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        for algo in ["rsa", "ecdsa"]:
+            name = algo + ".sni.tests.powerdns.com."
+            query = dns.message.make_query(name, "A", "IN", use_edns=False)
             response = dns.message.make_response(query)
-            rrset = dns.rrset.from_text(name,
-                                        3600,
-                                        dns.rdataclass.IN,
-                                        dns.rdatatype.A,
-                                        '127.0.0.1')
+            rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
             response.answer.append(rrset)
 
             sslctx = ssl.create_default_context(cafile=self._caCert)
-            if hasattr(sslctx, 'set_alpn_protocols'):
+            if hasattr(sslctx, "set_alpn_protocols"):
                 sslctx.set_alpn_protocols(self._serverName)
             # disable TLS 1.3 because configuring the signature algorithm is not supported by Python yet
             sslctx.maximum_version = ssl.TLSVersion.TLSv1_2
             # explicitly request authentication via RSA or ECDSA
-            sslctx.set_ciphers('a' + algo.upper())
+            sslctx.set_ciphers("a" + algo.upper())
 
             conn = self.openTLSConnection(self._tlsServerPort, self._serverName, self._caCert, timeout=1, sslctx=sslctx)
             self.sendTCPQueryOverConnection(conn, query, response=response, timeout=1)
@@ -182,11 +182,11 @@ class TestSNI(DNSDistTest):
             self.assertEqual(receivedResponse, response)
 
             cert = conn.getpeercert()
-            subject = cert['subject']
-            altNames = cert['subjectAltName']
-            self.assertEqual(dict(subject[0])['commonName'], 'tls.tests.dnsdist.org')
-            self.assertEqual(dict(subject[1])['organizationalUnitName'], 'PowerDNS.com BV')
+            subject = cert["subject"]
+            altNames = cert["subjectAltName"]
+            self.assertEqual(dict(subject[0])["commonName"], "tls.tests.dnsdist.org")
+            self.assertEqual(dict(subject[1])["organizationalUnitName"], "PowerDNS.com BV")
             names = []
             for entry in altNames:
                 names.append(entry[1])
-            self.assertEqual(names, ['tls.tests.dnsdist.org', 'powerdns.com', '127.0.0.1'])
+            self.assertEqual(names, ["tls.tests.dnsdist.org", "powerdns.com", "127.0.0.1"])
index 03d8429672c7e0358027999bbb0a43c253e5eb19..5a5636d097e4edb9430812a9433980071a526db5 100644 (file)
@@ -4,17 +4,18 @@ import dns
 from pysnmp.hlapi import *
 from dnsdisttests import DNSDistTest
 
+
 class TestSNMP(DNSDistTest):
     # wait 1s so that the uptime is > 0
     _extraStartupSleep = 1
     _snmpTimeout = 2.0
-    _snmpServer = '127.0.0.1'
+    _snmpServer = "127.0.0.1"
     _snmpPort = 161
-    _snmpV2Community = 'secretcommunity'
-    _snmpV3User = 'secretuser'
-    _snmpV3AuthKey = 'mysecretauthkey'
-    _snmpV3EncKey = 'mysecretenckey'
-    _snmpOID = '1.3.6.1.4.1.43315.3'
+    _snmpV2Community = "secretcommunity"
+    _snmpV3User = "secretuser"
+    _snmpV3AuthKey = "mysecretauthkey"
+    _snmpV3EncKey = "mysecretenckey"
+    _snmpOID = "1.3.6.1.4.1.43315.3"
     _queriesSent = 0
     _config_template = """
     newServer{address="127.0.0.1:%d", name="servername"}
@@ -24,28 +25,28 @@ class TestSNMP(DNSDistTest):
     _verboseMode = True
 
     def _checkStatsValues(self, results, queriesCountersValue):
-        for i in list(range(1, 5)) + list(range(6, 20)) + list(range(24, 35)) + [ 35 ] :
-            oid = self._snmpOID + '.1.' + str(i) + '.0'
+        for i in list(range(1, 5)) + list(range(6, 20)) + list(range(24, 35)) + [35]:
+            oid = self._snmpOID + ".1." + str(i) + ".0"
             self.assertIn(oid, results)
             self.assertTrue(isinstance(results[oid], Counter64))
 
         for i in range(20, 23):
-            oid = self._snmpOID + '.1.' + str(i) + '.0'
+            oid = self._snmpOID + ".1." + str(i) + ".0"
             self.assertTrue(isinstance(results[oid], OctetString))
 
         # check uptime > 0
-        self.assertGreater(results['1.3.6.1.4.1.43315.3.1.24.0'], 0)
+        self.assertGreater(results["1.3.6.1.4.1.43315.3.1.24.0"], 0)
         # check memory usage > 0
-        self.assertGreater(results['1.3.6.1.4.1.43315.3.1.25.0'], 0)
+        self.assertGreater(results["1.3.6.1.4.1.43315.3.1.25.0"], 0)
 
         # check that the queries, responses and rdQueries counters are now at queriesCountersValue
         for i in [1, 2, 28]:
-            oid = self._snmpOID + '.1.' + str(i) + '.0'
+            oid = self._snmpOID + ".1." + str(i) + ".0"
             self.assertEqual(results[oid], queriesCountersValue)
 
         # the others counters (except for latency ones) should still be at 0
         for i in [3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 26, 27, 29, 30, 31, 35, 36]:
-            oid = self._snmpOID + '.1.' + str(i) + '.0'
+            oid = self._snmpOID + ".1." + str(i) + ".0"
             self.assertEqual(results[oid], 0)
 
         # check the backend stats
@@ -53,41 +54,43 @@ class TestSNMP(DNSDistTest):
 
         ## types
         for i in [3, 4, 5, 6, 7, 11, 12, 13]:
-            oid = self._snmpOID + '.2.1.' + str(i) + '.0'
+            oid = self._snmpOID + ".2.1." + str(i) + ".0"
             self.assertTrue(isinstance(results[oid], Counter64))
         for i in [2, 8, 9, 10]:
-            oid = self._snmpOID + '.2.1.' + str(i) + '.0'
+            oid = self._snmpOID + ".2.1." + str(i) + ".0"
             self.assertTrue(isinstance(results[oid], OctetString))
 
         ## name
-        self.assertEqual(str(results['1.3.6.1.4.1.43315.3.2.1.2.0']), "servername")
+        self.assertEqual(str(results["1.3.6.1.4.1.43315.3.2.1.2.0"]), "servername")
         ## weight
-        self.assertEqual(results['1.3.6.1.4.1.43315.3.2.1.4.0'], 1)
+        self.assertEqual(results["1.3.6.1.4.1.43315.3.2.1.4.0"], 1)
         ## outstanding
-        self.assertEqual(results['1.3.6.1.4.1.43315.3.2.1.5.0'], 0)
+        self.assertEqual(results["1.3.6.1.4.1.43315.3.2.1.5.0"], 0)
         ## qpslimit
-        self.assertEqual(results['1.3.6.1.4.1.43315.3.2.1.6.0'], 0)
+        self.assertEqual(results["1.3.6.1.4.1.43315.3.2.1.6.0"], 0)
         ## reused
-        self.assertEqual(results['1.3.6.1.4.1.43315.3.2.1.7.0'], 0)
+        self.assertEqual(results["1.3.6.1.4.1.43315.3.2.1.7.0"], 0)
         ## state
-        self.assertEqual(str(results['1.3.6.1.4.1.43315.3.2.1.8.0']), "up")
+        self.assertEqual(str(results["1.3.6.1.4.1.43315.3.2.1.8.0"]), "up")
         ## address
-        self.assertEqual(str(results['1.3.6.1.4.1.43315.3.2.1.9.0']), ("127.0.0.1:%d" % (self._testServerPort)))
+        self.assertEqual(str(results["1.3.6.1.4.1.43315.3.2.1.9.0"]), ("127.0.0.1:%d" % (self._testServerPort)))
         ## pools
-        self.assertEqual(str(results['1.3.6.1.4.1.43315.3.2.1.10.0']), "")
+        self.assertEqual(str(results["1.3.6.1.4.1.43315.3.2.1.10.0"]), "")
         ## queries
-        self.assertEqual(results['1.3.6.1.4.1.43315.3.2.1.12.0'], queriesCountersValue)
+        self.assertEqual(results["1.3.6.1.4.1.43315.3.2.1.12.0"], queriesCountersValue)
         ## order
-        self.assertEqual(results['1.3.6.1.4.1.43315.3.2.1.13.0'], 1)
+        self.assertEqual(results["1.3.6.1.4.1.43315.3.2.1.13.0"], 1)
 
     def _getSNMPStats(self, auth):
         results = {}
-        for (errorIndication, errorStatus, errorIndex, varBinds) in nextCmd(SnmpEngine(),
-                                                                            auth,
-                                                                            UdpTransportTarget((self._snmpServer, self._snmpPort), timeout=self._snmpTimeout),
-                                                                            ContextData(),
-                                                                            ObjectType(ObjectIdentity(self._snmpOID)),
-                                                                            lookupMib=False):
+        for errorIndication, errorStatus, errorIndex, varBinds in nextCmd(
+            SnmpEngine(),
+            auth,
+            UdpTransportTarget((self._snmpServer, self._snmpPort), timeout=self._snmpTimeout),
+            ContextData(),
+            ObjectType(ObjectIdentity(self._snmpOID)),
+            lookupMib=False,
+        ):
             self.assertFalse(errorIndication)
             self.assertFalse(errorStatus)
             self.assertTrue(varBinds)
@@ -104,13 +107,9 @@ class TestSNMP(DNSDistTest):
         results = self._getSNMPStats(auth)
         self._checkStatsValues(results, self.__class__._queriesSent)
 
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         # send a query
@@ -131,7 +130,7 @@ class TestSNMP(DNSDistTest):
         """
 
         auth = CommunityData(self._snmpV2Community, mpModel=1)
-        name = 'simplea.snmpv2c.tests.powerdns.com.'
+        name = "simplea.snmpv2c.tests.powerdns.com."
         self._checkStats(auth, name)
 
     def testSNMPv3Stats(self):
@@ -139,10 +138,12 @@ class TestSNMP(DNSDistTest):
         SNMP: Retrieve statistics via SNMPv3
         """
 
-        auth = UsmUserData(self._snmpV3User,
-                               authKey=self._snmpV3AuthKey,
-                               privKey=self._snmpV3EncKey,
-                               authProtocol=usmHMACSHAAuthProtocol,
-                               privProtocol=usmAesCfb128Protocol)
-        name = 'simplea.snmpv2.tests.powerdns.com.'
+        auth = UsmUserData(
+            self._snmpV3User,
+            authKey=self._snmpV3AuthKey,
+            privKey=self._snmpV3EncKey,
+            authProtocol=usmHMACSHAAuthProtocol,
+            privProtocol=usmAesCfb128Protocol,
+        )
+        name = "simplea.snmpv2.tests.powerdns.com."
         self._checkStats(auth, name)
index b794636e9cea4d85a2d93ebd809ed9fb5bdea811..029616054029b7880859087e5977df03e42067e9 100644 (file)
@@ -2,8 +2,8 @@
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestSVCB(DNSDistTest):
 
+class TestSVCB(DNSDistTest):
     _config_template = """
     local basicSVC = { newSVCRecordParameters(1, "dot.powerdns.com.", { mandatory={"port"}, alpn={"dot"}, noDefaultAlpn=true, port=853, ipv4hint={ "192.0.2.1" }, ipv6hint={ "2001:db8::1" } }),
                        newSVCRecordParameters(2, "doh.powerdns.com.", { mandatory={"port"}, alpn={"h2"}, port=443, ipv4hint={ "192.0.2.2" }, ipv6hint={ "2001:db8::2" }, key7="/dns-query{?dns}" })
@@ -30,8 +30,8 @@ class TestSVCB(DNSDistTest):
         """
         SVCB: Basic service binding
         """
-        name = 'basic.svcb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 64, 'IN')
+        name = "basic.svcb.tests.powerdns.com."
+        query = dns.message.make_query(name, 64, "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
@@ -42,17 +42,29 @@ class TestSVCB(DNSDistTest):
             self.assertEqual(len(receivedResponse.answer), 1)
             self.assertEqual(receivedResponse.answer[0].rdtype, 64)
             self.assertEqual(len(receivedResponse.additional), 4)
-            self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'))
-            self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'))
-            self.assertEqual(receivedResponse.additional[2], dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::2'))
-            self.assertEqual(receivedResponse.additional[3], dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::1'))
+            self.assertEqual(
+                receivedResponse.additional[0],
+                dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2"),
+            )
+            self.assertEqual(
+                receivedResponse.additional[1],
+                dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+            )
+            self.assertEqual(
+                receivedResponse.additional[2],
+                dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::2"),
+            )
+            self.assertEqual(
+                receivedResponse.additional[3],
+                dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::1"),
+            )
 
     def testNoHints(self):
         """
         SVCB: No hints
         """
-        name = 'no-hints.svcb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 64, 'IN')
+        name = "no-hints.svcb.tests.powerdns.com."
+        query = dns.message.make_query(name, 64, "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
@@ -68,8 +80,8 @@ class TestSVCB(DNSDistTest):
         """
         SVCB: Effective target
         """
-        name = 'effective-target.svcb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 64, 'IN')
+        name = "effective-target.svcb.tests.powerdns.com."
+        query = dns.message.make_query(name, 64, "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
@@ -80,15 +92,21 @@ class TestSVCB(DNSDistTest):
             self.assertEqual(len(receivedResponse.answer), 1)
             self.assertEqual(receivedResponse.answer[0].rdtype, 64)
             self.assertEqual(len(receivedResponse.additional), 2)
-            self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'))
-            self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::1'))
+            self.assertEqual(
+                receivedResponse.additional[0],
+                dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+            )
+            self.assertEqual(
+                receivedResponse.additional[1],
+                dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::1"),
+            )
 
     def testHTTPS(self):
         """
         SVCB: HTTPS
         """
-        name = 'https.svcb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 65, 'IN')
+        name = "https.svcb.tests.powerdns.com."
+        query = dns.message.make_query(name, 65, "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
@@ -99,11 +117,17 @@ class TestSVCB(DNSDistTest):
             self.assertEqual(len(receivedResponse.answer), 1)
             self.assertEqual(receivedResponse.answer[0].rdtype, 65)
             self.assertEqual(len(receivedResponse.additional), 2)
-            self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'))
-            self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::2'))
+            self.assertEqual(
+                receivedResponse.additional[0],
+                dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2"),
+            )
+            self.assertEqual(
+                receivedResponse.additional[1],
+                dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::2"),
+            )
 
-class TestSVCBViaFFI(DNSDistTest):
 
+class TestSVCBViaFFI(DNSDistTest):
     _config_template = """
     local ffi = require("ffi")
 
@@ -193,8 +217,8 @@ class TestSVCBViaFFI(DNSDistTest):
         """
         SVCB: Basic service binding
         """
-        name = 'basic.svcb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 64, 'IN')
+        name = "basic.svcb.tests.powerdns.com."
+        query = dns.message.make_query(name, 64, "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
@@ -205,17 +229,29 @@ class TestSVCBViaFFI(DNSDistTest):
             self.assertEqual(len(receivedResponse.answer), 1)
             self.assertEqual(receivedResponse.answer[0].rdtype, 64)
             self.assertEqual(len(receivedResponse.additional), 4)
-            self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'))
-            self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'))
-            self.assertEqual(receivedResponse.additional[2], dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::2'))
-            self.assertEqual(receivedResponse.additional[3], dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::1'))
+            self.assertEqual(
+                receivedResponse.additional[0],
+                dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2"),
+            )
+            self.assertEqual(
+                receivedResponse.additional[1],
+                dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+            )
+            self.assertEqual(
+                receivedResponse.additional[2],
+                dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::2"),
+            )
+            self.assertEqual(
+                receivedResponse.additional[3],
+                dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::1"),
+            )
 
     def testNoHints(self):
         """
         SVCB: No hints
         """
-        name = 'no-hints.svcb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 64, 'IN')
+        name = "no-hints.svcb.tests.powerdns.com."
+        query = dns.message.make_query(name, 64, "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
@@ -231,8 +267,8 @@ class TestSVCBViaFFI(DNSDistTest):
         """
         SVCB: Effective target
         """
-        name = 'effective-target.svcb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 64, 'IN')
+        name = "effective-target.svcb.tests.powerdns.com."
+        query = dns.message.make_query(name, 64, "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
@@ -243,15 +279,21 @@ class TestSVCBViaFFI(DNSDistTest):
             self.assertEqual(len(receivedResponse.answer), 1)
             self.assertEqual(receivedResponse.answer[0].rdtype, 64)
             self.assertEqual(len(receivedResponse.additional), 2)
-            self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'))
-            self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::1'))
+            self.assertEqual(
+                receivedResponse.additional[0],
+                dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+            )
+            self.assertEqual(
+                receivedResponse.additional[1],
+                dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::1"),
+            )
 
     def testHTTPS(self):
         """
         SVCB: HTTPS
         """
-        name = 'https.svcb.tests.powerdns.com.'
-        query = dns.message.make_query(name, 65, 'IN')
+        name = "https.svcb.tests.powerdns.com."
+        query = dns.message.make_query(name, 65, "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
 
@@ -262,5 +304,11 @@ class TestSVCBViaFFI(DNSDistTest):
             self.assertEqual(len(receivedResponse.answer), 1)
             self.assertEqual(receivedResponse.answer[0].rdtype, 65)
             self.assertEqual(len(receivedResponse.additional), 2)
-            self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'))
-            self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::2'))
+            self.assertEqual(
+                receivedResponse.additional[0],
+                dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2"),
+            )
+            self.assertEqual(
+                receivedResponse.additional[1],
+                dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:db8::2"),
+            )
index 344c7523f32c3a091007023b8760321f8acb843e..ec8f98f95271f6a5fb19442ed89b113dabd28db3 100644 (file)
@@ -2,8 +2,8 @@
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestSelfAnsweredResponses(DNSDistTest):
 
+class TestSelfAnsweredResponses(DNSDistTest):
     _config_template = """
     -- this is a silly test config, please do not do this in production.
     addAction(SuffixMatchNodeRule("udp.selfanswered.tests.powerdns.com."), SpoofAction("192.0.2.1"))
@@ -18,14 +18,10 @@ class TestSelfAnsweredResponses(DNSDistTest):
         SelfAnsweredResponses: Drop when served from the cache
         """
         ttl = 60
-        name = 'udp.selfanswered.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.selfanswered.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         response.flags |= dns.flags.RA
 
@@ -43,14 +39,10 @@ class TestSelfAnsweredResponses(DNSDistTest):
         SelfAnsweredResponses: TCP: Drop after exceeding QPS
         """
         ttl = 60
-        name = 'tcp.selfanswered.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tcp.selfanswered.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    ttl,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, ttl, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
         response.flags |= dns.flags.RA
 
index cff8d81e713ab16d329f0b8d86f75d6bf214b4cb..bcd20ff18c96f20da8b0b241cdb2c6d0add1f668 100644 (file)
@@ -2,8 +2,8 @@
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestSize(DNSDistTest):
 
+class TestSize(DNSDistTest):
     _payloadSize = 49
     _config_template = """
     addAction(PayloadSizeRule("smaller", %d), SpoofAction("192.0.2.1"))
@@ -11,21 +11,17 @@ class TestSize(DNSDistTest):
     addAction(PayloadSizeRule("equal", %d), SpoofAction("192.0.2.3"))
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_payloadSize', '_payloadSize', '_payloadSize', '_testServerPort']
+    _config_params = ["_payloadSize", "_payloadSize", "_payloadSize", "_testServerPort"]
 
     def testPayloadSize(self):
         """
         Size: Check that PayloadSizeRule works
         """
-        name = 'payload.size.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "payload.size.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.3')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.3")
         expectedResponse.answer.append(rrset)
         self.assertEqual(len(query.to_wire()), self._payloadSize)
 
@@ -35,36 +31,32 @@ class TestSize(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestTruncateOversizedResponse(DNSDistTest):
 
+class TestTruncateOversizedResponse(DNSDistTest):
     _payloadSize = 512
     _config_template = """
     addResponseAction(PayloadSizeRule("greater", %d), TCResponseAction())
     newServer{address="127.0.0.1:%d"}
     """
-    _config_params = ['_payloadSize', '_testServerPort']
+    _config_params = ["_payloadSize", "_testServerPort"]
 
     def testTruncateOversizedResponse(self):
         """
         Size: Truncate oversized response
         """
-        name = 'truncate-oversized.size.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        name = "truncate-oversized.size.tests.powerdns.com."
+        query = dns.message.make_query(name, "TXT", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags |= dns.flags.TC
 
         backendResponse = dns.message.make_response(query)
-        content = ''
+        content = ""
         for i in range(2):
             if len(content) > 0:
-                content = content + ' '
-            content = content + 'A' * 255
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    content)
+                content = content + " "
+            content = content + "A" * 255
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, content)
         backendResponse.answer.append(rrset)
         self.assertGreater(len(backendResponse.to_wire()), self._payloadSize)
 
index 332615922af233191882f988a09030f2576a57f9..28f2079b09646535454b99860a4a8182bb2af1a4 100644 (file)
@@ -2,8 +2,8 @@
 import dns
 from dnsdisttests import DNSDistTest
 
-class SpoofingTests(object):
 
+class SpoofingTests(object):
     def testSpoofActionA(self):
         """
         Spoofing: Spoof A via Action
@@ -11,16 +11,12 @@ class SpoofingTests(object):
         Send an A query to "spoofaction.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'spoofaction.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "spoofaction.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -36,17 +32,13 @@ class SpoofingTests(object):
         Send an A query to "spoofaction.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'spoofaction.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        name = "spoofaction.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=1232)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -62,16 +54,12 @@ class SpoofingTests(object):
         Send an AAAA query to "spoofaction.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'spoofaction.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "spoofaction.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -87,16 +75,14 @@ class SpoofingTests(object):
         Send an A query for "cnamespoofaction.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'cnamespoofaction.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "cnamespoofaction.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'cnameaction.spoofing.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name, 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "cnameaction.spoofing.tests.powerdns.com."
+        )
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -112,16 +98,12 @@ class SpoofingTests(object):
         Send an A query for "multispoof.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'multispoof.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "multispoof.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.2', '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2", "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -137,16 +119,12 @@ class SpoofingTests(object):
         Send an AAAA query for "multispoof.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'multispoof.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "multispoof.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1', '2001:DB8::2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1", "2001:DB8::2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -162,24 +140,16 @@ class SpoofingTests(object):
         Send an ANY query for "multispoof.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'multispoof.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'ANY', 'IN')
+        name = "multispoof.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "ANY", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.2', '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2", "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1', '2001:DB8::2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1", "2001:DB8::2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -192,17 +162,13 @@ class SpoofingTests(object):
         """
         Spoofing: Spoof via Action, setting AA=1
         """
-        name = 'spoofaction-aa.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "spoofaction-aa.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags |= dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -216,17 +182,13 @@ class SpoofingTests(object):
         """
         Spoofing: Spoof via Action, setting AD=1
         """
-        name = 'spoofaction-ad.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "spoofaction-ad.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags |= dns.flags.AD
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -240,17 +202,13 @@ class SpoofingTests(object):
         """
         Spoofing: Spoof via Action, setting RA=1
         """
-        name = 'spoofaction-ra.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "spoofaction-ra.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags |= dns.flags.RA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -264,15 +222,11 @@ class SpoofingTests(object):
         """
         Spoofing: Spoof via Action, setting RA=0
         """
-        name = 'spoofaction-nora.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "spoofaction-nora.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.RA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -286,15 +240,11 @@ class SpoofingTests(object):
         """
         Spoofing: Spoof via Action, setting the TTL to 1500
         """
-        name = 'spoofaction-ttl.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "spoofaction-ttl.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags |= dns.flags.RA
-        rrset = dns.rrset.from_text(name,
-                                    1500,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 1500, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -308,18 +258,14 @@ class SpoofingTests(object):
         """
         Spoofing: Spoof a response from raw bytes
         """
-        name = 'raw.spoofing.tests.powerdns.com.'
+        name = "raw.spoofing.tests.powerdns.com."
 
         # A
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -330,16 +276,12 @@ class SpoofingTests(object):
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
         # A with EDNS
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
+        query = dns.message.make_query(name, "A", "IN", use_edns=True)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.use_edns(edns=True, payload=1232)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -350,15 +292,11 @@ class SpoofingTests(object):
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
         # TXT
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        query = dns.message.make_query(name, "TXT", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    '"aaa" "bbbb" "ccccccccccc"')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.TXT, '"aaa" "bbbb" "ccccccccccc"')
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -369,16 +307,12 @@ class SpoofingTests(object):
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
         # SRV
-        query = dns.message.make_query(name, 'SRV', 'IN')
+        query = dns.message.make_query(name, "SRV", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         # this one should have the AA flag set
         expectedResponse.flags |= dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SRV,
-                                    '0 0 65535 srv.powerdns.com.')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.SRV, "0 0 65535 srv.powerdns.com.")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -392,18 +326,14 @@ class SpoofingTests(object):
         """
         Spoofing: Spoof a response from several raw bytes in QCLass CH
         """
-        name = 'rawchaos.spoofing.tests.powerdns.com.'
+        name = "rawchaos.spoofing.tests.powerdns.com."
 
         # TXT CH
-        query = dns.message.make_query(name, 'TXT', 'CH')
+        query = dns.message.make_query(name, "TXT", "CH")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.CH,
-                                    dns.rdatatype.TXT,
-                                    '"chaos\\\\test"')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.CH, dns.rdatatype.TXT, '"chaos\\\\test"')
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -417,17 +347,13 @@ class SpoofingTests(object):
         """
         Spoofing: Spoof a HINFO response for ANY queries
         """
-        name = 'raw-any.spoofing.tests.powerdns.com.'
+        name = "raw-any.spoofing.tests.powerdns.com."
 
-        query = dns.message.make_query(name, 'ANY', 'IN')
+        query = dns.message.make_query(name, "ANY", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.HINFO,
-                                    '"rfc8482" ""')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.HINFO, '"rfc8482" ""')
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -441,18 +367,14 @@ class SpoofingTests(object):
         """
         Spoofing: Spoof a response from several raw bytes
         """
-        name = 'multiraw.spoofing.tests.powerdns.com.'
+        name = "multiraw.spoofing.tests.powerdns.com."
 
         # A
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1', '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -463,15 +385,11 @@ class SpoofingTests(object):
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
         # TXT
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        query = dns.message.make_query(name, "TXT", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    '"aaa" "bbbb"', '"ccccccccccc"')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.TXT, '"aaa" "bbbb"', '"ccccccccccc"')
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -481,8 +399,8 @@ class SpoofingTests(object):
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
-class TestSpoofingViaLuaConfig(DNSDistTest, SpoofingTests):
 
+class TestSpoofingViaLuaConfig(DNSDistTest, SpoofingTests):
     _config_template = """
     addAction(SuffixMatchNodeRule("spoofaction.spoofing.tests.powerdns.com."), SpoofAction({"192.0.2.1", "2001:DB8::1"}))
     addAction(SuffixMatchNodeRule("spoofaction-aa.spoofing.tests.powerdns.com."), SpoofAction({"192.0.2.1", "2001:DB8::1"}, {aa=true}))
@@ -503,8 +421,8 @@ class TestSpoofingViaLuaConfig(DNSDistTest, SpoofingTests):
     newServer{address="127.0.0.1:%d"}
     """
 
-class TestSpoofingViaYamlConfig(DNSDistTest, SpoofingTests):
 
+class TestSpoofingViaYamlConfig(DNSDistTest, SpoofingTests):
     _yaml_config_template = """
 backends:
   - address: "127.0.0.1:%d"
@@ -709,11 +627,11 @@ query_rules:
       vars:
         ttl: 60
     """
-    _yaml_config_params = ['_testServerPort']
+    _yaml_config_params = ["_testServerPort"]
     _config_params = []
 
-class TestSpoofingLuaSpoof(DNSDistTest):
 
+class TestSpoofingLuaSpoof(DNSDistTest):
     _config_template = """
     function spoof1rule(dq)
         if(dq.qtype==1) -- A
@@ -756,16 +674,12 @@ class TestSpoofingLuaSpoof(DNSDistTest):
         Send an A query to "luaspoof1.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'luaspoof1.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "luaspoof1.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1', '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -781,16 +695,12 @@ class TestSpoofingLuaSpoof(DNSDistTest):
         Send an AAAA query to "luaspoof1.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'luaspoof1.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "luaspoof1.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -806,16 +716,14 @@ class TestSpoofingLuaSpoof(DNSDistTest):
         Send an A query to "luaspoof2.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'luaspoof2.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "luaspoof2.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'spoofedcname.spoofing.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name, 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "spoofedcname.spoofing.tests.powerdns.com."
+        )
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -831,16 +739,14 @@ class TestSpoofingLuaSpoof(DNSDistTest):
         Send an AAAA query to "luaspoof2.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'luaspoof2.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "luaspoof2.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    'spoofedcname.spoofing.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name, 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "spoofedcname.spoofing.tests.powerdns.com."
+        )
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -853,18 +759,14 @@ class TestSpoofingLuaSpoof(DNSDistTest):
         """
         Spoofing: Spoof a response from raw bytes via Lua
         """
-        name = 'lua-raw.spoofing.tests.powerdns.com.'
+        name = "lua-raw.spoofing.tests.powerdns.com."
 
         # A
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -875,15 +777,11 @@ class TestSpoofingLuaSpoof(DNSDistTest):
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
         # TXT
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        query = dns.message.make_query(name, "TXT", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    '"aaa" "bbbb" "ccccccccccc"')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.TXT, '"aaa" "bbbb" "ccccccccccc"')
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -894,16 +792,12 @@ class TestSpoofingLuaSpoof(DNSDistTest):
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
         # SRV
-        query = dns.message.make_query(name, 'SRV', 'IN')
+        query = dns.message.make_query(name, "SRV", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         # this one should have the AA flag set
         expectedResponse.flags |= dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SRV,
-                                    '0 0 65535 srv.powerdns.com.')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.SRV, "0 0 65535 srv.powerdns.com.")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -912,10 +806,10 @@ class TestSpoofingLuaSpoof(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
             # sorry, we can't set the TTL from the Lua API right now
-            #self.assertEqual(receivedResponse.answer[0].ttl, 3600)
+            # self.assertEqual(receivedResponse.answer[0].ttl, 3600)
 
-class TestSpoofingLuaSpoofMulti(DNSDistTest):
 
+class TestSpoofingLuaSpoofMulti(DNSDistTest):
     _config_template = """
     function spoof1multirule(dq)
         if(dq.qtype==1) -- A
@@ -958,16 +852,12 @@ class TestSpoofingLuaSpoofMulti(DNSDistTest):
         Send an A query to "luaspoof1multi.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'luaspoof1multi.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "luaspoof1multi.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1', '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -983,16 +873,12 @@ class TestSpoofingLuaSpoofMulti(DNSDistTest):
         Send an AAAA query to "luaspoof1.spoofing.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'luaspoof1multi.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "luaspoof1multi.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1', '2001:DB8::2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1", "2001:DB8::2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1005,18 +891,14 @@ class TestSpoofingLuaSpoofMulti(DNSDistTest):
         """
         Spoofing: Spoof responses from raw bytes via Lua dq:spoof
         """
-        name = 'lua-raw-multi.spoofing.tests.powerdns.com.'
+        name = "lua-raw-multi.spoofing.tests.powerdns.com."
 
         # A
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1', '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1027,15 +909,11 @@ class TestSpoofingLuaSpoofMulti(DNSDistTest):
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
         # TXT
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        query = dns.message.make_query(name, "TXT", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    '"aaa" "bbbb"', '"ccccccccccc"')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.TXT, '"aaa" "bbbb"', '"ccccccccccc"')
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1046,16 +924,19 @@ class TestSpoofingLuaSpoofMulti(DNSDistTest):
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
         # SRV
-        query = dns.message.make_query(name, 'SRV', 'IN')
+        query = dns.message.make_query(name, "SRV", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         # this one should have the AA flag set
         expectedResponse.flags |= dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.SRV,
-                                    '0 0 65535 srv1.powerdns.com.', '0 0 65535 srv2.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name,
+            3600,
+            dns.rdataclass.IN,
+            dns.rdatatype.SRV,
+            "0 0 65535 srv1.powerdns.com.",
+            "0 0 65535 srv2.powerdns.com.",
+        )
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1064,10 +945,10 @@ class TestSpoofingLuaSpoofMulti(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
             # sorry, we can't set the TTL from the Lua API right now
-            #self.assertEqual(receivedResponse.answer[0].ttl, 3600)
+            # self.assertEqual(receivedResponse.answer[0].ttl, 3600)
 
-class TestSpoofingLuaFFISpoofMulti(DNSDistTest):
 
+class TestSpoofingLuaFFISpoofMulti(DNSDistTest):
     _config_template = """
     local ffi = require("ffi")
 
@@ -1114,18 +995,14 @@ class TestSpoofingLuaFFISpoofMulti(DNSDistTest):
         """
         Spoofing via Lua FFI: Spoof responses from raw bytes via Lua FFI
         """
-        name = 'lua-raw-multi.ffi-spoofing.tests.powerdns.com.'
+        name = "lua-raw-multi.ffi-spoofing.tests.powerdns.com."
 
         # A
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1', '192.0.2.255')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.255")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1136,15 +1013,13 @@ class TestSpoofingLuaFFISpoofMulti(DNSDistTest):
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
         # TXT
-        query = dns.message.make_query(name, 'TXT', 'IN')
+        query = dns.message.make_query(name, "TXT", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags &= ~dns.flags.AA
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    '"this text has a comma at the end,"', '"aaa" "bbbb"')
+        rrset = dns.rrset.from_text(
+            name, 60, dns.rdataclass.IN, dns.rdatatype.TXT, '"this text has a comma at the end,"', '"aaa" "bbbb"'
+        )
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1154,8 +1029,8 @@ class TestSpoofingLuaFFISpoofMulti(DNSDistTest):
             self.checkMessageNoEDNS(expectedResponse, receivedResponse)
             self.assertEqual(receivedResponse.answer[0].ttl, 60)
 
-class TestSpoofingLuaWithStatistics(DNSDistTest):
 
+class TestSpoofingLuaWithStatistics(DNSDistTest):
     _config_template = """
     function spoof1rule(dq)
         queriesCount = getStatisticsCounters()['queries']
@@ -1176,30 +1051,18 @@ class TestSpoofingLuaWithStatistics(DNSDistTest):
         Spoofing: Spoofing an A via Lua based on statistics counters
 
         """
-        name = 'luaspoofwithstats.spoofing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "luaspoofwithstats.spoofing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse1 = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse1.answer.append(rrset)
         expectedResponse2 = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.2')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2")
         expectedResponse2.answer.append(rrset)
         expectedResponseAfterwards = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.0')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.0")
         expectedResponseAfterwards.answer.append(rrset)
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
@@ -1216,8 +1079,8 @@ class TestSpoofingLuaWithStatistics(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(expectedResponseAfterwards, receivedResponse)
 
-class TestSpoofingLuaSpoofPacket(DNSDistTest):
 
+class TestSpoofingLuaSpoofPacket(DNSDistTest):
     _config_template = """
 
     function spoofpacket(dq)
@@ -1255,15 +1118,14 @@ class TestSpoofingLuaSpoofPacket(DNSDistTest):
         """
         Spoofing via Lua FFI: Spoof raw response via Lua
         """
-        for name in ('lua-raw-packet.spoofing.tests.powerdns.com.', 'rule-lua-raw-packet.spoofing.tests.powerdns.com.'):
-
-            query = dns.message.make_query(name, 'A', 'IN')
+        for name in ("lua-raw-packet.spoofing.tests.powerdns.com.", "rule-lua-raw-packet.spoofing.tests.powerdns.com."):
+            query = dns.message.make_query(name, "A", "IN")
             expectedResponse = dns.message.make_response(query)
             expectedResponse.flags |= dns.flags.RA
             expectedResponse.set_rcode(dns.rcode.REFUSED)
 
-            if name == 'rule-lua-raw-packet.spoofing.tests.powerdns.com.':
-                nsid_opt = dns.edns.GenericOption(dns.edns.NSID, 'dnsdist-1'.encode())
+            if name == "rule-lua-raw-packet.spoofing.tests.powerdns.com.":
+                nsid_opt = dns.edns.GenericOption(dns.edns.NSID, "dnsdist-1".encode())
                 expectedResponse.use_edns(options=[nsid_opt])
 
             for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -1271,17 +1133,17 @@ class TestSpoofingLuaSpoofPacket(DNSDistTest):
                 (_, receivedResponse) = sender(query, response=None, useQueue=False)
                 self.assertTrue(receivedResponse)
                 self.assertEqual(expectedResponse, receivedResponse)
-                if name == 'rule-lua-raw-packet.spoofing.tests.powerdns.com.':
+                if name == "rule-lua-raw-packet.spoofing.tests.powerdns.com.":
                     self.checkMessageEDNS(expectedResponse, receivedResponse)
 
     def testLuaFFISpoofPacket(self):
         """
         Spoofing via Lua FFI: Spoof raw response via Lua FFI
         """
-        name = 'lua-raw-packet.ffi-spoofing.tests.powerdns.com.'
+        name = "lua-raw-packet.ffi-spoofing.tests.powerdns.com."
 
         #
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.flags |= dns.flags.RA
         expectedResponse.set_rcode(dns.rcode.REFUSED)
index cc436eb1d5f5b9eb2a0e0b2494acd542b990952c..838d7fede2f7afb77f8f06bca3db8030456540c4 100644 (file)
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class TestStructuredLoggingDefaultBackendFromYaml(DNSDistTest):
 
+class TestStructuredLoggingDefaultBackendFromYaml(DNSDistTest):
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -18,7 +18,7 @@ logging:
 """
     _dnsDistPort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort"]
     _config_params = []
     _checkConfigExpectedOutput = None
     _checkConfigExpectedOutputPrefix = b'msg="Configuration OK" subsystem="setup"'
@@ -26,8 +26,8 @@ logging:
     def testOK(self):
         pass
 
-class TestStructuredLoggingJSONBackendFromYaml(DNSDistTest):
 
+class TestStructuredLoggingJSONBackendFromYaml(DNSDistTest):
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -44,7 +44,7 @@ logging:
 """
     _dnsDistPort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort"]
     _config_params = []
     _checkConfigExpectedOutput = None
     _checkConfigExpectedOutputPrefix = b'{"level": "0", "msg": "Configuration OK", "path":'
@@ -52,8 +52,8 @@ logging:
     def testOK(self):
         pass
 
-class TestStructuredLoggingDefaultBackendFromLua(DNSDistTest):
 
+class TestStructuredLoggingDefaultBackendFromLua(DNSDistTest):
     _config_template = """
 setStructuredLogging(true)
 
@@ -66,8 +66,8 @@ newServer{address="127.0.0.1:%d"}
     def testOK(self):
         pass
 
-class TestStructuredLoggingJSONBackendFromLua(DNSDistTest):
 
+class TestStructuredLoggingJSONBackendFromLua(DNSDistTest):
     _config_template = """
 setStructuredLogging(true, {backend="json"})
 
@@ -81,9 +81,7 @@ newServer{address="127.0.0.1:%d"}
         pass
 
 
-class TestStructuredLoggingDefaultBackendWithInstanceFromYaml(
-    TestStructuredLoggingDefaultBackendFromYaml
-):
+class TestStructuredLoggingDefaultBackendWithInstanceFromYaml(TestStructuredLoggingDefaultBackendFromYaml):
     _yaml_config_template = """---
 general:
   server_id: "foobar"
@@ -104,9 +102,7 @@ logging:
     _checkConfigExpectedOutputPrefix = b'msg="Configuration OK" subsystem="setup"'
 
 
-class TestStructuredLoggingJSONBackendWithInstanceFromYaml(
-    TestStructuredLoggingJSONBackendFromYaml
-):
+class TestStructuredLoggingJSONBackendWithInstanceFromYaml(TestStructuredLoggingJSONBackendFromYaml):
     _yaml_config_template = """---
 general:
   server_id: "foobar"
@@ -125,33 +121,26 @@ logging:
     backend: "json"
     set_instance_from_server_id: true
 """
-    _checkConfigExpectedOutputPrefix = (
-        b'{"instance": "foobar", "level": "0", "msg": "Configuration OK", "path":'
-    )
+    _checkConfigExpectedOutputPrefix = b'{"instance": "foobar", "level": "0", "msg": "Configuration OK", "path":'
 
 
-class TestStructuredLoggingDefaultBackendWithInstanceFromLua(
-    TestStructuredLoggingDefaultBackendFromLua
-):
+class TestStructuredLoggingDefaultBackendWithInstanceFromLua(TestStructuredLoggingDefaultBackendFromLua):
     _config_template = """
 setServerID("foobar")
 setStructuredLogging(true, {setInstanceFromServerID=true})
 
 newServer{address="127.0.0.1:%d"}
 """
-    _checkConfigExpectedOutputPrefix = b'msg="Configuration OK" subsystem="setup" level="0" prio="Info" instance="foobar" ts='
-
+    _checkConfigExpectedOutputPrefix = (
+        b'msg="Configuration OK" subsystem="setup" level="0" prio="Info" instance="foobar" ts='
+    )
 
-class TestStructuredLoggingJSONBackendWithInstanceFromLua(
-    TestStructuredLoggingJSONBackendFromLua
-):
 
+class TestStructuredLoggingJSONBackendWithInstanceFromLua(TestStructuredLoggingJSONBackendFromLua):
     _config_template = """
 setServerID("foobar")
 setStructuredLogging(true, {backend="json", setInstanceFromServerID=true})
 
 newServer{address="127.0.0.1:%d"}
 """
-    _checkConfigExpectedOutputPrefix = (
-        b'{"instance": "foobar", "level": "0", "msg": "Configuration OK", "path":'
-    )
+    _checkConfigExpectedOutputPrefix = b'{"instance": "foobar", "level": "0", "msg": "Configuration OK", "path":'
index 32b18ed9a3845cbfc5772f3af267c5e3e9cab4eb..76a387da57e603981e32591acf32f21212637df7 100644 (file)
@@ -6,8 +6,8 @@ import socket
 import struct
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class TestBrokenTCPFastOpen(DNSDistTest):
 
+class TestBrokenTCPFastOpen(DNSDistTest):
     # this test suite uses a different responder port
     # because, contrary to the other ones, its
     # TCP responder will accept a connection, read the
@@ -16,11 +16,21 @@ class TestBrokenTCPFastOpen(DNSDistTest):
     _testServerRetries = 5
     _webTimeout = 2.0
     _webServerPort = pickAvailablePort()
-    _webServerBasicAuthPassword = 'secret'
-    _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
-    _webServerAPIKey = 'apisecret'
-    _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
-    _config_params = ['_testServerPort', '_testServerRetries', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+    _webServerBasicAuthPassword = "secret"
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKey = "apisecret"
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
+    _config_params = [
+        "_testServerPort",
+        "_testServerRetries",
+        "_webServerPort",
+        "_webServerBasicAuthPasswordHashed",
+        "_webServerAPIKeyHashed",
+    ]
     _config_template = """
     newServer{address="127.0.0.1:%d", useClientSubnet=true, tcpFastOpen=true, retries=%d }
     webserver("127.0.0.1:%d")
@@ -69,12 +79,18 @@ class TestBrokenTCPFastOpen(DNSDistTest):
         print("Launching responders..")
 
         # Normal responder
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
 
         # Close the connection right after reading the query
-        cls._TCPResponder = threading.Thread(name='Broken TCP Responder', target=cls.BrokenTCPResponder, args=[cls._testServerPort])
+        cls._TCPResponder = threading.Thread(
+            name="Broken TCP Responder", target=cls.BrokenTCPResponder, args=[cls._testServerPort]
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
@@ -82,21 +98,21 @@ class TestBrokenTCPFastOpen(DNSDistTest):
         """
         TCP Fast Open: Close after read
         """
-        name = 'close-after-read.tfo.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "close-after-read.tfo.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
         self.assertFalse(receivedQuery)
         self.assertFalse(receivedResponse)
 
-        headers = {'x-api-key': self._webServerAPIKey}
-        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost'
+        headers = {"x-api-key": self._webServerAPIKey}
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        self.assertTrue(len(content['servers']), 1)
-        server = content['servers'][0]
-        self.assertIn('tcpDiedReadingResponse', server)
-        self.assertEqual(server['tcpDiedReadingResponse'], self._testServerRetries)
+        self.assertTrue(len(content["servers"]), 1)
+        server = content["servers"][0]
+        self.assertIn("tcpDiedReadingResponse", server)
+        self.assertEqual(server["tcpDiedReadingResponse"], self._testServerRetries)
index caec584d4b1ab27991027c20cf4c2463d8ab818b..ca3ebdfca5870a93a8f8ad347f6f5a35dc875ed7 100644 (file)
@@ -7,6 +7,7 @@ try:
 except NameError:
     pass
 
+
 class TestTCPKeepAlive(DNSDistTest):
     """
     These tests make sure that dnsdist keeps the TCP connection alive
@@ -35,14 +36,20 @@ class TestTCPKeepAlive(DNSDistTest):
     addAction("nodownstream-servfail.tcpka.tests.powerdns.com.", PoolAction("nosuchpool"))
     setServFailWhenNoServer(true)
     """
-    _config_params = ['_testServerPort', '_tcpIdleTimeout', '_maxTCPQueriesPerConn', '_maxTCPConnsPerClient', '_maxTCPConnDuration']
+    _config_params = [
+        "_testServerPort",
+        "_tcpIdleTimeout",
+        "_maxTCPQueriesPerConn",
+        "_maxTCPConnsPerClient",
+        "_maxTCPConnDuration",
+    ]
 
     def testTCPKaSelfGenerated(self):
         """
         TCP KeepAlive: Self-generated answer
         """
-        name = 'refused.tcpka.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "refused.tcpka.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -68,14 +75,10 @@ class TestTCPKeepAlive(DNSDistTest):
         """
         TCP KeepAlive: Cache Hit
         """
-        name = 'cachehit.tcpka.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "cachehit.tcpka.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         # first query to fill the cache
@@ -111,8 +114,8 @@ class TestTCPKeepAlive(DNSDistTest):
         and dnsdist is configured to send a ServFail when
         that happens. We should keep the TCP connection open.
         """
-        name = 'nodownstream-servfail.tcpka.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nodownstream-servfail.tcpka.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.SERVFAIL)
 
@@ -137,8 +140,8 @@ class TestTCPKeepAlive(DNSDistTest):
         """
         TCP KeepAlive: QR bit set in question
         """
-        name = 'qrset.tcpka.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "qrset.tcpka.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags |= dns.flags.QR
 
         conn = self.openTCPConnection()
@@ -161,8 +164,8 @@ class TestTCPKeepAlive(DNSDistTest):
         """
         TCP KeepAlive: Drop
         """
-        name = 'dropped.tcpka.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "dropped.tcpka.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags |= dns.flags.QR
 
         conn = self.openTCPConnection()
@@ -185,8 +188,8 @@ class TestTCPKeepAlive(DNSDistTest):
         """
         TCP KeepAlive: Drop Response
         """
-        name = 'dropped-response.tcpka.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "dropped-response.tcpka.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         conn = self.openTCPConnection()
 
@@ -208,15 +211,11 @@ class TestTCPKeepAlive(DNSDistTest):
         """
         TCP KeepAlive: Large number of connections
         """
-        name = 'largernumberofconnections.tcpka.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "largernumberofconnections.tcpka.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        #expectedResponse.set_rcode(dns.rcode.SERVFAIL)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        # expectedResponse.set_rcode(dns.rcode.SERVFAIL)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         # number of connections
@@ -242,10 +241,11 @@ class TestTCPKeepAlive(DNSDistTest):
                 pass
 
         for conn in conns:
-          conn.close()
+            conn.close()
 
         self.assertEqual(count, numConns * numQueriesPerConn)
 
+
 class TestTCPKeepAliveNoDownstreamDrop(DNSDistTest):
     """
     This test makes sure that dnsdist drops the TCP connection
@@ -267,7 +267,13 @@ class TestTCPKeepAliveNoDownstreamDrop(DNSDistTest):
     getPool("nosuchpool")
     addAction("nodownstream-drop.tcpka.tests.powerdns.com.", PoolAction("nosuchpool"))
     """
-    _config_params = ['_testServerPort', '_tcpIdleTimeout', '_maxTCPQueriesPerConn', '_maxTCPConnsPerClient', '_maxTCPConnDuration']
+    _config_params = [
+        "_testServerPort",
+        "_tcpIdleTimeout",
+        "_maxTCPQueriesPerConn",
+        "_maxTCPConnsPerClient",
+        "_maxTCPConnDuration",
+    ]
 
     def testTCPKaNoDownstreamDrop(self):
         """
@@ -277,8 +283,8 @@ class TestTCPKeepAliveNoDownstreamDrop(DNSDistTest):
         and dnsdist is configured to drop the query when
         that happens. We should close the TCP connection right away.
         """
-        name = 'nodownstream-drop.tcpka.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nodownstream-drop.tcpka.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
 
         conn = self.openTCPConnection()
 
index cb81265fcc954ee6eb08799645e3aab9cb2069a1..d304ef6383a3ce339eb43b6be668d165d9e3706a 100644 (file)
@@ -6,12 +6,12 @@ import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
 try:
-  range = xrange
+    range = xrange
 except NameError:
-  pass
+    pass
 
-class TestTCPLimits(DNSDistTest):
 
+class TestTCPLimits(DNSDistTest):
     # this test suite uses a different responder port
     # because it uses a different health check configuration
     _testServerPort = pickAvailablePort()
@@ -33,14 +33,20 @@ class TestTCPLimits(DNSDistTest):
     -- test gets us banned very quickly
     setMaxTCPReadIOsPerQuery(0)
     """
-    _config_params = ['_testServerPort', '_tcpIdleTimeout', '_maxTCPQueriesPerConn', '_maxTCPConnsPerClient', '_maxTCPConnDuration']
+    _config_params = [
+        "_testServerPort",
+        "_tcpIdleTimeout",
+        "_maxTCPQueriesPerConn",
+        "_maxTCPConnsPerClient",
+        "_maxTCPConnDuration",
+    ]
 
     def testTCPQueriesPerConn(self):
         """
         TCP Limits: Maximum number of queries
         """
-        name = 'maxqueriesperconn.tcp.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "maxqueriesperconn.tcp.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         conn = self.openTCPConnection()
 
         count = 0
@@ -74,8 +80,8 @@ class TestTCPLimits(DNSDistTest):
         """
         TCP Limits: Maximum number of conns per client
         """
-        name = 'maxconnsperclient.tcp.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "maxconnsperclient.tcp.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         conns = []
 
         for idx in range(self._maxTCPConnsPerClient + 1):
@@ -121,7 +127,7 @@ class TestTCPLimits(DNSDistTest):
                 # sleeping for only one second keeps us below the
                 # idle timeout (setTCPRecvTimeout())
                 time.sleep(0.1)
-                conn.send(b'A')
+                conn.send(b"A")
                 count = count + 1
             except Exception as e:
                 print("Exception: %s!" % (e))
@@ -134,8 +140,8 @@ class TestTCPLimits(DNSDistTest):
 
         conn.close()
 
-class TestTCPLimitsReadIO(DNSDistTest):
 
+class TestTCPLimitsReadIO(DNSDistTest):
     # separate test suite because we get banned for a few seconds
     _testServerPort = pickAvailablePort()
     _answerUnexpected = True
@@ -151,14 +157,14 @@ class TestTCPLimitsReadIO(DNSDistTest):
     -- disable "near limits" otherwise our tests are broken because connections are forcibly closed
     setTCPConnectionsOverloadThreshold(0)
     """
-    _config_params = ['_testServerPort', '_tcpIdleTimeout', '_maxTCPReadIOsPerQuery', '_banDuration']
+    _config_params = ["_testServerPort", "_tcpIdleTimeout", "_maxTCPReadIOsPerQuery", "_banDuration"]
 
     def testTCPMaxReadIOsPerQuery(self):
         """
         TCP Limits: Maximum number of IO read events per query
         """
-        name = 'maxreadios.tcp.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "maxreadios.tcp.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         payload = query.to_wire()
         self.assertGreater(len(payload), self._maxTCPReadIOsPerQuery)
 
@@ -180,7 +186,7 @@ class TestTCPLimitsReadIO(DNSDistTest):
             try:
                 response = self.recvTCPResponseOverConnection(conn)
                 if not response:
-                  failed = True
+                    failed = True
             except Exception:
                 failed = True
 
@@ -193,7 +199,7 @@ class TestTCPLimitsReadIO(DNSDistTest):
             conn = self.openTCPConnection()
             response = self.recvTCPResponseOverConnection(conn)
             if response is None:
-              failed = True
+                failed = True
         except Exception:
             failed = True
         finally:
@@ -201,8 +207,8 @@ class TestTCPLimitsReadIO(DNSDistTest):
 
         self.assertTrue(failed)
 
-class TestTCPLimitsConnectionRate(DNSDistTest):
 
+class TestTCPLimitsConnectionRate(DNSDistTest):
     # separate test suite because we get banned for a few seconds
     _testServerPort = pickAvailablePort()
     _answerUnexpected = True
@@ -217,15 +223,15 @@ class TestTCPLimitsConnectionRate(DNSDistTest):
     -- disable "near limits" otherwise our tests are broken because connections are forcibly closed
     setTCPConnectionsOverloadThreshold(0)
     """
-    _config_params = ['_testServerPort', '_tcpIdleTimeout', '_maxConnectionRate', '_banDuration']
+    _config_params = ["_testServerPort", "_tcpIdleTimeout", "_maxConnectionRate", "_banDuration"]
     _verboseMode = True
 
     def testTCPConnectionRate(self):
         """
         TCP Limits: Maximum connection rate
         """
-        name = 'maxconnectionrate.tcp.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "maxconnectionrate.tcp.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         # _maxConnectionRate connections in a row
@@ -239,6 +245,7 @@ class TestTCPLimitsConnectionRate(DNSDistTest):
         self.assertEqual(receivedQuery, None)
         self.assertEqual(receivedResponse, None)
 
+
 class TestTCPLimitsTLSNewSessionRate(DNSDistTest):
     # separate test suite because we get banned for a few seconds
     _testServerPort = pickAvailablePort()
@@ -247,10 +254,10 @@ class TestTCPLimitsTLSNewSessionRate(DNSDistTest):
     _maxNewTLSSessionRate = 10
     _tcpIdleTimeout = 2
     _banDuration = 2
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     setTCPRecvTimeout(%d)
@@ -261,15 +268,23 @@ class TestTCPLimitsTLSNewSessionRate(DNSDistTest):
     -- disable "near limits" otherwise our tests are broken because connections are forcibly closed
     setTCPConnectionsOverloadThreshold(0)
     """
-    _config_params = ['_testServerPort', '_tcpIdleTimeout', '_maxNewTLSSessionRate', '_banDuration', '_tlsServerPort', '_serverCert', '_serverKey']
+    _config_params = [
+        "_testServerPort",
+        "_tcpIdleTimeout",
+        "_maxNewTLSSessionRate",
+        "_banDuration",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
     _verboseMode = True
 
     def testTLSNewSessionRate(self):
         """
         TCP Limits: Maximum TLS new session rate
         """
-        name = 'maxtlsnewsessionrate.tcp.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "maxtlsnewsessionrate.tcp.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         # _maxNewTLSSessionRate connections in a row, plus one because
@@ -285,7 +300,8 @@ class TestTCPLimitsTLSNewSessionRate(DNSDistTest):
             self.sendDOTQueryWrapper(query, response=None, useQueue=False)
             self.fail()
         except ConnectionResetError:
-          pass
+            pass
+
 
 class TestTCPLimitsTLSResumedSessionRate(DNSDistTest):
     # separate test suite because we get banned for a few seconds
@@ -296,10 +312,10 @@ class TestTCPLimitsTLSResumedSessionRate(DNSDistTest):
     _maxResumedTLSSessionRate = 10
     _tcpIdleTimeout = 2
     _banDuration = 2
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     setTCPRecvTimeout(%d)
@@ -311,15 +327,24 @@ class TestTCPLimitsTLSResumedSessionRate(DNSDistTest):
     -- disable "near limits" otherwise our tests are broken because connections are forcibly closed
     setTCPConnectionsOverloadThreshold(0)
     """
-    _config_params = ['_testServerPort', '_tcpIdleTimeout', '_maxNewTLSSessionRate', '_maxResumedTLSSessionRate', '_banDuration', '_tlsServerPort', '_serverCert', '_serverKey']
+    _config_params = [
+        "_testServerPort",
+        "_tcpIdleTimeout",
+        "_maxNewTLSSessionRate",
+        "_maxResumedTLSSessionRate",
+        "_banDuration",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
     _verboseMode = True
 
     def testTLSResumedSessionRate(self):
         """
         TCP Limits: Maximum TLS resumed session rate
         """
-        name = 'maxtlsresumedsessionrate.tcp.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "maxtlsresumedsessionrate.tcp.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         session = None
@@ -329,7 +354,9 @@ class TestTCPLimitsTLSResumedSessionRate(DNSDistTest):
         # - the first one is a new TLS session
         # - the session is only accounted for once the handshake has been completed
         for idx in range(self._maxResumedTLSSessionRate + 2):
-            conn = self.openTLSConnection(self._tlsServerPort, self._serverName, self._caCert, timeout=1, sslctx=sslctx, session=session)
+            conn = self.openTLSConnection(
+                self._tlsServerPort, self._serverName, self._caCert, timeout=1, sslctx=sslctx, session=session
+            )
             self.sendTCPQueryOverConnection(conn, query, response=response, timeout=1)
             (receivedQuery, receivedResponse) = self.recvTCPResponseOverConnection(conn, useQueue=True, timeout=1)
             receivedQuery.id = query.id
@@ -343,15 +370,17 @@ class TestTCPLimitsTLSResumedSessionRate(DNSDistTest):
 
         try:
             # the next one should be past the max rate
-            conn = self.openTLSConnection(self._tlsServerPort, self._serverName, self._caCert, timeout=1, sslctx=sslctx, session=session)
+            conn = self.openTLSConnection(
+                self._tlsServerPort, self._serverName, self._caCert, timeout=1, sslctx=sslctx, session=session
+            )
             self.sendTCPQueryOverConnection(conn, query, response=response, timeout=1)
             self.recvTCPResponseOverConnection(conn, useQueue=True, timeout=1)
             self.fail()
         except ConnectionResetError:
-          pass
+            pass
 
-class TestTCPFrontendLimits(DNSDistTest):
 
+class TestTCPFrontendLimits(DNSDistTest):
     # this test suite uses a different responder port
     # because it uses a different health check configuration
     _testServerPort = pickAvailablePort()
@@ -366,14 +395,14 @@ class TestTCPFrontendLimits(DNSDistTest):
     -- disable "near limits" otherwise our tests are broken because connections are forcibly closed
     setTCPConnectionsOverloadThreshold(0)
     """
-    _config_params = ['_testServerPort', '_dnsDistListeningAddr', '_dnsDistPort', '_maxTCPConnsPerFrontend']
+    _config_params = ["_testServerPort", "_dnsDistListeningAddr", "_dnsDistPort", "_maxTCPConnsPerFrontend"]
 
     def testTCPConnsPerFrontend(self):
         """
         TCP Frontend Limits: Maximum number of conns per frontend
         """
-        name = 'maxconnsperfrontend.tcp.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "maxconnsperfrontend.tcp.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         conns = []
 
         for idx in range(self._maxTCPConnsPerFrontend + 1):
index 34886a9af937fcdb5b184639c4e49aa1f7758c34..e7b42125fb5404adacab30e75c8ce0fe763da0fc 100644 (file)
@@ -3,8 +3,8 @@ import dns
 
 from dnsdisttests import DNSDistTest
 
-class TestTCPOnly(DNSDistTest):
 
+class TestTCPOnly(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d", tcpOnly=true}
     """
@@ -13,14 +13,10 @@ class TestTCPOnly(DNSDistTest):
         """
         TCP Only: UDP query is sent via TCP
         """
-        name = 'udp.tcp-only.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.tcp-only.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
@@ -28,30 +24,26 @@ class TestTCPOnly(DNSDistTest):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, expectedResponse)
 
-        if 'UDP Responder' in self._responsesCounter:
-            self.assertEqual(self._responsesCounter['UDP Responder'], 0)
-        if 'TCP Responder' in self._responsesCounter:
-            self.assertEqual(self._responsesCounter['TCP Responder'], 1)
+        if "UDP Responder" in self._responsesCounter:
+            self.assertEqual(self._responsesCounter["UDP Responder"], 0)
+        if "TCP Responder" in self._responsesCounter:
+            self.assertEqual(self._responsesCounter["TCP Responder"], 1)
 
     def testTCP(self):
         """
         TCP Only: TCP query is sent via TCP
         """
-        name = 'tcp.tcp-only.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tcp.tcp-only.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, expectedResponse)
         receivedQuery.id = query.id
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, expectedResponse)
-        if 'UDP Responder' in self._responsesCounter:
-            self.assertEqual(self._responsesCounter['UDP Responder'], 0)
-        if 'TCP Responder' in self._responsesCounter:
-            self.assertEqual(self._responsesCounter['TCP Responder'], 1)
+        if "UDP Responder" in self._responsesCounter:
+            self.assertEqual(self._responsesCounter["UDP Responder"], 0)
+        if "TCP Responder" in self._responsesCounter:
+            self.assertEqual(self._responsesCounter["TCP Responder"], 1)
index f11f5984489bb19025af52f1ff36d473875c99e8..2093a973dbba749116f472a974ad2f43cf6e444f 100644 (file)
@@ -6,9 +6,10 @@ import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
 try:
-  range = xrange
+    range = xrange
 except NameError:
-  pass
+    pass
+
 
 class TestTCPShort(DNSDistTest):
     # this test suite uses a different responder port
@@ -16,10 +17,10 @@ class TestTCPShort(DNSDistTest):
     # responders allow trailing data and multiple responses,
     # and we don't want to mix things up.
     _testServerPort = pickAvailablePort()
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _tcpSendTimeout = 60
     _config_template = """
@@ -27,17 +28,25 @@ class TestTCPShort(DNSDistTest):
     addTLSLocal("127.0.0.1:%d", "%s", "%s")
     setTCPSendTimeout(%d)
     """
-    _config_params = ['_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_tcpSendTimeout']
+    _config_params = ["_testServerPort", "_tlsServerPort", "_serverCert", "_serverKey", "_tcpSendTimeout"]
 
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
 
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, True])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, True],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, True, True])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, True, True],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
@@ -45,14 +54,10 @@ class TestTCPShort(DNSDistTest):
         """
         TCP: Short read from client
         """
-        name = 'short-read.tcp-short.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "short-read.tcp-short.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         conn = self.openTCPConnection()
@@ -60,7 +65,7 @@ class TestTCPShort(DNSDistTest):
         # announce 7680 bytes (more than 4096, less than 8192 - the 512 bytes dnsdist is going to add)
         announcedSize = 7680
         paddingSize = announcedSize - len(wire)
-        wire = wire + (b'A' * (paddingSize - 1))
+        wire = wire + (b"A" * (paddingSize - 1))
         self._toResponderQueue.put(expectedResponse, True, 2.0)
 
         sizeBytes = struct.pack("!H", announcedSize)
@@ -71,7 +76,7 @@ class TestTCPShort(DNSDistTest):
         conn.send(wire)
         time.sleep(1)
         # send the remaining byte
-        conn.send(b'A')
+        conn.send(b"A")
 
         (receivedQuery, receivedResponse) = self.recvTCPResponseOverConnection(conn, True)
         conn.close()
@@ -86,14 +91,10 @@ class TestTCPShort(DNSDistTest):
         """
         TCP/TLS: Short read from client
         """
-        name = 'short-read-tls.tcp-short.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "short-read-tls.tcp-short.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         expectedResponse.answer.append(rrset)
 
         conn = self.openTLSConnection(self._tlsServerPort, self._serverName, self._caCert)
@@ -101,7 +102,7 @@ class TestTCPShort(DNSDistTest):
         # announce 7680 bytes (more than 4096, less than 8192 - the 512 bytes dnsdist is going to add)
         announcedSize = 7680
         paddingSize = announcedSize - len(wire)
-        wire = wire + (b'A' * (paddingSize - 1))
+        wire = wire + (b"A" * (paddingSize - 1))
         self._toResponderQueue.put(expectedResponse, True, 2.0)
 
         sizeBytes = struct.pack("!H", announcedSize)
@@ -112,7 +113,7 @@ class TestTCPShort(DNSDistTest):
         conn.send(wire)
         time.sleep(1)
         # send the remaining byte
-        conn.send(b'A')
+        conn.send(b"A")
 
         (receivedQuery, receivedResponse) = self.recvTCPResponseOverConnection(conn, True)
         conn.close()
@@ -127,17 +128,19 @@ class TestTCPShort(DNSDistTest):
         """
         TCP: Short write to client
         """
-        name = 'short-write.tcp-short.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AXFR', 'IN')
+        name = "short-write.tcp-short.tests.powerdns.com."
+        query = dns.message.make_query(name, "AXFR", "IN")
 
         # we prepare a large AXFR answer
         # SOA + 200 dns messages of one huge TXT RRset each + SOA
         responses = []
-        soa = dns.rrset.from_text(name,
-                                  60,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
 
         soaResponse = dns.message.make_response(query)
         soaResponse.use_edns(edns=False)
@@ -149,14 +152,10 @@ class TestTCPShort(DNSDistTest):
         content = ""
         for i in range(200):
             if len(content) > 0:
-                content = content + ', '
-            content = content + (str(i)*50)
-
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    content)
+                content = content + ", "
+            content = content + (str(i) * 50)
+
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, content)
         response.answer.append(rrset)
 
         for _ in range(200):
@@ -184,7 +183,7 @@ class TestTCPShort(DNSDistTest):
                 break
 
             (datalen,) = struct.unpack("!H", datalen)
-            data = b''
+            data = b""
             remaining = datalen
             got = conn.recv(remaining)
             while got:
@@ -217,14 +216,16 @@ class TestTCPShort(DNSDistTest):
         TCP/TLS: Short write to client
         """
         # same as testTCPShortWrite but over TLS this time
-        name = 'short-write-tls.tcp-short.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AXFR', 'IN')
+        name = "short-write-tls.tcp-short.tests.powerdns.com."
+        query = dns.message.make_query(name, "AXFR", "IN")
         responses = []
-        soa = dns.rrset.from_text(name,
-                                  60,
-                                  dns.rdataclass.IN,
-                                  dns.rdatatype.SOA,
-                                  'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60')
+        soa = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.SOA,
+            "ns." + name + " hostmaster." + name + " 1 3600 3600 3600 60",
+        )
 
         soaResponse = dns.message.make_response(query)
         soaResponse.use_edns(edns=False)
@@ -236,14 +237,10 @@ class TestTCPShort(DNSDistTest):
         content = ""
         for i in range(200):
             if len(content) > 0:
-                content = content + ', '
-            content = content + (str(i)*50)
-
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    content)
+                content = content + ", "
+            content = content + (str(i) * 50)
+
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, content)
         response.answer.append(rrset)
 
         for _ in range(200):
@@ -267,7 +264,7 @@ class TestTCPShort(DNSDistTest):
                 break
 
             (datalen,) = struct.unpack("!H", datalen)
-            data = b''
+            data = b""
             remaining = datalen
             got = conn.recv(remaining)
             while got:
index cbf3be16bf2848dcb09c7b999c877243e9d15ad9..7d3b5649ad56dc2a3e2cf2795b53630faccee00d 100644 (file)
@@ -9,8 +9,8 @@ import string
 
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class TLSTests(object):
 
+class TLSTests(object):
     def getServerCertificate(self):
         conn = self.openTLSConnection(self._tlsServerPort, self._serverName, self._caCert)
         cert = conn.getpeercert()
@@ -24,14 +24,10 @@ class TLSTests(object):
         """
         TLS: Single query
         """
-        name = 'single.tls.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "single.tls.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         conn = self.openTLSConnection(self._tlsServerPort, self._serverName, self._caCert)
@@ -46,20 +42,20 @@ class TLSTests(object):
 
         # check the certificate
         cert = self.getServerCertificate()
-        self.assertIn('subject', cert)
-        self.assertIn('serialNumber', cert)
-        self.assertIn('subjectAltName', cert)
-        subject = cert['subject']
-        altNames = cert['subjectAltName']
-        self.assertEqual(dict(subject[0])['commonName'], 'tls.tests.dnsdist.org')
-        self.assertEqual(dict(subject[1])['organizationalUnitName'], 'PowerDNS.com BV')
+        self.assertIn("subject", cert)
+        self.assertIn("serialNumber", cert)
+        self.assertIn("subjectAltName", cert)
+        subject = cert["subject"]
+        altNames = cert["subjectAltName"]
+        self.assertEqual(dict(subject[0])["commonName"], "tls.tests.dnsdist.org")
+        self.assertEqual(dict(subject[1])["organizationalUnitName"], "PowerDNS.com BV")
         names = []
         for entry in altNames:
             names.append(entry[1])
-        self.assertEqual(names, ['tls.tests.dnsdist.org', 'powerdns.com', '127.0.0.1'])
-        serialNumber = cert['serialNumber']
+        self.assertEqual(names, ["tls.tests.dnsdist.org", "powerdns.com", "127.0.0.1"])
+        serialNumber = cert["serialNumber"]
 
-        self.generateNewCertificateAndKey('server-tls')
+        self.generateNewCertificateAndKey("server-tls")
         self.sendConsoleCommand("reloadAllCertificates()")
 
         conn.close()
@@ -76,34 +72,30 @@ class TLSTests(object):
 
         # check that the certificate is OK
         cert = self.getServerCertificate()
-        self.assertIn('subject', cert)
-        self.assertIn('serialNumber', cert)
-        self.assertIn('subjectAltName', cert)
-        subject = cert['subject']
-        altNames = cert['subjectAltName']
-        self.assertEqual(dict(subject[0])['commonName'], 'tls.tests.dnsdist.org')
-        self.assertEqual(dict(subject[1])['organizationalUnitName'], 'PowerDNS.com BV')
+        self.assertIn("subject", cert)
+        self.assertIn("serialNumber", cert)
+        self.assertIn("subjectAltName", cert)
+        subject = cert["subject"]
+        altNames = cert["subjectAltName"]
+        self.assertEqual(dict(subject[0])["commonName"], "tls.tests.dnsdist.org")
+        self.assertEqual(dict(subject[1])["organizationalUnitName"], "PowerDNS.com BV")
         names = []
         for entry in altNames:
             names.append(entry[1])
-        self.assertEqual(names, ['tls.tests.dnsdist.org', 'powerdns.com', '127.0.0.1'])
+        self.assertEqual(names, ["tls.tests.dnsdist.org", "powerdns.com", "127.0.0.1"])
 
         # and that the serial is different
-        self.assertNotEqual(serialNumber, cert['serialNumber'])
+        self.assertNotEqual(serialNumber, cert["serialNumber"])
         conn.close()
 
     def testTLKA(self):
         """
         TLS: Several queries over the same connection
         """
-        name = 'ka.tls.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "ka.tls.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         conn = self.openTLSConnection(self._tlsServerPort, self._serverName, self._caCert)
@@ -123,14 +115,10 @@ class TLSTests(object):
         """
         TLS: Several queries over the same connection without waiting for the responses
         """
-        name = 'pipelining.tls.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "pipelining.tls.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         conn = self.openTLSConnection(self._tlsServerPort, self._serverName, self._caCert)
@@ -152,26 +140,18 @@ class TLSTests(object):
         """
         TLS: SNI Routing
         """
-        name = 'sni.tls.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "sni.tls.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.4')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4")
         expectedResponse.answer.append(rrset)
 
         # this SNI should match so we should get a spoofed answer
-        conn = self.openTLSConnection(self._tlsServerPort, 'powerdns.com', self._caCert)
+        conn = self.openTLSConnection(self._tlsServerPort, "powerdns.com", self._caCert)
 
         self.sendTCPQueryOverConnection(conn, query, response=None)
         receivedResponse = self.recvTCPResponseOverConnection(conn, useQueue=False)
@@ -197,22 +177,14 @@ class TLSTests(object):
         """
         TLS: SNI Routing after resumption
         """
-        name = 'sni-resumed.tls.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "sni-resumed.tls.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.4')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4")
         expectedResponse.answer.append(rrset)
 
         # this SNI should match so we should get a spoofed answer
@@ -224,7 +196,7 @@ class TLSTests(object):
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
         sock.settimeout(2.0)
-        sslsock = sslctx.wrap_socket(sock, server_hostname='powerdns.com')
+        sslsock = sslctx.wrap_socket(sock, server_hostname="powerdns.com")
         sslsock.connect(("127.0.0.1", self._tlsServerPort))
 
         self.sendTCPQueryOverConnection(sslsock, query, response=None)
@@ -254,7 +226,7 @@ class TLSTests(object):
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
         sock.settimeout(2.0)
-        sslsock = sslctx.wrap_socket(sock, server_hostname='powerdns.com')
+        sslsock = sslctx.wrap_socket(sock, server_hostname="powerdns.com")
         sslsock.session = session
         sslsock.connect(("127.0.0.1", self._tlsServerPort))
 
@@ -264,17 +236,17 @@ class TLSTests(object):
         self.assertEqual(expectedResponse, receivedResponse)
         self.assertTrue(sslsock.session_reused)
 
-class TestOpenSSL(DNSDistTest, TLSTests):
 
+class TestOpenSSL(DNSDistTest, TLSTests):
     _extraStartupSleep = 1
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _serverKey = 'server-tls.key'
-    _serverCert = 'server-tls.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _serverIPOnlyKey = 'server-ip-only.key'
-    _serverIPOnlyCert = 'server-ip-only.chain'
-    _caCert = 'ca.pem'
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _serverKey = "server-tls.key"
+    _serverCert = "server-tls.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _serverIPOnlyKey = "server-ip-only.key"
+    _serverIPOnlyCert = "server-ip-only.chain"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _tlsServerPort2 = pickAvailablePort()
     _config_template = """
@@ -286,11 +258,21 @@ class TestOpenSSL(DNSDistTest, TLSTests):
     addTLSLocal("127.0.0.1:%d", "%s", "%s", { provider="openssl" })
     addAction(SNIRule("powerdns.com"), SpoofAction("1.2.3.4"))
     """
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_tlsServerPort2', '_serverIPOnlyCert', '_serverIPOnlyKey']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_tlsServerPort2",
+        "_serverIPOnlyCert",
+        "_serverIPOnlyKey",
+    ]
 
     @classmethod
     def setUpClass(cls):
-        cls.generateNewCertificateAndKey('server-tls')
+        cls.generateNewCertificateAndKey("server-tls")
         cls.startResponders()
         cls.startDNSDist()
         cls.setUpSockets()
@@ -298,16 +280,16 @@ class TestOpenSSL(DNSDistTest, TLSTests):
     def testProvider(self):
         self.assertEqual(self.getTLSProvider(), "openssl")
 
-class TestGnuTLS(DNSDistTest, TLSTests):
 
+class TestGnuTLS(DNSDistTest, TLSTests):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _serverKey = 'server-tls.key'
-    _serverCert = 'server-tls.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _serverIPOnlyKey = 'server-ip-only.key'
-    _serverIPOnlyCert = 'server-ip-only.chain'
-    _caCert = 'ca.pem'
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _serverKey = "server-tls.key"
+    _serverCert = "server-tls.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _serverIPOnlyKey = "server-ip-only.key"
+    _serverIPOnlyCert = "server-ip-only.chain"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _tlsServerPort2 = pickAvailablePort()
     _config_template = """
@@ -319,11 +301,21 @@ class TestGnuTLS(DNSDistTest, TLSTests):
     addTLSLocal("127.0.0.1:%d", "%s", "%s", { provider="gnutls" })
     addAction(SNIRule("powerdns.com"), SpoofAction("1.2.3.4"))
     """
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_tlsServerPort2', '_serverIPOnlyCert', '_serverIPOnlyKey']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+        "_tlsServerPort2",
+        "_serverIPOnlyCert",
+        "_serverIPOnlyKey",
+    ]
 
     @classmethod
     def setUpClass(cls):
-        cls.generateNewCertificateAndKey('server-tls')
+        cls.generateNewCertificateAndKey("server-tls")
         cls.startResponders()
         cls.startDNSDist()
         cls.setUpSockets()
@@ -331,15 +323,15 @@ class TestGnuTLS(DNSDistTest, TLSTests):
     def testProvider(self):
         self.assertEqual(self.getTLSProvider(), "gnutls")
 
-class TestOpenSSLYaml(DNSDistTest, TLSTests):
 
+class TestOpenSSLYaml(DNSDistTest, TLSTests):
     _extraStartupSleep = 1
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _serverKey = 'server-tls.key'
-    _serverCert = 'server-tls.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _serverKey = "server-tls.key"
+    _serverCert = "server-tls.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _config_template = ""
     _config_params = []
@@ -371,11 +363,18 @@ query_rules:
       ips:
         - "1.2.3.4"
     """
-    _yaml_config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey']
+    _yaml_config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
 
     @classmethod
     def setUpClass(cls):
-        cls.generateNewCertificateAndKey('server-tls')
+        cls.generateNewCertificateAndKey("server-tls")
         cls.startResponders()
         cls.startDNSDist()
         cls.setUpSockets()
@@ -383,11 +382,12 @@ query_rules:
     def testProvider(self):
         self.assertEqual(self.getTLSProvider(), "openssl")
 
+
 class TestDOTWithCache(DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _config_template = """
     newServer{address="127.0.0.1:%d"}
@@ -397,33 +397,29 @@ class TestDOTWithCache(DNSDistTest):
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
     """
-    _config_params = ['_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_tlsServerPort", "_serverCert", "_serverKey"]
 
     def testDOTCacheLargeAnswer(self):
         """
         DOT with cache: Check that we can cache (and retrieve) large answers
         """
         numberOfQueries = 10
-        name = 'large.dot-with-cache.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        name = "large.dot-with-cache.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN", use_edns=False)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+        expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, payload=4096)
         expectedQuery.id = 0
         response = dns.message.make_response(query)
         # we prepare a large answer
         content = ""
         for i in range(44):
             if len(content) > 0:
-                content = content + ', '
-            content = content + (str(i)*50)
+                content = content + ", "
+            content = content + (str(i) * 50)
         # pad up to 4096
-        content = content + 'A'*40
+        content = content + "A" * 40
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.TXT,
-                                    content)
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.TXT, content)
         response.answer.append(rrset)
         self.assertEqual(len(response.to_wire()), 4096)
 
@@ -447,17 +443,17 @@ class TestDOTWithCache(DNSDistTest):
             self.assertEqual(receivedResponse, response)
             conn.close()
 
-class TestTLSFrontendLimits(DNSDistTest):
 
+class TestTLSFrontendLimits(DNSDistTest):
     # this test suite uses a different responder port
     # because it uses a different health check configuration
     _testServerPort = pickAvailablePort()
     _answerUnexpected = True
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
 
     _skipListeningOnCL = True
@@ -467,16 +463,16 @@ class TestTLSFrontendLimits(DNSDistTest):
     newServer{address="127.0.0.1:%d"}
     addTLSLocal("127.0.0.1:%d", "%s", "%s", { provider="openssl", maxConcurrentTCPConnections=%d })
     """
-    _config_params = ['_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_maxTCPConnsPerTLSFrontend']
-    _alternateListeningAddr = '127.0.0.1'
+    _config_params = ["_testServerPort", "_tlsServerPort", "_serverCert", "_serverKey", "_maxTCPConnsPerTLSFrontend"]
+    _alternateListeningAddr = "127.0.0.1"
     _alternateListeningPort = _tlsServerPort
 
     def testTCPConnsPerTLSFrontend(self):
         """
         TLS Frontend Limits: Maximum number of conns per TLS frontend
         """
-        name = 'maxconnspertlsfrontend.tls.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "maxconnspertlsfrontend.tls.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         conns = []
 
         for idx in range(self._maxTCPConnsPerTLSFrontend + 1):
@@ -514,11 +510,12 @@ class TestTLSFrontendLimits(DNSDistTest):
         self.assertEqual(count, self._maxTCPConnsPerTLSFrontend)
         self.assertEqual(failed, 1)
 
+
 class TestProtocols(DNSDistTest):
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
 
     _config_template = """
@@ -533,14 +530,14 @@ class TestProtocols(DNSDistTest):
     newServer{address="127.0.0.1:%d"}
     addTLSLocal("127.0.0.1:%d", "%s", "%s", { provider="openssl" })
     """
-    _config_params = ['_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey']
+    _config_params = ["_testServerPort", "_tlsServerPort", "_serverCert", "_serverKey"]
 
     def testProtocolDOT(self):
         """
         DoT: Test DNSQuestion.Protocol
         """
-        name = 'protocols.tls.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "protocols.tls.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
         conn = self.openTLSConnection(self._tlsServerPort, self._serverName, self._caCert)
@@ -553,13 +550,14 @@ class TestProtocols(DNSDistTest):
         self.assertEqual(response, receivedResponse)
         conn.close()
 
+
 class TestPKCSTLSCertificate(DNSDistTest, TLSTests):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
-    _serverCert = 'server-tls.p12'
-    _pkcsPassphrase = 'passw0rd'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+    _serverCert = "server-tls.p12"
+    _pkcsPassphrase = "passw0rd"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _config_template = """
     setKey("%s")
@@ -569,27 +567,42 @@ class TestPKCSTLSCertificate(DNSDistTest, TLSTests):
     addTLSLocal("127.0.0.1:%d", cert, "", { provider="openssl" })
     addAction(SNIRule("powerdns.com"), SpoofAction("1.2.3.4"))
     """
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_serverCert', '_pkcsPassphrase', '_tlsServerPort']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_serverCert",
+        "_pkcsPassphrase",
+        "_tlsServerPort",
+    ]
 
     @classmethod
     def setUpClass(cls):
-        cls.generateNewCertificateAndKey('server-tls')
+        cls.generateNewCertificateAndKey("server-tls")
         cls.startResponders()
         cls.startDNSDist()
         cls.setUpSockets()
 
+
 class TestOpenSSLTLSTicketsKeyCallback(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _numberOfKeys = 5
 
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -612,25 +625,33 @@ class TestOpenSSLTLSTicketsKeyCallback(DNSDistTest):
         TLSTicketsKey: test setting new key and the key added hook
         """
 
-        newKey = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(80))
-        self.sendConsoleCommand("getTLSFrontend(0):loadTicketsKey(\"{}\")".format(newKey))
-        keyLen = self.sendConsoleCommand('lastKeyLen')
+        newKey = "".join(random.choice(string.ascii_uppercase + string.digits) for _ in range(80))
+        self.sendConsoleCommand('getTLSFrontend(0):loadTicketsKey("{}")'.format(newKey))
+        keyLen = self.sendConsoleCommand("lastKeyLen")
         self.assertEqual(int(keyLen), 80)
-        lastKey = self.sendConsoleCommand('lastKey')
+        lastKey = self.sendConsoleCommand("lastKey")
         self.assertEqual(newKey, lastKey.strip())
 
+
 class TestGnuTLSTLSTicketsKeyCallback(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
-    _serverKey = 'server.key'
-    _serverCert = 'server.chain'
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
+    _serverKey = "server.key"
+    _serverCert = "server.chain"
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _numberOfKeys = 5
 
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_tlsServerPort",
+        "_serverCert",
+        "_serverKey",
+    ]
     _config_template = """
     setKey("%s")
     controlSocket("127.0.0.1:%d")
@@ -653,9 +674,9 @@ class TestGnuTLSTLSTicketsKeyCallback(DNSDistTest):
         TLSTicketsKey: test setting new key and the key added hook
         """
 
-        newKey = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(64))
-        self.sendConsoleCommand("getTLSFrontend(0):loadTicketsKey(\"{}\")".format(newKey))
-        keyLen = self.sendConsoleCommand('lastKeyLen')
+        newKey = "".join(random.choice(string.ascii_uppercase + string.digits) for _ in range(64))
+        self.sendConsoleCommand('getTLSFrontend(0):loadTicketsKey("{}")'.format(newKey))
+        keyLen = self.sendConsoleCommand("lastKeyLen")
         self.assertEqual(int(keyLen), 64)
-        lastKey = self.sendConsoleCommand('lastKey')
+        lastKey = self.sendConsoleCommand("lastKey")
         self.assertEqual(newKey, lastKey.strip())
index 4c25018b94291fe18228ea3a110660fe57a6557e..6cadff2453ad7cd83ed052fc585e9943f21db441 100644 (file)
@@ -18,7 +18,6 @@ except NameError:
 
 
 class DNSDistTLSSessionResumptionTest(DNSDistTest):
-
     _consoleKey = DNSDistTest.generateConsoleKey()
     _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
 
@@ -66,21 +65,16 @@ class DNSDistTLSSessionResumptionTest(DNSDistTest):
             time.sleep(0.5)
             output = process.communicate(input=b"")
         except subprocess.CalledProcessError as exc:
-            raise AssertionError(
-                "%s failed (%d): %s" % (testcmd, process.returncode, process.output)
-            )
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, process.output))
 
         if process.returncode != 0:
-            raise AssertionError(
-                "%s failed (%d): %s" % (testcmd, process.returncode, output)
-            )
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, output))
 
         if os.stat(outFile.name).st_size == 0:
             # if tickets have been disabled, or if the session ticket encryption key is exactly the same, we might not get a new ticket
             if not allowNoTicket:
                 raise AssertionError(
-                    "%s failed (%d) to write a session to the output file: %s"
-                    % (testcmd, process.returncode, output)
+                    "%s failed (%d) to write a session to the output file: %s" % (testcmd, process.returncode, output)
                 )
         else:
             shutil.copyfile(outFile.name, ticketFileOut)
@@ -99,7 +93,6 @@ class DNSDistTLSSessionResumptionTest(DNSDistTest):
 
 @unittest.skipIf("SKIP_DOH_TESTS" in os.environ, "DNS over HTTPS tests are disabled")
 class TestNoTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
-
     _serverKey = "server.key"
     _serverCert = "server.chain"
     _serverName = "tls.tests.dnsdist.org"
@@ -150,7 +143,6 @@ class TestNoTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
 
 @unittest.skipIf("SKIP_DOH_TESTS" in os.environ, "DNS over HTTPS tests are disabled")
 class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
-
     _serverKey = "server.key"
     _serverCert = "server.chain"
     _serverName = "tls.tests.dnsdist.org"
@@ -254,9 +246,7 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
             self.generateTicketKeysFile(self._numberOfKeys, "/tmp/ticketKeys.1")
             self.generateTicketKeysFile(self._numberOfKeys - 1, "/tmp/ticketKeys.2")
             # load all ticket keys from the file
-            self.sendConsoleCommand(
-                f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.1')"
-            )
+            self.sendConsoleCommand(f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.1')")
 
             # create a new session, resume it
             self.assertFalse(
@@ -282,9 +272,7 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
             )
 
             # reload the same keys
-            self.sendConsoleCommand(
-                f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.1')"
-            )
+            self.sendConsoleCommand(f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.1')")
 
             # should still be able to resume
             self.assertTrue(
@@ -315,9 +303,7 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
             )
 
             # reload the same keys
-            self.sendConsoleCommand(
-                f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.1')"
-            )
+            self.sendConsoleCommand(f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.1')")
             # since the last key was only present in memory, we should not be able to resume
             self.assertFalse(
                 self.checkSessionResumed(
@@ -345,9 +331,7 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
 
             # generate a file with only _numberOfKeys - 1 keys, so the last active one should still be around after loading that one
             self.generateTicketKeysFile(self._numberOfKeys - 1, "/tmp/ticketKeys.2")
-            self.sendConsoleCommand(
-                f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.2')"
-            )
+            self.sendConsoleCommand(f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.2')")
             # we should be able to resume, and the ticket should be re-encrypted with the new key (NOTE THAT we store into a new file!!)
             self.assertTrue(
                 self.checkSessionResumed(
@@ -386,9 +370,7 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
             )
 
             # reload from file 1, the old session should resume
-            self.sendConsoleCommand(
-                f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.1')"
-            )
+            self.sendConsoleCommand(f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.1')")
             self.assertTrue(
                 self.checkSessionResumed(
                     "127.0.0.1",
@@ -402,9 +384,7 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
             )
 
             # reload from file 2, the latest session should resume
-            self.sendConsoleCommand(
-                f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.2')"
-            )
+            self.sendConsoleCommand(f"getDOHFrontend({bindIdx}):loadTicketsKeys('/tmp/ticketKeys.2')")
             self.assertTrue(
                 self.checkSessionResumed(
                     "127.0.0.1",
@@ -419,7 +399,6 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
 
 
 class TestNoTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest):
-
     _serverKey = "server.key"
     _serverCert = "server.chain"
     _serverName = "tls.tests.dnsdist.org"
@@ -468,7 +447,6 @@ class TestNoTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest):
 
 
 class TestTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest):
-
     _serverKey = "server.key"
     _serverCert = "server.chain"
     _serverName = "tls.tests.dnsdist.org"
@@ -569,9 +547,7 @@ class TestTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest):
         self.generateTicketKeysFile(self._numberOfKeys, "/tmp/ticketKeys.1")
         self.generateTicketKeysFile(self._numberOfKeys - 1, "/tmp/ticketKeys.2")
         # load all ticket keys from the file
-        self.sendConsoleCommand(
-            "getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')"
-        )
+        self.sendConsoleCommand("getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')")
 
         # create a new session, resume it
         self.assertFalse(
@@ -597,9 +573,7 @@ class TestTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest):
         )
 
         # reload the same keys
-        self.sendConsoleCommand(
-            "getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')"
-        )
+        self.sendConsoleCommand("getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')")
 
         # should still be able to resume
         self.assertTrue(
@@ -630,9 +604,7 @@ class TestTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest):
         )
 
         # reload the same keys
-        self.sendConsoleCommand(
-            "getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')"
-        )
+        self.sendConsoleCommand("getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')")
         # since the last key was only present in memory, we should not be able to resume
         self.assertFalse(
             self.checkSessionResumed(
@@ -660,9 +632,7 @@ class TestTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest):
 
         # generate a file with only _numberOfKeys - 1 keys, so the last active one should still be around after loading that one
         self.generateTicketKeysFile(self._numberOfKeys - 1, "/tmp/ticketKeys.2")
-        self.sendConsoleCommand(
-            "getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.2')"
-        )
+        self.sendConsoleCommand("getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.2')")
         # we should be able to resume, and the ticket should be re-encrypted with the new key (NOTE THAT we store into a new file!!)
         self.assertTrue(
             self.checkSessionResumed(
@@ -701,9 +671,7 @@ class TestTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest):
         )
 
         # reload from file 1, the old session should resume
-        self.sendConsoleCommand(
-            "getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')"
-        )
+        self.sendConsoleCommand("getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')")
         self.assertTrue(
             self.checkSessionResumed(
                 "127.0.0.1",
@@ -717,9 +685,7 @@ class TestTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest):
         )
 
         # reload from file 2, the latest session should resume
-        self.sendConsoleCommand(
-            "getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.2')"
-        )
+        self.sendConsoleCommand("getTLSFrontend(0):loadTicketsKeys('/tmp/ticketKeys.2')")
         self.assertTrue(
             self.checkSessionResumed(
                 "127.0.0.1",
@@ -742,8 +708,12 @@ class TestTLSSessionResumptionDOTIdenticalFrontends(DNSDistTest):
     _webServerPort = pickAvailablePort()
     _webServerBasicAuthPassword = "secret"
     _webServerAPIKey = "apisecret"
-    _webServerBasicAuthPasswordHashed = "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
-    _webServerAPIKeyHashed = "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    _webServerBasicAuthPasswordHashed = (
+        "$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM="
+    )
+    _webServerAPIKeyHashed = (
+        "$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso="
+    )
     _serverKey = "server.key"
     _serverCert = "server.chain"
     _serverName = "tls.tests.dnsdist.org"
@@ -806,9 +776,7 @@ binds:
                 session=session,
             )
             self.sendTCPQueryOverConnection(conn, query, response=response, timeout=1)
-            (receivedQuery, receivedResponse) = self.recvTCPResponseOverConnection(
-                conn, useQueue=True, timeout=1
-            )
+            (receivedQuery, receivedResponse) = self.recvTCPResponseOverConnection(conn, useQueue=True, timeout=1)
             receivedQuery.id = query.id
             self.assertEqual(receivedQuery, query)
             self.assertEqual(receivedResponse, response)
@@ -819,9 +787,7 @@ binds:
                 self.assertTrue(conn.session_reused)
 
         headers = {"x-api-key": self._webServerAPIKey}
-        url = (
-            "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
-        )
+        url = "http://127.0.0.1:" + str(self._webServerPort) + "/api/v1/servers/localhost"
         r = requests.get(url, headers=headers, timeout=self._webTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -837,10 +803,7 @@ binds:
                 continue
             new_sessions = new_sessions + int(frontend["tlsNewSessions"])
             resumed_sessions = resumed_sessions + int(frontend["tlsResumptions"])
-            if (
-                int(frontend["tlsNewSessions"]) > 0
-                or int(frontend["tlsResumptions"]) > 0
-            ):
+            if int(frontend["tlsNewSessions"]) > 0 or int(frontend["tlsResumptions"]) > 0:
                 tls_frontends_seen[frontend["id"]] = True
 
         self.assertEqual(new_sessions, 1)
index 62d6e83a58bf51c1df7a5c5bdabb696ea9bc37ae..b9c6b2aa6e2d3ae9df29a049f373a62c22fde35b 100644 (file)
@@ -2,8 +2,8 @@
 import dns
 from dnsdisttests import DNSDistTest
 
-class TestTags(DNSDistTest):
 
+class TestTags(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -45,14 +45,10 @@ class TestTags(DNSDistTest):
         """
         Tag: No match
         """
-        name = 'no-match.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "no-match.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -68,16 +64,12 @@ class TestTags(DNSDistTest):
         """
         Tag: Name and value match
         """
-        name = 'tag-me-dns-1.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tag-me-dns-1.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.50')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.50")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -90,16 +82,12 @@ class TestTags(DNSDistTest):
         """
         Tag: Name matches
         """
-        name = 'tag-me-dns-2.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tag-me-dns-2.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.100')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.100")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -112,16 +100,12 @@ class TestTags(DNSDistTest):
         """
         Tag: Name matches, and value is exactly empty
         """
-        name = 'tag-me-dns-3.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tag-me-dns-3.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.75')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.75")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -134,14 +118,10 @@ class TestTags(DNSDistTest):
         """
         Tag: Tag set on query does not match anything
         """
-        name = 'tag-me-response-2.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tag-me-response-2.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -157,16 +137,12 @@ class TestTags(DNSDistTest):
         """
         Tag: Tag and value set on query matches on response
         """
-        name = 'tag-me-response-1.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tag-me-response-1.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.100')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.100")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
@@ -186,16 +162,12 @@ class TestTags(DNSDistTest):
         """
         Tag: Tag set on response matches
         """
-        name = 'tag-me-response-3.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tag-me-response-3.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.100')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.100")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
@@ -211,8 +183,8 @@ class TestTags(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestSetTagAction(DNSDistTest):
 
+class TestSetTagAction(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -225,20 +197,15 @@ class TestSetTagAction(DNSDistTest):
     """
 
     def testSetTagDefault(self):
-
         """
         Tag: Test setTag overwrites existing value
         """
-        name = 'tag-me-dns-1.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tag-me-dns-1.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.50')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.50")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -248,20 +215,15 @@ class TestSetTagAction(DNSDistTest):
             self.assertEqual(expectedResponse, receivedResponse)
 
     def testSetTagOverwritten(self):
-
         """
         Tag: Test setTag overwrites existing value
         """
-        name = 'tag-me-dns-2.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tag-me-dns-2.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.4')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -270,8 +232,8 @@ class TestSetTagAction(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestSetTag(DNSDistTest):
 
+class TestSetTag(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -291,20 +253,15 @@ class TestSetTag(DNSDistTest):
     """
 
     def testSetTagDefault(self):
-
         """
         Tag: Test setTag overwrites existing value
         """
-        name = 'tag-me-dns-1.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tag-me-dns-1.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.50')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.50")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -314,20 +271,15 @@ class TestSetTag(DNSDistTest):
             self.assertEqual(expectedResponse, receivedResponse)
 
     def testSetTagOverwritten(self):
-
         """
         Tag: Test setTag overwrites existing value
         """
-        name = 'tag-me-dns-2.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "tag-me-dns-2.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.4')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.4")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -336,8 +288,8 @@ class TestSetTag(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestUnsetTag(DNSDistTest):
 
+class TestUnsetTag(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -353,20 +305,15 @@ class TestUnsetTag(DNSDistTest):
     """
 
     def testUnsetTag(self):
-
         """
         Tag: Test UnsetTagAction
         """
-        name = 'unset.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "unset.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.50')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.50")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -378,8 +325,8 @@ class TestUnsetTag(DNSDistTest):
             self.assertEqual(query, receivedQuery)
             self.assertEqual(expectedResponse, receivedResponse)
 
-class TestUnsetTagViaLua(DNSDistTest):
 
+class TestUnsetTagViaLua(DNSDistTest):
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
@@ -395,20 +342,15 @@ class TestUnsetTagViaLua(DNSDistTest):
     """
 
     def testUnsetTag(self):
-
         """
         Tag: Test UnsetTag via Lua
         """
-        name = 'unset-lua.tags.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "unset-lua.tags.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '1.2.3.50')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "1.2.3.50")
         expectedResponse.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index 56194d8601e5725f926d74b633190dc36a7c228c..6de0af11a1c25b8c98eeb9d5486e2fefaf83b54b 100644 (file)
@@ -6,10 +6,10 @@ import dns
 from dnsdisttests import DNSDistTest, Queue, pickAvailablePort
 from proxyprotocolutils import ProxyProtocolUDPResponder
 
-class TestTeeAction(DNSDistTest):
 
+class TestTeeAction(DNSDistTest):
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _teeServerPort = pickAvailablePort()
     _teeProxyServerPort = pickAvailablePort()
     _toTeeQueue = Queue()
@@ -24,24 +24,46 @@ class TestTeeAction(DNSDistTest):
     addAction(QTypeRule(DNSQType.AAAA), TeeAction("127.0.0.1:%d", false))
     addAction(QTypeRule(DNSQType.ANY), TeeAction("127.0.0.1:%d", false, '127.0.0.1', true))
     """
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_teeServerPort', '_teeServerPort', '_teeProxyServerPort']
+    _config_params = [
+        "_consoleKeyB64",
+        "_consolePort",
+        "_testServerPort",
+        "_teeServerPort",
+        "_teeServerPort",
+        "_teeProxyServerPort",
+    ]
+
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
 
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
 
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, True])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, True],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
-        cls._TeeResponder = threading.Thread(name='Tee Responder', target=cls.UDPResponder, args=[cls._teeServerPort, cls._toTeeQueue, cls._fromTeeQueue])
+        cls._TeeResponder = threading.Thread(
+            name="Tee Responder", target=cls.UDPResponder, args=[cls._teeServerPort, cls._toTeeQueue, cls._fromTeeQueue]
+        )
         cls._TeeResponder.daemon = True
         cls._TeeResponder.start()
 
-        cls._TeeProxyResponder = threading.Thread(name='Proxy Protocol Tee Responder', target=ProxyProtocolUDPResponder, args=[cls._teeProxyServerPort, cls._toTeeProxyQueue, cls._fromTeeProxyQueue])
+        cls._TeeProxyResponder = threading.Thread(
+            name="Proxy Protocol Tee Responder",
+            target=ProxyProtocolUDPResponder,
+            args=[cls._teeProxyServerPort, cls._toTeeProxyQueue, cls._fromTeeProxyQueue],
+        )
         cls._TeeProxyResponder.daemon = True
         cls._TeeProxyResponder.start()
 
@@ -49,15 +71,11 @@ class TestTeeAction(DNSDistTest):
         """
         TeeAction: ECS
         """
-        name = 'ecs.tee.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "ecs.tee.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         numberOfQueries = 10
@@ -74,14 +92,16 @@ class TestTeeAction(DNSDistTest):
 
             # retrieve the query from the Tee server
             teedQuery = self._fromTeeQueue.get(True, 2.0)
-            ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-            expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
+            ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+            expectedQuery = dns.message.make_query(name, "A", "IN", use_edns=True, options=[ecso], payload=512)
             expectedQuery.id = query.id
             self.checkQueryEDNSWithECS(expectedQuery, teedQuery)
 
         # check the TeeAction stats
         stats = self.sendConsoleCommand("getAction(0):printStats()")
-        self.assertEqual(stats, """noerrors\t%d
+        self.assertEqual(
+            stats,
+            """noerrors\t%d
 nxdomains\t0
 other-rcode\t0
 queries\t%d
@@ -91,21 +111,19 @@ responses\t%d
 send-errors\t0
 servfails\t0
 tcp-drops\t0
-""" % (numberOfQueries, numberOfQueries, numberOfQueries))
+"""
+            % (numberOfQueries, numberOfQueries, numberOfQueries),
+        )
 
     def testTeeWithoutECS(self):
         """
         TeeAction: No ECS
         """
-        name = 'noecs.tee.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'AAAA', 'IN')
+        name = "noecs.tee.tests.powerdns.com."
+        query = dns.message.make_query(name, "AAAA", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.AAAA,
-                                    '2001:DB8::1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.AAAA, "2001:DB8::1")
         response.answer.append(rrset)
 
         numberOfQueries = 10
@@ -122,14 +140,16 @@ tcp-drops\t0
 
             # retrieve the query from the Tee server
             teedQuery = self._fromTeeQueue.get(True, 2.0)
-            ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
-            expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+            ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 24)
+            expectedQuery = dns.message.make_query(name, "AAAA", "IN", use_edns=True, options=[ecso], payload=512)
             expectedQuery.id = query.id
             self.checkMessageNoEDNS(expectedQuery, teedQuery)
 
         # check the TeeAction stats
         stats = self.sendConsoleCommand("getAction(0):printStats()")
-        self.assertEqual(stats, """noerrors\t%d
+        self.assertEqual(
+            stats,
+            """noerrors\t%d
 nxdomains\t0
 other-rcode\t0
 queries\t%d
@@ -139,21 +159,19 @@ responses\t%d
 send-errors\t0
 servfails\t0
 tcp-drops\t0
-""" % (numberOfQueries, numberOfQueries, numberOfQueries))
+"""
+            % (numberOfQueries, numberOfQueries, numberOfQueries),
+        )
 
     def testTeeWithProxy(self):
         """
         TeeAction: Proxy
         """
-        name = 'proxy.tee.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'ANY', 'IN')
+        name = "proxy.tee.tests.powerdns.com."
+        query = dns.message.make_query(name, "ANY", "IN")
         response = dns.message.make_response(query)
 
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '192.0.2.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1")
         response.answer.append(rrset)
 
         numberOfQueries = 10
@@ -171,11 +189,13 @@ tcp-drops\t0
             # retrieve the query from the Tee Proxy server
             [payload, teedQuery] = self._fromTeeProxyQueue.get(True, 2.0)
             self.checkMessageNoEDNS(query, dns.message.from_wire(teedQuery))
-            self.checkMessageProxyProtocol(payload, '127.0.0.1', '127.0.0.1', False)
+            self.checkMessageProxyProtocol(payload, "127.0.0.1", "127.0.0.1", False)
 
         # check the TeeAction stats
         stats = self.sendConsoleCommand("getAction(0):printStats()")
-        self.assertEqual(stats, """noerrors\t%d
+        self.assertEqual(
+            stats,
+            """noerrors\t%d
 nxdomains\t0
 other-rcode\t0
 queries\t%d
@@ -185,4 +205,6 @@ responses\t%d
 send-errors\t0
 servfails\t0
 tcp-drops\t0
-""" % (numberOfQueries, numberOfQueries, numberOfQueries))
+"""
+            % (numberOfQueries, numberOfQueries, numberOfQueries),
+        )
index 3a2446069aac74b8aa9dc01b27186ceaef870848..d991673983c5f98ab70f9230c2c6b285fdb116d1 100644 (file)
@@ -4,8 +4,8 @@ import time
 import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class TestTimeIPSetYaml(DNSDistTest):
 
+class TestTimeIPSetYaml(DNSDistTest):
     _yaml_config_template = """---
 console:
   listen_address: "127.0.0.1:%d"
@@ -34,24 +34,20 @@ query_rules:
       rcode: "Refused"
 """
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _consolePort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_consolePort', '_consoleKeyB64', '_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_consolePort", "_consoleKeyB64", "_dnsDistPort", "_testServerPort"]
     _config_params = []
 
     def testTimedIPSet(self):
         """
         TimedIPSet from YAML configuration
         """
-        name = 'timedipset-yaml.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "timedipset-yaml.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         refusedResponse = dns.message.make_response(query)
         refusedResponse.set_rcode(dns.rcode.REFUSED)
@@ -64,7 +60,7 @@ query_rules:
             self.assertEqual(receivedResponse, response)
 
         # now we block it for two seconds
-        self.sendConsoleCommand('getObjectFromYAMLConfiguration(\'my-set\'):add(newCA(\'127.0.0.1\'), 2)')
+        self.sendConsoleCommand("getObjectFromYAMLConfiguration('my-set'):add(newCA('127.0.0.1'), 2)")
 
         for method in ["sendUDPQuery", "sendTCPQuery"]:
             sender = getattr(self, method)
@@ -81,6 +77,7 @@ query_rules:
             self.assertEqual(receivedQuery, query)
             self.assertEqual(receivedResponse, response)
 
+
 class TestTimeIPSetLua(DNSDistTest):
     _config_template = """---
     setKey("%s")
@@ -91,24 +88,20 @@ class TestTimeIPSetLua(DNSDistTest):
     addAction(mySet:slice(), RCodeAction(DNSRCode.REFUSED))
 """
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _consolePort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
 
     def testTimedIPSet(self):
         """
         TimedIPSet from Lua configuration
         """
-        name = 'timedipset-lua.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "timedipset-lua.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         refusedResponse = dns.message.make_response(query)
         refusedResponse.set_rcode(dns.rcode.REFUSED)
@@ -121,7 +114,7 @@ class TestTimeIPSetLua(DNSDistTest):
             self.assertEqual(receivedResponse, response)
 
         # now we block it for two seconds
-        self.sendConsoleCommand('mySet:add(newCA(\'127.0.0.1\'), 2)')
+        self.sendConsoleCommand("mySet:add(newCA('127.0.0.1'), 2)")
 
         for method in ["sendUDPQuery", "sendTCPQuery"]:
             sender = getattr(self, method)
index 7180c9067912038c0afc9278939ae8529756b496..4419efd18be1de19e1f4281655ea1ef038ebb15f 100644 (file)
@@ -27,27 +27,27 @@ _common_config = """
     addTimeoutResponseAction(AllRule(), LuaResponseAction(restartQuery))
 """
 
+
 def timeoutResponseCallback(request):
     return ResponderDropAction()
 
+
 def normalResponseCallback(request):
     response = dns.message.make_response(request)
-    rrset = dns.rrset.from_text(request.question[0].name,
-                                3600,
-                                dns.rdataclass.IN,
-                                dns.rdatatype.A,
-                                '127.0.0.1')
+    rrset = dns.rrset.from_text(request.question[0].name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
     response.answer.append(rrset)
     return response.to_wire()
 
+
 def dohTimeoutResponseCallback(request, headers, fromQueue, toQueue):
     return 200, timeoutResponseCallback(request)
 
+
 def dohNormalResponseCallback(request, headers, fromQueue, toQueue):
     return 200, normalResponseCallback(request)
 
-class TestTimeoutBackendUdpTcp(DNSDistTest):
 
+class TestTimeoutBackendUdpTcp(DNSDistTest):
     # this test suite uses different responder ports
     _testNormalServerPort = pickAvailablePort()
     _testTimeoutServerPort = pickAvailablePort()
@@ -56,16 +56,26 @@ class TestTimeoutBackendUdpTcp(DNSDistTest):
     _doh3ServerPort = pickAvailablePort()
     _tlsServerPort = pickAvailablePort()
 
-    _serverName = 'tls.tests.dnsdist.org'
-    _caCert = 'ca.pem'
-    _dohWithNGHTTP2BaseURL =  ("https://%s:%d/dns-query" % ("127.0.0.1", _dohWithNGHTTP2ServerPort))
-    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
+    _serverName = "tls.tests.dnsdist.org"
+    _caCert = "ca.pem"
+    _dohWithNGHTTP2BaseURL = "https://%s:%d/dns-query" % ("127.0.0.1", _dohWithNGHTTP2ServerPort)
+    _dohBaseURL = "https://%s:%d/" % (_serverName, _doh3ServerPort)
 
-    _config_template = """
+    _config_template = (
+        """
     newServer{address="127.0.0.1:%d",pool='restarted',udpTimeout=1,tcpRecvTimeout=1}:setUp()
     newServer{address="127.0.0.1:%d",pool='',udpTimeout=1,tcpRecvTimeout=1}:setUp()
-    """ + _common_config
-    _config_params = ['_testNormalServerPort', '_testTimeoutServerPort', '_dohWithNGHTTP2ServerPort', '_doqServerPort', '_doh3ServerPort', '_tlsServerPort']
+    """
+        + _common_config
+    )
+    _config_params = [
+        "_testNormalServerPort",
+        "_testTimeoutServerPort",
+        "_dohWithNGHTTP2ServerPort",
+        "_doqServerPort",
+        "_doh3ServerPort",
+        "_tlsServerPort",
+    ]
     _verboseMode = True
 
     @classmethod
@@ -73,16 +83,58 @@ class TestTimeoutBackendUdpTcp(DNSDistTest):
         print("Launching responders..")
 
         # timeout
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testTimeoutServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, timeoutResponseCallback])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[
+                cls._testTimeoutServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                timeoutResponseCallback,
+            ],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testTimeoutServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, timeoutResponseCallback])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._testTimeoutServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                timeoutResponseCallback,
+            ],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
-        cls._UDPResponderNormal = threading.Thread(name='UDP ResponderNormal', target=cls.UDPResponder, args=[cls._testNormalServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, normalResponseCallback])
+        cls._UDPResponderNormal = threading.Thread(
+            name="UDP ResponderNormal",
+            target=cls.UDPResponder,
+            args=[
+                cls._testNormalServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                normalResponseCallback,
+            ],
+        )
         cls._UDPResponderNormal.daemon = True
         cls._UDPResponderNormal.start()
-        cls._TCPResponderNormal = threading.Thread(name='TCP ResponderNormal', target=cls.TCPResponder, args=[cls._testNormalServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, normalResponseCallback])
+        cls._TCPResponderNormal = threading.Thread(
+            name="TCP ResponderNormal",
+            target=cls.TCPResponder,
+            args=[
+                cls._testNormalServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                normalResponseCallback,
+            ],
+        )
         cls._TCPResponderNormal.daemon = True
         cls._TCPResponderNormal.start()
 
@@ -90,63 +142,120 @@ class TestTimeoutBackendUdpTcp(DNSDistTest):
         """
         Restart: Timeout then restarted to a second pool
         """
-        name = 'timeout.restart.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        name = "timeout.restart.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse = dns.message.make_response(query)
         expectedResponse.answer.append(rrset)
 
-        for method in ("sendUDPQuery", "sendTCPQuery", "sendDOQQueryWrapper", "sendDOH3QueryWrapper", "sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper"):
+        for method in (
+            "sendUDPQuery",
+            "sendTCPQuery",
+            "sendDOQQueryWrapper",
+            "sendDOH3QueryWrapper",
+            "sendDOTQueryWrapper",
+            "sendDOHWithNGHTTP2QueryWrapper",
+        ):
             sender = getattr(self, method)
             (_, receivedResponse) = sender(query, response=None, useQueue=False, timeout=4)
             self.assertTrue(receivedResponse)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestTimeoutBackendDOH(TestTimeoutBackendUdpTcp):
 
-    _config_template = """
+class TestTimeoutBackendDOH(TestTimeoutBackendUdpTcp):
+    _config_template = (
+        """
     newServer{address="127.0.0.1:%d",pool='restarted',udpTimeout=1,tcpRecvTimeout=1,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com',dohPath='/dns-query'}:setUp()
     newServer{address="127.0.0.1:%d",pool='',udpTimeout=1,tcpRecvTimeout=1,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com',dohPath='/dns-query'}:setUp()
-    """ + _common_config
+    """
+        + _common_config
+    )
 
     @classmethod
     def startResponders(cls):
 
         # timeout
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching DOH responder..")
-        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._testTimeoutServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, dohTimeoutResponseCallback, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH Responder",
+            target=cls.DOHResponder,
+            args=[
+                cls._testTimeoutServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                dohTimeoutResponseCallback,
+                tlsContext,
+            ],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
-        cls._DOHResponder = threading.Thread(name='DOH ResponderNormal', target=cls.DOHResponder, args=[cls._testNormalServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, dohNormalResponseCallback, tlsContext])
+        cls._DOHResponder = threading.Thread(
+            name="DOH ResponderNormal",
+            target=cls.DOHResponder,
+            args=[
+                cls._testNormalServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                dohNormalResponseCallback,
+                tlsContext,
+            ],
+        )
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
-class TestTimeoutBackendDOT(TestTimeoutBackendUdpTcp):
 
-    _config_template = """
+class TestTimeoutBackendDOT(TestTimeoutBackendUdpTcp):
+    _config_template = (
+        """
     newServer{address="127.0.0.1:%d",pool='restarted',udpTimeout=1,tcpRecvTimeout=1,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com'}:setUp()
     newServer{address="127.0.0.1:%d",pool='',udpTimeout=1,tcpRecvTimeout=1,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com'}:setUp()
-    """ + _common_config
+    """
+        + _common_config
+    )
 
     @classmethod
     def startResponders(cls):
 
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
 
         print("Launching TLS responder..")
-        cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._testTimeoutServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, timeoutResponseCallback, tlsContext])
+        cls._TLSResponder = threading.Thread(
+            name="TLS Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._testTimeoutServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                timeoutResponseCallback,
+                tlsContext,
+            ],
+        )
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
 
-        cls._TLSResponder = threading.Thread(name='TLS ResponderNormal', target=cls.TCPResponder, args=[cls._testNormalServerPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, normalResponseCallback, tlsContext])
+        cls._TLSResponder = threading.Thread(
+            name="TLS ResponderNormal",
+            target=cls.TCPResponder,
+            args=[
+                cls._testNormalServerPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                normalResponseCallback,
+                tlsContext,
+            ],
+        )
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
index 25fa1ce273258bd7cc40b1efd8350ed47e1e60ca..3dd445303893ed5dc33f362428d62f6ece7f9096 100644 (file)
@@ -3,8 +3,8 @@ import threading
 import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class TestTrailingDataToBackend(DNSDistTest):
 
+class TestTrailingDataToBackend(DNSDistTest):
     # this test suite uses a different responder port
     # because, contrary to the other ones, its
     # responders allow trailing data and we don't want
@@ -51,17 +51,26 @@ class TestTrailingDataToBackend(DNSDistTest):
     end
     addAction("limited.trailing.tests.powerdns.com.", LuaAction(exceedBuffer))
     """
+
     @classmethod
     def startResponders(cls):
         print("Launching responders..")
 
         # Respond REFUSED to queries with trailing data.
-        cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, dns.rcode.REFUSED])
+        cls._UDPResponder = threading.Thread(
+            name="UDP Responder",
+            target=cls.UDPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, dns.rcode.REFUSED],
+        )
         cls._UDPResponder.daemon = True
         cls._UDPResponder.start()
 
         # Respond REFUSED to queries with trailing data.
-        cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, dns.rcode.REFUSED])
+        cls._TCPResponder = threading.Thread(
+            name="TCP Responder",
+            target=cls.TCPResponder,
+            args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, dns.rcode.REFUSED],
+        )
         cls._TCPResponder.daemon = True
         cls._TCPResponder.start()
 
@@ -70,20 +79,16 @@ class TestTrailingDataToBackend(DNSDistTest):
         Trailing data: Pass through
 
         """
-        name = 'passthrough.trailing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "passthrough.trailing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
 
         raw = query.to_wire()
-        raw = raw + b'A'* 20
+        raw = raw + b"A" * 20
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -99,14 +104,10 @@ class TestTrailingDataToBackend(DNSDistTest):
         Trailing data: Fill buffer
 
         """
-        name = 'max.trailing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "max.trailing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -125,14 +126,10 @@ class TestTrailingDataToBackend(DNSDistTest):
         Trailing data: Reject buffer overflows
 
         """
-        name = 'limited.trailing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "limited.trailing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.SERVFAIL)
@@ -148,14 +145,10 @@ class TestTrailingDataToBackend(DNSDistTest):
         Trailing data: Add
 
         """
-        name = 'added.trailing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "added.trailing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -169,6 +162,7 @@ class TestTrailingDataToBackend(DNSDistTest):
             self.assertEqual(receivedQuery, query)
             self.assertEqual(receivedResponse, expectedResponse)
 
+
 class TestTrailingDataToDnsdist(DNSDistTest):
     _verboseMode = True
     _config_template = """
@@ -227,18 +221,14 @@ class TestTrailingDataToDnsdist(DNSDistTest):
         Trailing data: Drop query
 
         """
-        name = 'dropped.trailing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "dropped.trailing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         raw = query.to_wire()
-        raw = raw + b'A'* 20
+        raw = raw + b"A" * 20
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -260,18 +250,14 @@ class TestTrailingDataToDnsdist(DNSDistTest):
         Trailing data: Remove
 
         """
-        name = 'removed.trailing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "removed.trailing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         raw = query.to_wire()
-        raw = raw + b'A'* 20
+        raw = raw + b"A" * 20
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -287,20 +273,18 @@ class TestTrailingDataToDnsdist(DNSDistTest):
         Trailing data: Echo
 
         """
-        name = 'echoed.trailing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "echoed.trailing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.SERVFAIL)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    '-TrailingData.echoed.trailing.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name, 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "-TrailingData.echoed.trailing.tests.powerdns.com."
+        )
         expectedResponse.answer.append(rrset)
 
         raw = query.to_wire()
-        raw = raw + b'TrailingData'
+        raw = raw + b"TrailingData"
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -314,20 +298,18 @@ class TestTrailingDataToDnsdist(DNSDistTest):
         Trailing data: Replace
 
         """
-        name = 'replaced.trailing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "replaced.trailing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.SERVFAIL)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    '-ABC.echoed.trailing.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name, 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "-ABC.echoed.trailing.tests.powerdns.com."
+        )
         expectedResponse.answer.append(rrset)
 
         raw = query.to_wire()
-        raw = raw + b'TrailingData'
+        raw = raw + b"TrailingData"
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -341,20 +323,18 @@ class TestTrailingDataToDnsdist(DNSDistTest):
         Trailing data: Echo as hex
 
         """
-        name = 'echoed-hex.trailing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "echoed-hex.trailing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.SERVFAIL)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    '-0x0000DEAD.echoed-hex.trailing.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name, 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "-0x0000DEAD.echoed-hex.trailing.tests.powerdns.com."
+        )
         expectedResponse.answer.append(rrset)
 
         raw = query.to_wire()
-        raw = raw + b'\x00\x00\xDE\xAD'
+        raw = raw + b"\x00\x00\xde\xad"
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -368,20 +348,22 @@ class TestTrailingDataToDnsdist(DNSDistTest):
         Trailing data: Replace with null and/or non-ASCII bytes
 
         """
-        name = 'replaced-unsafe.trailing.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "replaced-unsafe.trailing.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         response = dns.message.make_response(query)
         response.set_rcode(dns.rcode.SERVFAIL)
         expectedResponse = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.CNAME,
-                                    '-0xB000DEAD42F09F91BBC3BE.echoed-hex.trailing.tests.powerdns.com.')
+        rrset = dns.rrset.from_text(
+            name,
+            60,
+            dns.rdataclass.IN,
+            dns.rdatatype.CNAME,
+            "-0xB000DEAD42F09F91BBC3BE.echoed-hex.trailing.tests.powerdns.com.",
+        )
         expectedResponse.answer.append(rrset)
 
         raw = query.to_wire()
-        raw = raw + b'TrailingData'
+        raw = raw + b"TrailingData"
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
index 7f31d04c5456ecef3631cba6dc1e95321b116666..237206ad06d8c8788d5baffdf2c1f253e0a932e1 100644 (file)
@@ -3,8 +3,8 @@ import base64
 import dns
 from dnsdisttests import DNSDistTest, pickAvailablePort
 
-class TestYaml(DNSDistTest):
 
+class TestYaml(DNSDistTest):
     _yaml_config_template = """---
 webserver:
   listen_addresses:
@@ -118,29 +118,32 @@ response_rules:
     _webServerPort2 = pickAvailablePort()
     _dnsDistPort = pickAvailablePort()
     _consoleKey = DNSDistTest.generateConsoleKey()
-    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
     _consolePort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_webServerPort', '_webServerPort2', '_consolePort', '_consoleKeyB64', '_dnsDistPort', '_testServerPort']
+    _yaml_config_params = [
+        "_webServerPort",
+        "_webServerPort2",
+        "_consolePort",
+        "_consoleKeyB64",
+        "_dnsDistPort",
+        "_testServerPort",
+    ]
     _config_params = []
 
     def testForwarded(self):
         """
         Yaml: Forwarded query
         """
-        name = 'forwarded.yaml.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "forwarded.yaml.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         # UDP query should be dropped
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
         self.assertEqual(receivedResponse, None)
         # TCP query should be forwarded
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response=response)
@@ -152,16 +155,12 @@ response_rules:
         """
         Yaml: Inline Lua
         """
-        name = 'inline-lua.yaml.test.powerdns.com.'
+        name = "inline-lua.yaml.test.powerdns.com."
 
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
         truncatedResponse = dns.message.make_response(query)
@@ -181,14 +180,10 @@ response_rules:
         self.assertEqual(receivedResponse, clearedResponse)
 
         # response with RD should be forwarded
-        query = dns.message.make_query(name, 'A', 'IN')
+        query = dns.message.make_query(name, "A", "IN")
         query.flags |= dns.flags.RD
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    60,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
 
         response.answer.append(rrset)
         for method in ["sendUDPQuery", "sendTCPQuery"]:
@@ -198,8 +193,8 @@ response_rules:
             self.assertEqual(receivedQuery, query)
             self.assertEqual(receivedResponse, response)
 
-class TestMixingYamlWithLua(DNSDistTest):
 
+class TestMixingYamlWithLua(DNSDistTest):
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -226,7 +221,7 @@ query_rules:
 """
     _dnsDistPort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort"]
     _config_params = []
     _config_template = """
 enableLuaConfiguration()
@@ -237,8 +232,8 @@ addAction(QNameRule("notimp-lua.yaml-lua-mix.test.powerdns.com."), RCodeAction(D
         """
         Yaml / Lua mix: Refused from YAML
         """
-        name = 'refused.yaml-lua-mix.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "refused.yaml-lua-mix.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -251,8 +246,8 @@ addAction(QNameRule("notimp-lua.yaml-lua-mix.test.powerdns.com."), RCodeAction(D
         """
         Yaml / Lua mix: Not imp from Lua
         """
-        name = 'notimp-lua.yaml-lua-mix.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "notimp-lua.yaml-lua-mix.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.NOTIMP)
@@ -261,8 +256,8 @@ addAction(QNameRule("notimp-lua.yaml-lua-mix.test.powerdns.com."), RCodeAction(D
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestYamlNMGRule(DNSDistTest):
 
+class TestYamlNMGRule(DNSDistTest):
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -284,15 +279,15 @@ query_rules:
       type: "RCode"
       rcode: "5"
 """
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort"]
     _config_params = []
 
     def testYamlNMGRule(self):
         """
         YAML: NMGRule should refuse our queries
         """
-        name = 'nmgrule.yaml.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nmgrule.yaml.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -302,8 +297,8 @@ query_rules:
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestYamlNMGRuleObject(DNSDistTest):
 
+class TestYamlNMGRuleObject(DNSDistTest):
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -328,15 +323,15 @@ query_rules:
       type: "RCode"
       rcode: "5"
 """
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort"]
     _config_params = []
 
     def testYamlNMGRule(self):
         """
         YAML: NMGRule (via a NMG object) should refuse our queries
         """
-        name = 'nmgrule-object.yaml.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nmgrule-object.yaml.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -346,8 +341,8 @@ query_rules:
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestYamlNMGRuleObjectExcludeMasks(DNSDistTest):
 
+class TestYamlNMGRuleObjectExcludeMasks(DNSDistTest):
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -374,15 +369,15 @@ query_rules:
       type: "RCode"
       rcode: "5"
 """
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort"]
     _config_params = []
 
     def testYamlNMGRule(self):
         """
         YAML: NMGRule (via a NMG object with exclusion) should refuse our queries
         """
-        name = 'nmgrule-object-exclusion.yaml.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "nmgrule-object-exclusion.yaml.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
@@ -392,8 +387,8 @@ query_rules:
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
-class TestYamlOpcode(DNSDistTest):
 
+class TestYamlOpcode(DNSDistTest):
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -412,15 +407,15 @@ query_rules:
       type: "RCode"
       rcode: "Refused"
 """
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort"]
     _config_params = []
 
     def testRefuseOpcodeNotify(self):
         """
         YAML: Refuse Opcode NOTIFY
         """
-        name = 'opcodenotify.yaml.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "opcodenotify.yaml.tests.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         query.set_opcode(dns.opcode.NOTIFY)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query)
@@ -435,15 +430,11 @@ query_rules:
         """
         YAML: Allow Opcode UPDATE
         """
-        name = 'opcodeupdate.yaml.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'SOA', 'IN')
+        name = "opcodeupdate.yaml.tests.powerdns.com."
+        query = dns.message.make_query(name, "SOA", "IN")
         query.set_opcode(dns.opcode.UPDATE)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -455,8 +446,8 @@ query_rules:
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-class TestYamlPoolECSZeroScope(DNSDistTest):
 
+class TestYamlPoolECSZeroScope(DNSDistTest):
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -498,22 +489,18 @@ query_rules:
       type: "RCode"
       rcode: "Refused"
 """
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort", "_testServerPort"]
     _config_params = []
 
     def testPoolECSZeroScopeConfig(self):
         """
         YAML: Test pool ECS and zero scope
         """
-        name = 'pool-ecs-zero-scope.yaml.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'SOA', 'IN')
+        name = "pool-ecs-zero-scope.yaml.tests.powerdns.com."
+        query = dns.message.make_query(name, "SOA", "IN")
         query.set_opcode(dns.opcode.UPDATE)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -525,8 +512,8 @@ query_rules:
             self.assertEqual(query, receivedQuery)
             self.assertEqual(response, receivedResponse)
 
-class TestYamlUnknownSelectorName(DNSDistTest):
 
+class TestYamlUnknownSelectorName(DNSDistTest):
     _yaml_config_template = """---
 logging:
   structured:
@@ -554,7 +541,7 @@ query_rules:
       type: "Pool"
       pool_name: "tcp-pool"
 """
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort"]
     _config_params = []
     # we need this because the error is triggered during the parsing of the YAML configuration,
     # too early for the logging for the logging configuration to have been applied
@@ -584,8 +571,8 @@ query_rules:
         if cls._dnsdist:
             cls.killProcess(cls._dnsdist)
 
-class TestYamlUnknownPolicyName(DNSDistTest):
 
+class TestYamlUnknownPolicyName(DNSDistTest):
     _yaml_config_template = """---
 logging:
   structured:
@@ -603,7 +590,7 @@ pools:
   - name: ""
     policy: "this-policy-does-not-exist"
 """
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort"]
     _config_params = []
 
     def testFailToStart(self):
@@ -630,8 +617,8 @@ pools:
         if cls._dnsdist:
             cls.killProcess(cls._dnsdist)
 
-class TestYamlLuaCodeUsingObjects(DNSDistTest):
 
+class TestYamlLuaCodeUsingObjects(DNSDistTest):
     _yaml_config_template = """---
 binds:
   - listen_address: "127.0.0.1:%d"
@@ -667,22 +654,18 @@ query_rules:
       type: "RCode"
       rcode: "Refused"
 """
-    _yaml_config_params = ['_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ["_dnsDistPort", "_testServerPort"]
     _config_params = []
 
     def testLuaObjects(self):
         """
         YAML: Test Lua objects
         """
-        name = 'lua-objects.yaml.tests.powerdns.com.'
-        query = dns.message.make_query(name, 'SOA', 'IN')
+        name = "lua-objects.yaml.tests.powerdns.com."
+        query = dns.message.make_query(name, "SOA", "IN")
         query.set_opcode(dns.opcode.UPDATE)
         response = dns.message.make_response(query)
-        rrset = dns.rrset.from_text(name,
-                                    3600,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         response.answer.append(rrset)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
index a56642cdecd2cdec399c9c58d57ef43b2d30657b..b4a495e64bf05713e5fb55e54ce0a8008344a46b 100644 (file)
@@ -13,8 +13,8 @@ import dns.message
 
 from eqdnsmessage import AssertEqualDNSMessageMixin
 
-class IXFRDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
 
+class IXFRDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     _ixfrDistStartupDelay = 2.0
     _ixfrDistPort = 5342
 
@@ -30,15 +30,15 @@ work-dir: 'ixfrdist.dir'
 failed-soa-retry: 3
 """
     _config_domains = None
-    _config_params = ['_ixfrDistPort']
+    _config_params = ["_ixfrDistPort"]
 
     @classmethod
     def startIXFRDist(cls):
         print("Launching ixfrdist..")
-        conffile = 'ixfrdist.yml'
+        conffile = "ixfrdist.yml"
         params = tuple([getattr(cls, param) for param in cls._config_params])
         print(params)
-        with open(conffile, 'w') as conf:
+        with open(conffile, "w") as conf:
             conf.write("# Autogenerated by ixfrdisttests.py\n")
             conf.write(cls._config_template % params)
 
@@ -46,19 +46,18 @@ failed-soa-retry: 3
                 conf.write("domains:\n")
 
                 for item in cls._config_domains:
-                    conf.write("  - domain: %s\n" % (item['domain']))
-                    conf.write("    master: %s\n" % (item['master']))
-                    if ('notify' in item) :
-                        conf.write("    notify: %s\n" % (item['notify']))
+                    conf.write("  - domain: %s\n" % (item["domain"]))
+                    conf.write("    master: %s\n" % (item["master"]))
+                    if "notify" in item:
+                        conf.write("    notify: %s\n" % (item["notify"]))
 
-        ixfrdistcmd = [os.environ['IXFRDISTBIN'], '--config', conffile, '--debug']
+        ixfrdistcmd = [os.environ["IXFRDISTBIN"], "--config", conffile, "--debug"]
 
-        logFile = 'ixfrdist.log'
-        with open(logFile, 'w') as fdLog:
-            cls._ixfrdist = subprocess.Popen(ixfrdistcmd, close_fds=True,
-                                             stdout=fdLog, stderr=fdLog)
+        logFile = "ixfrdist.log"
+        with open(logFile, "w") as fdLog:
+            cls._ixfrdist = subprocess.Popen(ixfrdistcmd, close_fds=True, stdout=fdLog, stderr=fdLog)
 
-        if 'IXFRDIST_FAST_TESTS' in os.environ:
+        if "IXFRDIST_FAST_TESTS" in os.environ:
             delay = 0.5
         else:
             delay = cls._ixfrDistStartupDelay
@@ -89,7 +88,7 @@ failed-soa-retry: 3
 
     @classmethod
     def tearDownIXFRDist(cls):
-        if 'IXFRDIST_FAST_TESTS' in os.environ:
+        if "IXFRDIST_FAST_TESTS" in os.environ:
             delay = 0.1
         else:
             delay = 1.0
@@ -200,4 +199,3 @@ failed-soa-retry: 3
     def setUp(self):
         # This function is called before every tests
         super(IXFRDistTest, self).setUp()
-
index 50a9b37288345d85c88fe43e997077209a80dd74..95dda8442a5ad67e000eb81a52d3c24bf07cb688 100644 (file)
@@ -54,12 +54,13 @@ ns2.ixfr.case.    4242    A       192.0.2.2
 test.ixfr.case.   1234    TXT     "Hello World"
 case2.ixfr.case.  1234    TXT     "Mixed Case"
 case3.ixfr.case.  1234    TXT     "MIXED CASE"
-"""
+""",
 }
 
 xfrServerPort = 4246
 xfrServer = AXFRServer(xfrServerPort, zones)
 
+
 class IXFRDistCaseSensitiveTXTTest(IXFRDistTest):
     """
     This test verifies that TXT record comparisons are case-sensitive
@@ -70,7 +71,7 @@ class IXFRDistCaseSensitiveTXTTest(IXFRDistTest):
     global xfrServerPort
     _xfrDone = 0
     _config_domains = [
-        {"domain" : "ixfr.case", "master" : "127.0.0.1:" + str(xfrServerPort)},
+        {"domain": "ixfr.case", "master": "127.0.0.1:" + str(xfrServerPort)},
     ]
     _loaded_serials = []
 
@@ -89,26 +90,28 @@ class IXFRDistCaseSensitiveTXTTest(IXFRDistTest):
         xfrServer.moveToSerial(serial)
 
         if notify:
-            notif = dns.message.make_query('ixfr.case.', 'SOA')
+            notif = dns.message.make_query("ixfr.case.", "SOA")
             notif.set_opcode(dns.opcode.NOTIFY)
             notify_response = self.sendUDPQuery(notif)
             assert notify_response.rcode() == dns.rcode.NOERROR
 
         def get_current_serial():
-            query = dns.message.make_query('ixfr.case.', 'SOA')
+            query = dns.message.make_query("ixfr.case.", "SOA")
             response_message = self.sendUDPQuery(query)
 
             if response_message.rcode() == dns.rcode.REFUSED:
                 return 0
 
-            soa_rrset = response_message.find_rrset(dns.message.ANSWER, dns.name.from_text("ixfr.case."), dns.rdataclass.IN, dns.rdatatype.SOA)
+            soa_rrset = response_message.find_rrset(
+                dns.message.ANSWER, dns.name.from_text("ixfr.case."), dns.rdataclass.IN, dns.rdatatype.SOA
+            )
             return soa_rrset[0].serial
 
         attempts = 0
         while attempts < timeout:
-            print('attempts=%s timeout=%s' % (attempts, timeout))
+            print("attempts=%s timeout=%s" % (attempts, timeout))
             servedSerial = get_current_serial()
-            print('servedSerial=%s' % servedSerial)
+            print("servedSerial=%s" % servedSerial)
             if servedSerial > serial:
                 raise AssertionError("Expected serial %d, got %d" % (serial, servedSerial))
             if servedSerial == serial:
@@ -119,13 +122,16 @@ class IXFRDistCaseSensitiveTXTTest(IXFRDistTest):
             attempts = attempts + 1
             time.sleep(1)
 
-        raise AssertionError("Waited %d seconds for the serial to be updated to %d but the last served serial is still %d" % (timeout, serial, servedSerial))
+        raise AssertionError(
+            "Waited %d seconds for the serial to be updated to %d but the last served serial is still %d"
+            % (timeout, serial, servedSerial)
+        )
 
     def checkTXTRecord(self, expected_txt_records):
         """
         Check for the presence of specific TXT records in the zone using AXFR
         """
-        query = dns.message.make_query('ixfr.case.', 'AXFR')
+        query = dns.message.make_query("ixfr.case.", "AXFR")
         responses = self.sendTCPQueryMultiResponse(query, count=10)
 
         found_txt_records = []
@@ -143,8 +149,10 @@ class IXFRDistCaseSensitiveTXTTest(IXFRDistTest):
                 if found_name == expected_name and found_txt == expected_txt:
                     found = True
                     break
-            self.assertTrue(found,
-                        f"TXT record '{expected_name}' with content '{expected_txt}' not found in AXFR. Found: {found_txt_records}")
+            self.assertTrue(
+                found,
+                f"TXT record '{expected_name}' with content '{expected_txt}' not found in AXFR. Found: {found_txt_records}",
+            )
 
     def checkIXFRContainsTXTChange(self, fromserial, toserial, expected_removed=None, expected_added=None):
         """
@@ -157,7 +165,7 @@ class IXFRDistCaseSensitiveTXTTest(IXFRDistTest):
 
         self.assertEqual(soa_latest[0].serial, toserial)
 
-        query = dns.message.make_query('ixfr.case.', 'IXFR')
+        query = dns.message.make_query("ixfr.case.", "IXFR")
         query.authority = [soa_requested]
 
         responses = self.sendTCPQueryMultiResponse(query, count=10)  # Allow for multiple responses
@@ -180,18 +188,16 @@ class IXFRDistCaseSensitiveTXTTest(IXFRDistTest):
 
         if expected_removed:
             for removed_txt in expected_removed:
-                self.assertIn(removed_txt, found_removed,
-                            f"Expected removed TXT '{removed_txt}' not found in IXFR")
-        
+                self.assertIn(removed_txt, found_removed, f"Expected removed TXT '{removed_txt}' not found in IXFR")
+
         if expected_added:
             for added_txt in expected_added:
-                self.assertIn(added_txt, found_added,
-                            f"Expected added TXT '{added_txt}' not found in IXFR")
+                self.assertIn(added_txt, found_added, f"Expected added TXT '{added_txt}' not found in IXFR")
 
     def test_a_first_version(self):
         """Test first version of zone and verify TXT record presence"""
         self.waitUntilCorrectSerialIsLoaded(1)
-        self.checkTXTRecord([('test.ixfr.case.', "Hello World")])
+        self.checkTXTRecord([("test.ixfr.case.", "Hello World")])
 
     def test_b_case_change_lowercase(self):
         """Test that changing TXT from 'Hello World' to 'hello world' is detected"""
@@ -206,7 +212,9 @@ class IXFRDistCaseSensitiveTXTTest(IXFRDistTest):
     def test_d_multiple_txt_records_mixed_case(self):
         """Test multiple TXT records with different case variations"""
         self.waitUntilCorrectSerialIsLoaded(4)
-        self.checkIXFRContainsTXTChange(3, 4, expected_removed=["HELLO WORLD"], expected_added=["Hello World", "Mixed Case", "mixed case"])
+        self.checkIXFRContainsTXTChange(
+            3, 4, expected_removed=["HELLO WORLD"], expected_added=["Hello World", "Mixed Case", "mixed case"]
+        )
 
     def test_e_case_sensitive_update(self):
         """Test that updating a TXT record's case is properly handled"""
index dbc1dc906fc0bf980bb84aa088b36aefd2c3b9ee..c26cfaa021f9becfbd8b8275c340b39c9cdb2777 100644 (file)
@@ -43,13 +43,14 @@ ns1.example.    4242    A       192.0.2.1
 ns2.example.    4242    A       192.0.2.2
 newrecord2.example.        8484    A       192.0.2.42
 other.example.  1234    TXT     "foo"
-"""
+""",
 }
 
 
 xfrServerPort = 4244
 xfrServer = AXFRServer(xfrServerPort, zones)
 
+
 class IXFRDistBasicTest(IXFRDistTest):
     """
     This test makes sure that we correctly fetch a zone via AXFR, and provide the full AXFR and IXFR
@@ -59,12 +60,15 @@ class IXFRDistBasicTest(IXFRDistTest):
     _xfrDone = 0
     _config_domains = [
         # zone for actual XFR testing
-        {"domain" : "example", "master" : "127.0.0.1:" + str(xfrServerPort), 'notify' : "127.0.0.1:" + str(xfrServerPort + 1)},
+        {
+            "domain": "example",
+            "master": "127.0.0.1:" + str(xfrServerPort),
+            "notify": "127.0.0.1:" + str(xfrServerPort + 1),
+        },
         # bogus port is intentional - zone is intentionally unloadable
-        {"domain" : "example2", "master" : "127.0.0.1:1"},
+        {"domain": "example2", "master": "127.0.0.1:1"},
         # for testing how ixfrdist deals with getting the wrong zone on XFR
-        {"domain" : "example4", "master" : '127.0.0.1:' + str(xfrServerPort)},
-
+        {"domain": "example4", "master": "127.0.0.1:" + str(xfrServerPort)},
     ]
     _loaded_serials = []
 
@@ -84,26 +88,28 @@ class IXFRDistBasicTest(IXFRDistTest):
         xfrServer.moveToSerial(serial)
 
         if notify:
-            notif = dns.message.make_query('example.', 'SOA')
+            notif = dns.message.make_query("example.", "SOA")
             notif.set_opcode(dns.opcode.NOTIFY)
             notify_response = self.sendUDPQuery(notif)
             assert notify_response.rcode() == dns.rcode.NOERROR
 
         def get_current_serial():
-            query = dns.message.make_query('example.', 'SOA')
+            query = dns.message.make_query("example.", "SOA")
             response_message = self.sendUDPQuery(query)
 
             if response_message.rcode() == dns.rcode.REFUSED:
                 return 0
 
-            soa_rrset = response_message.find_rrset(dns.message.ANSWER, dns.name.from_text("example."), dns.rdataclass.IN, dns.rdatatype.SOA)
+            soa_rrset = response_message.find_rrset(
+                dns.message.ANSWER, dns.name.from_text("example."), dns.rdataclass.IN, dns.rdatatype.SOA
+            )
             return soa_rrset[0].serial
 
         attempts = 0
         while attempts < timeout:
-            print('attempts=%s timeout=%s' % (attempts, timeout))
+            print("attempts=%s timeout=%s" % (attempts, timeout))
             servedSerial = get_current_serial()
-            print('servedSerial=%s' % servedSerial)
+            print("servedSerial=%s" % servedSerial)
             if servedSerial > serial:
                 raise AssertionError("Expected serial %d, got %d" % (serial, servedSerial))
             if servedSerial == serial:
@@ -114,7 +120,10 @@ class IXFRDistBasicTest(IXFRDistTest):
             attempts = attempts + 1
             time.sleep(1)
 
-        raise AssertionError("Waited %d seconds for the serial to be updated to %d but the last served serial is still %d" % (timeout, serial, servedSerial))
+        raise AssertionError(
+            "Waited %d seconds for the serial to be updated to %d but the last served serial is still %d"
+            % (timeout, serial, servedSerial)
+        )
 
     def checkFullZone(self, serial):
         global zones
@@ -123,14 +132,18 @@ class IXFRDistBasicTest(IXFRDistTest):
         zone = []
         for i in dns.zone.from_text(zones[serial], relativize=False).iterate_rdatasets():
             n, rds = i
-            rrs=dns.rrset.RRset(n, rds.rdclass, rds.rdtype)
+            rrs = dns.rrset.RRset(n, rds.rdclass, rds.rdtype)
             rrs.update(rds)
             zone.append(rrs)
 
-        expected =[[zone[0]], sorted(zone[1:], key=lambda rrset: (rrset.name, rrset.rdtype)), [zone[0]]] # AXFRs are SOA-wrapped
+        expected = [
+            [zone[0]],
+            sorted(zone[1:], key=lambda rrset: (rrset.name, rrset.rdtype)),
+            [zone[0]],
+        ]  # AXFRs are SOA-wrapped
 
-        query = dns.message.make_query('example.', 'AXFR')
-        res = self.sendTCPQueryMultiResponse(query, count=len(expected)+1) # +1 for trailing data check
+        query = dns.message.make_query("example.", "AXFR")
+        res = self.sendTCPQueryMultiResponse(query, count=len(expected) + 1)  # +1 for trailing data check
         answers = [r.answer for r in res]
         answers[1].sort(key=lambda rrset: (rrset.name, rrset.rdtype))
         self.assertEqual(answers, expected)
@@ -143,13 +156,13 @@ class IXFRDistBasicTest(IXFRDistTest):
 
         self.assertEqual(soa_latest[0].serial, toserial)
 
-        query = dns.message.make_query('example.', 'IXFR')
+        query = dns.message.make_query("example.", "IXFR")
         query.authority = [soa_requested]
 
         expected = []
-        expected.append([soa_latest]) #latest SOA
+        expected.append([soa_latest])  # latest SOA
 
-        def pairwise(iterable): # itertools.pairwise exists in 3.10, but until then...
+        def pairwise(iterable):  # itertools.pairwise exists in 3.10, but until then...
             # pairwise('ABCDEFG') --> AB BC CD DE EF FG
             a, b = itertools.tee(iterable)
             next(b, None)
@@ -168,17 +181,21 @@ class IXFRDistBasicTest(IXFRDistTest):
             added = [r for r in new_records if r not in old_records]
             removed = [r for r in old_records if r not in new_records]
 
-            expected.append([xfrServer._getSOAForSerial(serial_pair[0])]) # old SOA
-            if removed: expected.append(removed) # removed records from old SOA (sendTCPQueryMultiResponse skips if empty)
-            expected.append([xfrServer._getSOAForSerial(serial_pair[1])]) # new SOA
-            if added: expected.append(added) # added records in new SOA (sendTCPQueryMultiResponse skips if empty)
+            expected.append([xfrServer._getSOAForSerial(serial_pair[0])])  # old SOA
+            if removed:
+                expected.append(removed)  # removed records from old SOA (sendTCPQueryMultiResponse skips if empty)
+            expected.append([xfrServer._getSOAForSerial(serial_pair[1])])  # new SOA
+            if added:
+                expected.append(added)  # added records in new SOA (sendTCPQueryMultiResponse skips if empty)
 
-        expected.append([soa_latest]) # latest SOA
+        expected.append([soa_latest])  # latest SOA
 
         if not found_starting_version:
-            raise AssertionError("Did not find zone version with requested serial {fromserial}, impossible to IXFR scenario?")
+            raise AssertionError(
+                "Did not find zone version with requested serial {fromserial}, impossible to IXFR scenario?"
+            )
 
-        res = self.sendTCPQueryMultiResponse(query, count=len(expected)+1) # +1 for trailing data check
+        res = self.sendTCPQueryMultiResponse(query, count=len(expected) + 1)  # +1 for trailing data check
         answers = [r.answer for r in res]
 
         # answers[1].sort(key=lambda rrset: (rrset.name, rrset.rdtype))
@@ -192,7 +209,6 @@ class IXFRDistBasicTest(IXFRDistTest):
                 pos = pos + 1
             answerPos = answerPos + 1
 
-
     def test_a_XFR(self):
         self.waitUntilCorrectSerialIsLoaded(1)
         self.checkFullZone(1)
@@ -200,11 +216,11 @@ class IXFRDistBasicTest(IXFRDistTest):
         self.waitUntilCorrectSerialIsLoaded(2)
         self.checkFullZone(2)
 
-        self.checkIXFR(1,2)
+        self.checkIXFR(1, 2)
 
     # _b_ because we expect post-XFR testing state
     def test_b_UDP_SOA_existing(self):
-        query = dns.message.make_query('example.', 'SOA')
+        query = dns.message.make_query("example.", "SOA")
         expected = dns.message.make_response(query)
         expected.flags |= dns.flags.AA
         expected.answer.append(xfrServer._getSOAForSerial(2))
@@ -218,7 +234,7 @@ class IXFRDistBasicTest(IXFRDistTest):
             pos = pos + 1
 
     def test_b_UDP_SOA_not_loaded(self):
-        query = dns.message.make_query('example2.', 'SOA')
+        query = dns.message.make_query("example2.", "SOA")
         expected = dns.message.make_response(query)
         expected.set_rcode(dns.rcode.REFUSED)
 
@@ -226,7 +242,7 @@ class IXFRDistBasicTest(IXFRDistTest):
         self.assertEqual(expected, response)
 
     def test_b_UDP_SOA_not_configured(self):
-        query = dns.message.make_query('example3.', 'SOA')
+        query = dns.message.make_query("example3.", "SOA")
         expected = dns.message.make_response(query)
         expected.set_rcode(dns.rcode.REFUSED)
 
@@ -236,8 +252,8 @@ class IXFRDistBasicTest(IXFRDistTest):
     def test_c_IXFR_multi(self):
         self.waitUntilCorrectSerialIsLoaded(3)
         self.checkFullZone(3)
-        self.checkIXFR(2,3)
-        self.checkIXFR(1,3)
+        self.checkIXFR(2, 3)
+        self.checkIXFR(1, 3)
 
         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         sock.bind(("127.0.0.1", xfrServerPort + 1))
@@ -250,7 +266,7 @@ class IXFRDistBasicTest(IXFRDistTest):
         received = dns.message.from_wire(data)
         sock.close()
 
-        notif = dns.message.make_query('example.', 'SOA')
+        notif = dns.message.make_query("example.", "SOA")
         notif.set_opcode(dns.opcode.NOTIFY)
         notif.flags |= dns.flags.AA
         notif.flags &= ~dns.flags.RD
@@ -259,6 +275,6 @@ class IXFRDistBasicTest(IXFRDistTest):
         self.assertEqual(received, notif)
 
         self.checkFullZone(4)
-        self.checkIXFR(3,4)
-        self.checkIXFR(2,4)
-        self.checkIXFR(1,4)
+        self.checkIXFR(3, 4)
+        self.checkIXFR(2, 4)
+        self.checkIXFR(1, 4)
index bc1bf3d74dc3e974cf634ff226319f6c9a2d70f3..e937cc601ddddaf8072907f5829c8704a605efbc 100644 (file)
@@ -5,14 +5,15 @@ import subprocess
 
 xfrServerPort = 4244
 
+
 class IXFRDistStatsTest(IXFRDistTest):
     """
     This test makes sure we have statistics in ixfrdist
     """
 
-    webserver_address = '127.0.0.1:8080'
+    webserver_address = "127.0.0.1:8080"
 
-    _config_params = ['_ixfrDistPort', 'webserver_address']
+    _config_params = ["_ixfrDistPort", "webserver_address"]
 
     _config_template = """
 listen:
@@ -27,19 +28,28 @@ failed-soa-retry: 3
 webserver-address: %s
 """
 
-    _config_domains = [{'domain' : 'example', 'master' : '127.0.0.1:' + str(xfrServerPort)}]
-
-    metric_prog_stats = ["ixfrdist_uptime_seconds", "ixfrdist_domains",
-                         "ixfrdist_unknown_domain_inqueries_total",
-                         "ixfrdist_sys_msec", "ixfrdist_user_msec",
-                         "ixfrdist_real_memory_usage",
-                         "ixfrdist_fd_usage",
-                         "ixfrdist_notimp"]
-    metric_domain_stats = ["ixfrdist_soa_serial", "ixfrdist_soa_checks_total",
-                           "ixfrdist_soa_checks_failed_total",
-                           "ixfrdist_soa_inqueries_total",
-                           "ixfrdist_axfr_inqueries_total", "ixfrdist_axfr_failures_total",
-                           "ixfrdist_ixfr_inqueries_total", "ixfrdist_ixfr_failures_total"]
+    _config_domains = [{"domain": "example", "master": "127.0.0.1:" + str(xfrServerPort)}]
+
+    metric_prog_stats = [
+        "ixfrdist_uptime_seconds",
+        "ixfrdist_domains",
+        "ixfrdist_unknown_domain_inqueries_total",
+        "ixfrdist_sys_msec",
+        "ixfrdist_user_msec",
+        "ixfrdist_real_memory_usage",
+        "ixfrdist_fd_usage",
+        "ixfrdist_notimp",
+    ]
+    metric_domain_stats = [
+        "ixfrdist_soa_serial",
+        "ixfrdist_soa_checks_total",
+        "ixfrdist_soa_checks_failed_total",
+        "ixfrdist_soa_inqueries_total",
+        "ixfrdist_axfr_inqueries_total",
+        "ixfrdist_axfr_failures_total",
+        "ixfrdist_ixfr_inqueries_total",
+        "ixfrdist_ixfr_failures_total",
+    ]
 
     @classmethod
     def setUpClass(cls):
@@ -54,23 +64,28 @@ webserver-address: %s
     def checkPrometheusContentPromtool(self, content):
         output = None
         try:
-            testcmd = ['promtool', 'check', 'metrics']
-            process = subprocess.Popen(testcmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
+            testcmd = ["promtool", "check", "metrics"]
+            process = subprocess.Popen(
+                testcmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True
+            )
             output = process.communicate(input=content)
         except subprocess.CalledProcessError as exc:
-            raise AssertionError('%s failed (%d): %s' % (testcmd, process.returncode, process.output))
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, process.output))
 
         # promtool may return 3 because of the "_total" suffix warnings
         if not process.returncode in [0, 3]:
-          raise AssertionError('%s failed (%d): %s' % (testcmd, process.returncode, output))
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, output))
 
         for line in output[0].splitlines():
-            if line.endswith(b"should have \"_total\" suffix"):
+            if line.endswith(b'should have "_total" suffix'):
                 continue
-            raise AssertionError('%s returned an unexpected output. Faulty line is "%s", complete content is "%s"' % (testcmd, line, output))
+            raise AssertionError(
+                '%s returned an unexpected output. Faulty line is "%s", complete content is "%s"'
+                % (testcmd, line, output)
+            )
 
     def test_program_stats_exist(self):
-        res = requests.get('http://{}/metrics'.format(self.webserver_address))
+        res = requests.get("http://{}/metrics".format(self.webserver_address))
         self.assertEqual(res.status_code, 200)
         for line in res.text.splitlines():
             if line[0] == "#":
@@ -78,19 +93,18 @@ webserver-address: %s
             if "{" in line:
                 continue
             tokens = line.split(" ")
-            self.assertIn(tokens[0],
-                          self.metric_prog_stats + self.metric_domain_stats)
-            if tokens[0] == 'ixfrdist_unknown_domain_inqueries_total':
+            self.assertIn(tokens[0], self.metric_prog_stats + self.metric_domain_stats)
+            if tokens[0] == "ixfrdist_unknown_domain_inqueries_total":
                 self.assertEqual(int(tokens[1]), 0)
 
         self.checkPrometheusContentPromtool(res.content)
 
     def test_registered(self):
-        res = requests.get('http://{}/metrics'.format(self.webserver_address))
+        res = requests.get("http://{}/metrics".format(self.webserver_address))
         self.assertEqual(res.status_code, 200)
         for line in res.text.splitlines():
-            if line.startswith('ixfrdist_domains'):
-                self.assertEqual(line, 'ixfrdist_domains 1')
+            if line.startswith("ixfrdist_domains"):
+                self.assertEqual(line, "ixfrdist_domains 1")
                 continue
             if line[0] == "#":
                 continue
@@ -100,21 +114,21 @@ webserver-address: %s
             self.assertIn(line.split("{")[0], self.metric_domain_stats)
 
     def test_metrics_have_help(self):
-        res = requests.get('http://{}/metrics'.format(self.webserver_address))
+        res = requests.get("http://{}/metrics".format(self.webserver_address))
         self.assertEqual(res.status_code, 200)
         for s in self.metric_prog_stats + self.metric_domain_stats:
-            self.assertIn('# HELP {}'.format(s), res.text)
+            self.assertIn("# HELP {}".format(s), res.text)
 
     def test_metrics_have_type(self):
-        res = requests.get('http://{}/metrics'.format(self.webserver_address))
+        res = requests.get("http://{}/metrics".format(self.webserver_address))
         self.assertEqual(res.status_code, 200)
         for s in self.metric_prog_stats + self.metric_domain_stats:
-            self.assertIn('# TYPE {}'.format(s), res.text)
+            self.assertIn("# TYPE {}".format(s), res.text)
 
     def test_missing_metrics(self):
         all_metrics = set()
 
-        res = requests.get('http://{}/metrics'.format(self.webserver_address))
+        res = requests.get("http://{}/metrics".format(self.webserver_address))
         self.assertEqual(res.status_code, 200)
 
         for line in res.text.splitlines():
@@ -126,8 +140,7 @@ webserver-address: %s
                 continue
             all_metrics.add(line.split(" ")[0])
 
-        should_have_metrics = set(self.metric_prog_stats +
-                                  self.metric_domain_stats)
+        should_have_metrics = set(self.metric_prog_stats + self.metric_domain_stats)
 
         unknown_metrics = all_metrics - should_have_metrics
 
index b3bf82be0c91dfacfdcd8c22831c656df4c95533..f6e2630d04ddf353dbefe5d2a1345b91462e7dc5 100755 (executable)
@@ -5,18 +5,18 @@ import socket
 
 # TODO use dnspython to parse/check
 
-MESSAGE=b"\xaf\x03\x00\x20\x00\x01\x00\x00\x00\x00\x00\x01\x04\x75\x6e\x69\x74\x04\x74\x65\x73\x74\x00\x00\x06\x00\x01\x00\x00\x29\x10\x00\x00\x64\x00\x00\x00\x10\x00\x0a\x00\x08\x39\x70\xad\xaf\xca\xa8\x96\xca\x00\x64\x00\x00"
+MESSAGE = b"\xaf\x03\x00\x20\x00\x01\x00\x00\x00\x00\x00\x01\x04\x75\x6e\x69\x74\x04\x74\x65\x73\x74\x00\x00\x06\x00\x01\x00\x00\x29\x10\x00\x00\x64\x00\x00\x00\x10\x00\x0a\x00\x08\x39\x70\xad\xaf\xca\xa8\x96\xca\x00\x64\x00\x00"
 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 
-sock.bind(("127.0.0.1",5502))
+sock.bind(("127.0.0.1", 5502))
 sock.sendto(MESSAGE, ("127.0.0.1", 5501))
 
 data, addr = sock.recvfrom(512)
 
 # make sure data is correct
-EXPECT=b"\xaf\x03\x84\x00\x00\x01\x00\x00\x00\x00\x00\x01\x04\x75\x6e\x69\x74\x04\x74\x65\x73\x74\x00\x00\x06\x00\x01\x00\x00\x29\x04\xd0\x01\x00\x00\x00\x00\x00"
+EXPECT = b"\xaf\x03\x84\x00\x00\x01\x00\x00\x00\x00\x00\x01\x04\x75\x6e\x69\x74\x04\x74\x65\x73\x74\x00\x00\x06\x00\x01\x00\x00\x29\x04\xd0\x01\x00\x00\x00\x00\x00"
 
-if (data != EXPECT):
-  print("Invalid EDNS response, expected extended RCODE=BADVERS, no SOA, and OPT version 0")
+if data != EXPECT:
+    print("Invalid EDNS response, expected extended RCODE=BADVERS, no SOA, and OPT version 0")
 else:
-  print("EDNS response OK")
+    print("EDNS response OK")
index 091427a4ecec7686df456d952d45e0f899cf4aab..e2fa675cb4ba8fc2a25892f7d704db153bf1631a 100755 (executable)
@@ -3,33 +3,36 @@
 import sys
 
 line = sys.stdin.readline()
-items = line.split('\t')
-if (items[0] != 'HELO'):
-    print('LOG\tGot unexpected greeting\t%s' % line)
+items = line.split("\t")
+if items[0] != "HELO":
+    print("LOG\tGot unexpected greeting\t%s" % line)
 # TOLO
-print('OK\tTest backend firing up')
+print("OK\tTest backend firing up")
 
 while True:
     line = sys.stdin.readline()
-    items = line.split('\t')
+    items = line.split("\t")
     sys.stderr.write(line)
     if len(items) < 6:
-        print('LOG\tGot an unparseable line')
-        print('LOG\t%s' % line)
-        print('END')
+        print("LOG\tGot an unparseable line")
+        print("LOG\t%s" % line)
+        print("END")
         continue
 
     what, qname, qclass, qtype, id, ip = items
 
-    if qtype in ['SOA', 'ANY'] and qname == 'example2.com':
-        print('DATA\t%s\t%s\tSOA\t300\t-1\tns1.example.com ahu.example.com 2008080300 1800 3600 604800 3600' % (qname, qclass))
+    if qtype in ["SOA", "ANY"] and qname == "example2.com":
+        print(
+            "DATA\t%s\t%s\tSOA\t300\t-1\tns1.example.com ahu.example.com 2008080300 1800 3600 604800 3600"
+            % (qname, qclass)
+        )
 
-    if qtype in ['NS', 'ANY'] and qname == 'example2.com':
-        print('DATA\t%s\t%s\tNS\t3600\t-1\tns1.example.com' % (qname, qclass))
-        print('DATA\t%s\t%s\tNS\t3600\t-1\tns2.example.com' % (qname, qclass))
+    if qtype in ["NS", "ANY"] and qname == "example2.com":
+        print("DATA\t%s\t%s\tNS\t3600\t-1\tns1.example.com" % (qname, qclass))
+        print("DATA\t%s\t%s\tNS\t3600\t-1\tns2.example.com" % (qname, qclass))
 
-    if qtype in ['A', 'ANY'] and qname.endswith('example2.com'):
+    if qtype in ["A", "ANY"] and qname.endswith("example2.com"):
         # We were asked a specific record
-        print('DATA\t%s\t%s\tCNAME\t3600\t-1\twww.example.com.' % (qname, qclass))
+        print("DATA\t%s\t%s\tCNAME\t3600\t-1\twww.example.com." % (qname, qclass))
 
-    print('END')
+    print("END")
index de0a078a8ab7520da30100e96026d2d56e838185..fc58b0910a7726201cc57bd72b4f2e413b0fac6b 100644 (file)
@@ -2,6 +2,7 @@ import dns
 from recursortests import RecursorTest
 import os
 
+
 class BasicDNSSEC(RecursorTest):
     __test__ = False
     _config_template = """dnssec=validate"""
@@ -9,19 +10,21 @@ class BasicDNSSEC(RecursorTest):
 
     @classmethod
     def setUp(cls):
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         cls.wipeRecursorCache(confdir)
 
     def testSecureAnswer(self):
-        res = self.sendQuery('ns.secure.example.', 'A')
-        expected = dns.rrset.from_text('ns.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
+        res = self.sendQuery("ns.secure.example.", "A")
+        expected = dns.rrset.from_text(
+            "ns.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expected)
         self.assertMessageIsAuthenticated(res)
 
     def testInsecureAnswer(self):
-        res = self.sendQuery('node1.insecure.example.', 'A')
+        res = self.sendQuery("node1.insecure.example.", "A")
 
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -29,72 +32,74 @@ class BasicDNSSEC(RecursorTest):
         # now we request the DS for insecure.example., which does not exist,
         # to check that we correctly get the SOA and not just the denial proof
         # that the recursor received on the delegation from example. to insecure.example.
-        res = self.sendQuery('insecure.example.', 'DS')
+        res = self.sendQuery("insecure.example.", "DS")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMessageIsAuthenticated(res)
         self.assertAuthorityHasSOA(res)
 
     def testBogusAnswer(self):
-        res = self.sendQuery('ted.bogus.example.', 'A')
+        res = self.sendQuery("ted.bogus.example.", "A")
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
 
     def testSecureNXDOMAIN(self):
-        res = self.sendQuery('nxdomain.secure.example.', 'A')
+        res = self.sendQuery("nxdomain.secure.example.", "A")
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
 
     def testInsecureNXDOMAIN(self):
-        res = self.sendQuery('nxdomain.insecure.example.', 'A')
+        res = self.sendQuery("nxdomain.insecure.example.", "A")
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
 
     def testBogusNXDOMAIN(self):
-        res = self.sendQuery('nxdomain.bogus.example.', 'A')
+        res = self.sendQuery("nxdomain.bogus.example.", "A")
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
     def testSecureOptoutAnswer(self):
-        res = self.sendQuery('node1.secure.optout.example.', 'A')
-        expected = dns.rrset.from_text('node1.secure.optout.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.8')
+        res = self.sendQuery("node1.secure.optout.example.", "A")
+        expected = dns.rrset.from_text("node1.secure.optout.example.", 0, dns.rdataclass.IN, "A", "192.0.2.8")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expected)
         self.assertMessageIsAuthenticated(res)
 
     def testInsecureOptoutAnswer(self):
-        res = self.sendQuery('node1.insecure.optout.example.', 'A')
+        res = self.sendQuery("node1.insecure.optout.example.", "A")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertNoRRSIGsInAnswer(res)
 
     def testSecureSubtreeInZoneAnswer(self):
-        res = self.sendQuery('host1.sub.secure.example.', 'A')
-        expected = dns.rrset.from_text('host1.sub.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.11')
+        res = self.sendQuery("host1.sub.secure.example.", "A")
+        expected = dns.rrset.from_text("host1.sub.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.11")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expected)
         self.assertMessageIsAuthenticated(res)
 
     def testSecureSubtreeInZoneNXDOMAIN(self):
-        res = self.sendQuery('host2.sub.secure.example.', 'A')
+        res = self.sendQuery("host2.sub.secure.example.", "A")
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertMessageIsAuthenticated(res)
 
     def testSecureWildcardAnswer(self):
-        res = self.sendQuery('something.wildcard.secure.example.', 'A')
-        expected = dns.rrset.from_text('something.wildcard.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.10')
+        res = self.sendQuery("something.wildcard.secure.example.", "A")
+        expected = dns.rrset.from_text("something.wildcard.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.10")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expected)
         self.assertMessageIsAuthenticated(res)
 
     def testSecureCNAMEWildCardAnswer(self):
-        res = self.sendQuery('something.cnamewildcard.secure.example.', 'A')
-        expectedCNAME = dns.rrset.from_text('something.cnamewildcard.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'host1.secure.example.')
-        expectedA = dns.rrset.from_text('host1.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2')
+        res = self.sendQuery("something.cnamewildcard.secure.example.", "A")
+        expectedCNAME = dns.rrset.from_text(
+            "something.cnamewildcard.secure.example.", 0, dns.rdataclass.IN, "CNAME", "host1.secure.example."
+        )
+        expectedA = dns.rrset.from_text("host1.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.2")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expectedCNAME)
@@ -103,15 +108,21 @@ class BasicDNSSEC(RecursorTest):
 
     def testSecureCNAMEWildCardNXDOMAIN(self):
         # the answer to this query reaches the UDP truncation threshold, so let's use TCP
-        res = self.sendQuery('something.cnamewildcardnxdomain.secure.example.', 'A', useTCP=True)
-        expectedCNAME = dns.rrset.from_text('something.cnamewildcardnxdomain.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'doesnotexist.secure.example.')
+        res = self.sendQuery("something.cnamewildcardnxdomain.secure.example.", "A", useTCP=True)
+        expectedCNAME = dns.rrset.from_text(
+            "something.cnamewildcardnxdomain.secure.example.",
+            0,
+            dns.rdataclass.IN,
+            "CNAME",
+            "doesnotexist.secure.example.",
+        )
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertMatchingRRSIGInAnswer(res, expectedCNAME)
         self.assertMessageIsAuthenticated(res)
 
     def testSecureNoData(self):
-        res = self.sendQuery('host1.secure.example.', 'AAAA')
+        res = self.sendQuery("host1.secure.example.", "AAAA")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnswerEmpty(res)
@@ -119,8 +130,10 @@ class BasicDNSSEC(RecursorTest):
         self.assertMessageIsAuthenticated(res)
 
     def testSecureCNAMENoData(self):
-        res = self.sendQuery('cname.secure.example.', 'AAAA')
-        expectedCNAME = dns.rrset.from_text('cname.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'host1.secure.example.')
+        res = self.sendQuery("cname.secure.example.", "AAAA")
+        expectedCNAME = dns.rrset.from_text(
+            "cname.secure.example.", 0, dns.rdataclass.IN, "CNAME", "host1.secure.example."
+        )
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expectedCNAME)
@@ -128,8 +141,10 @@ class BasicDNSSEC(RecursorTest):
         self.assertMessageIsAuthenticated(res)
 
     def testSecureWildCardNoData(self):
-        res = self.sendQuery('something.cnamewildcard.secure.example.', 'AAAA')
-        expectedCNAME = dns.rrset.from_text('something.cnamewildcard.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'host1.secure.example.')
+        res = self.sendQuery("something.cnamewildcard.secure.example.", "AAAA")
+        expectedCNAME = dns.rrset.from_text(
+            "something.cnamewildcard.secure.example.", 0, dns.rdataclass.IN, "CNAME", "host1.secure.example."
+        )
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expectedCNAME)
@@ -137,33 +152,41 @@ class BasicDNSSEC(RecursorTest):
         self.assertMessageIsAuthenticated(res)
 
     def testInsecureToSecureCNAMEAnswer(self):
-        res = self.sendQuery('cname-to-secure.insecure.example.', 'A')
-        expectedA = dns.rrset.from_text('host1.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2')
-        expectedCNAME = dns.rrset.from_text('cname-to-secure.insecure.example.', 0, dns.rdataclass.IN, 'CNAME', 'host1.secure.example.')
+        res = self.sendQuery("cname-to-secure.insecure.example.", "A")
+        expectedA = dns.rrset.from_text("host1.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.2")
+        expectedCNAME = dns.rrset.from_text(
+            "cname-to-secure.insecure.example.", 0, dns.rdataclass.IN, "CNAME", "host1.secure.example."
+        )
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA"], ["DO"])
         self.assertRRsetInAnswer(res, expectedCNAME)
         self.assertMatchingRRSIGInAnswer(res, expectedA)
 
     def testSecureToInsecureCNAMEAnswer(self):
-        res = self.sendQuery('cname-to-insecure.secure.example.', 'A')
-        expectedA = dns.rrset.from_text('node1.insecure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.6')
-        expectedCNAME = dns.rrset.from_text('cname-to-insecure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'node1.secure.example.')
+        res = self.sendQuery("cname-to-insecure.secure.example.", "A")
+        expectedA = dns.rrset.from_text("node1.insecure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.6")
+        expectedCNAME = dns.rrset.from_text(
+            "cname-to-insecure.secure.example.", 0, dns.rdataclass.IN, "CNAME", "node1.secure.example."
+        )
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA"], ["DO"])
         self.assertRRsetInAnswer(res, expectedA)
         self.assertMatchingRRSIGInAnswer(res, expectedCNAME)
 
     def testSecureDNAMEToSecureAnswer(self):
-        res = self.sendQuery('host1.dname-secure.secure.example.', 'A')
-        expectedDNAME = dns.rrset.from_text('dname-secure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
-        expectedCNAME = dns.rrset.from_text('host1.dname-secure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'host1.dname-secure.example.')
-        expectedA = dns.rrset.from_text('host1.dname-secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.21')
+        res = self.sendQuery("host1.dname-secure.secure.example.", "A")
+        expectedDNAME = dns.rrset.from_text(
+            "dname-secure.secure.example.", 0, dns.rdataclass.IN, "DNAME", "dname-secure.example."
+        )
+        expectedCNAME = dns.rrset.from_text(
+            "host1.dname-secure.secure.example.", 0, dns.rdataclass.IN, "CNAME", "host1.dname-secure.example."
+        )
+        expectedA = dns.rrset.from_text("host1.dname-secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.21")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'AD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA", "AD"], ["DO"])
         self.assertRRsetInAnswer(res, expectedA)
         self.assertRRsetInAnswer(res, expectedCNAME)
         self.assertRRsetInAnswer(res, expectedDNAME)
@@ -171,75 +194,101 @@ class BasicDNSSEC(RecursorTest):
         self.assertMatchingRRSIGInAnswer(res, expectedA)
 
     def testSecureDNAMEToSecureNXDomain(self):
-        res = self.sendQuery('nxd.dname-secure.secure.example.', 'A')
-        expectedDNAME = dns.rrset.from_text('dname-secure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
-        expectedCNAME = dns.rrset.from_text('nxd.dname-secure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'nxd.dname-secure.example.')
+        res = self.sendQuery("nxd.dname-secure.secure.example.", "A")
+        expectedDNAME = dns.rrset.from_text(
+            "dname-secure.secure.example.", 0, dns.rdataclass.IN, "DNAME", "dname-secure.example."
+        )
+        expectedCNAME = dns.rrset.from_text(
+            "nxd.dname-secure.secure.example.", 0, dns.rdataclass.IN, "CNAME", "nxd.dname-secure.example."
+        )
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'AD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA", "AD"], ["DO"])
         self.assertRRsetInAnswer(res, expectedCNAME)
         self.assertRRsetInAnswer(res, expectedDNAME)
         self.assertMatchingRRSIGInAnswer(res, expectedDNAME)
 
     def testSecureDNAMEToInsecureAnswer(self):
-        res = self.sendQuery('node1.dname-insecure.secure.example.', 'A')
-        expectedDNAME = dns.rrset.from_text('dname-insecure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'insecure.example.')
-        expectedCNAME = dns.rrset.from_text('node1.dname-insecure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'node1.insecure.example.')
-        expectedA = dns.rrset.from_text('node1.insecure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.6')
+        res = self.sendQuery("node1.dname-insecure.secure.example.", "A")
+        expectedDNAME = dns.rrset.from_text(
+            "dname-insecure.secure.example.", 0, dns.rdataclass.IN, "DNAME", "insecure.example."
+        )
+        expectedCNAME = dns.rrset.from_text(
+            "node1.dname-insecure.secure.example.", 0, dns.rdataclass.IN, "CNAME", "node1.insecure.example."
+        )
+        expectedA = dns.rrset.from_text("node1.insecure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.6")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA"], ["DO"])
         self.assertRRsetInAnswer(res, expectedA)
         self.assertRRsetInAnswer(res, expectedCNAME)
         self.assertRRsetInAnswer(res, expectedDNAME)
         self.assertMatchingRRSIGInAnswer(res, expectedDNAME)
 
     def testSecureDNAMEToInsecureNXDomain(self):
-        res = self.sendQuery('nxd.dname-insecure.secure.example.', 'A')
-        expectedDNAME = dns.rrset.from_text('dname-insecure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'insecure.example.')
-        expectedCNAME = dns.rrset.from_text('nxd.dname-insecure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'nxd.insecure.example.')
+        res = self.sendQuery("nxd.dname-insecure.secure.example.", "A")
+        expectedDNAME = dns.rrset.from_text(
+            "dname-insecure.secure.example.", 0, dns.rdataclass.IN, "DNAME", "insecure.example."
+        )
+        expectedCNAME = dns.rrset.from_text(
+            "nxd.dname-insecure.secure.example.", 0, dns.rdataclass.IN, "CNAME", "nxd.insecure.example."
+        )
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA"], ["DO"])
         self.assertRRsetInAnswer(res, expectedCNAME)
         self.assertRRsetInAnswer(res, expectedDNAME)
         self.assertMatchingRRSIGInAnswer(res, expectedDNAME)
 
     def testSecureDNAMEToBogusAnswer(self):
-        res = self.sendQuery('ted.dname-bogus.secure.example.', 'A')
+        res = self.sendQuery("ted.dname-bogus.secure.example.", "A")
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
 
     def testSecureDNAMEToBogusNXDomain(self):
-        res = self.sendQuery('nxd.dname-bogus.secure.example.', 'A')
+        res = self.sendQuery("nxd.dname-bogus.secure.example.", "A")
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
 
     def testInsecureDNAMEtoSecureAnswer(self):
-        res = self.sendQuery('host1.dname-to-secure.insecure.example.', 'A')
-        expectedDNAME = dns.rrset.from_text('dname-to-secure.insecure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
-        expectedCNAME = dns.rrset.from_text('host1.dname-to-secure.insecure.example.', 0, dns.rdataclass.IN, 'CNAME', 'host1.dname-secure.example.')
-        expectedA = dns.rrset.from_text('host1.dname-secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.21')
+        res = self.sendQuery("host1.dname-to-secure.insecure.example.", "A")
+        expectedDNAME = dns.rrset.from_text(
+            "dname-to-secure.insecure.example.", 0, dns.rdataclass.IN, "DNAME", "dname-secure.example."
+        )
+        expectedCNAME = dns.rrset.from_text(
+            "host1.dname-to-secure.insecure.example.", 0, dns.rdataclass.IN, "CNAME", "host1.dname-secure.example."
+        )
+        expectedA = dns.rrset.from_text("host1.dname-secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.21")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA"], ["DO"])
         self.assertRRsetInAnswer(res, expectedA)
         self.assertRRsetInAnswer(res, expectedCNAME)
         self.assertRRsetInAnswer(res, expectedDNAME)
         self.assertMatchingRRSIGInAnswer(res, expectedA)
 
     def testSecureDNAMEToSecureCNAMEAnswer(self):
-        res = self.sendQuery('cname-to-secure.dname-secure.secure.example.', 'A')
-
-        expectedDNAME = dns.rrset.from_text('dname-secure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
-        expectedCNAME1 = dns.rrset.from_text('cname-to-secure.dname-secure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'cname-to-secure.dname-secure.example.')
-        expectedCNAME2 = dns.rrset.from_text('cname-to-secure.dname-secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'host1.secure.example.')
-        expectedA = dns.rrset.from_text('host1.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2')
+        res = self.sendQuery("cname-to-secure.dname-secure.secure.example.", "A")
+
+        expectedDNAME = dns.rrset.from_text(
+            "dname-secure.secure.example.", 0, dns.rdataclass.IN, "DNAME", "dname-secure.example."
+        )
+        expectedCNAME1 = dns.rrset.from_text(
+            "cname-to-secure.dname-secure.secure.example.",
+            0,
+            dns.rdataclass.IN,
+            "CNAME",
+            "cname-to-secure.dname-secure.example.",
+        )
+        expectedCNAME2 = dns.rrset.from_text(
+            "cname-to-secure.dname-secure.example.", 0, dns.rdataclass.IN, "CNAME", "host1.secure.example."
+        )
+        expectedA = dns.rrset.from_text("host1.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.2")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'AD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA", "AD"], ["DO"])
         self.assertRRsetInAnswer(res, expectedA)
         self.assertRRsetInAnswer(res, expectedCNAME1)
         self.assertRRsetInAnswer(res, expectedCNAME2)
@@ -249,15 +298,25 @@ class BasicDNSSEC(RecursorTest):
         self.assertMatchingRRSIGInAnswer(res, expectedA)
 
     def testSecureDNAMEToInsecureCNAMEAnswer(self):
-        res = self.sendQuery('cname-to-insecure.dname-secure.secure.example.', 'A')
-
-        expectedDNAME = dns.rrset.from_text('dname-secure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
-        expectedCNAME1 = dns.rrset.from_text('cname-to-insecure.dname-secure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'cname-to-insecure.dname-secure.example.')
-        expectedCNAME2 = dns.rrset.from_text('cname-to-insecure.dname-secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'node1.insecure.example.')
-        expectedA = dns.rrset.from_text('node1.insecure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.6')
+        res = self.sendQuery("cname-to-insecure.dname-secure.secure.example.", "A")
+
+        expectedDNAME = dns.rrset.from_text(
+            "dname-secure.secure.example.", 0, dns.rdataclass.IN, "DNAME", "dname-secure.example."
+        )
+        expectedCNAME1 = dns.rrset.from_text(
+            "cname-to-insecure.dname-secure.secure.example.",
+            0,
+            dns.rdataclass.IN,
+            "CNAME",
+            "cname-to-insecure.dname-secure.example.",
+        )
+        expectedCNAME2 = dns.rrset.from_text(
+            "cname-to-insecure.dname-secure.example.", 0, dns.rdataclass.IN, "CNAME", "node1.insecure.example."
+        )
+        expectedA = dns.rrset.from_text("node1.insecure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.6")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA"], ["DO"])
         self.assertRRsetInAnswer(res, expectedA)
         self.assertRRsetInAnswer(res, expectedCNAME1)
         self.assertRRsetInAnswer(res, expectedCNAME2)
@@ -266,17 +325,21 @@ class BasicDNSSEC(RecursorTest):
         self.assertMatchingRRSIGInAnswer(res, expectedDNAME)
 
     def testSecureDNAMEToBogusCNAMEAnswer(self):
-        res = self.sendQuery('cname-to-bogus.dname-secure.secure.example.', 'A')
+        res = self.sendQuery("cname-to-bogus.dname-secure.secure.example.", "A")
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
 
     def testInsecureDNAMEtoSecureNXDomain(self):
-        res = self.sendQuery('nxd.dname-to-secure.insecure.example.', 'A')
-        expectedDNAME = dns.rrset.from_text('dname-to-secure.insecure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
-        expectedCNAME = dns.rrset.from_text('nxd.dname-to-secure.insecure.example.', 0, dns.rdataclass.IN, 'CNAME', 'nxd.dname-secure.example.')
+        res = self.sendQuery("nxd.dname-to-secure.insecure.example.", "A")
+        expectedDNAME = dns.rrset.from_text(
+            "dname-to-secure.insecure.example.", 0, dns.rdataclass.IN, "DNAME", "dname-secure.example."
+        )
+        expectedCNAME = dns.rrset.from_text(
+            "nxd.dname-to-secure.insecure.example.", 0, dns.rdataclass.IN, "CNAME", "nxd.dname-secure.example."
+        )
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA"], ["DO"])
         self.assertRRsetInAnswer(res, expectedCNAME)
         self.assertRRsetInAnswer(res, expectedDNAME)
index 83ab109d53951cdef2ddbaa8d86e004caf501619..43fd270d4d28161cc0c8b4cb68b29c07fdae36bd 100644 (file)
 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-""" Class to implement draft-ietf-dnsop-edns-client-subnet (previously known as
+"""Class to implement draft-ietf-dnsop-edns-client-subnet (previously known as
 draft-vandergaast-edns-client-subnet.
 
 The contained class supports both IPv4 and IPv6 addresses.
 Requirements:
   dnspython (http://www.dnspython.org/)
 """
+
 from __future__ import print_function
 from __future__ import division
 
@@ -77,11 +78,11 @@ class ClientSubnetOption(dns.edns.Option):
                 n = socket.inet_pton(family, ip)
                 if family == socket.AF_INET6:
                     f = FAMILY_IPV6
-                    hi, lo = struct.unpack('!QQ', n)
+                    hi, lo = struct.unpack("!QQ", n)
                     ip = hi << 64 | lo
                 elif family == socket.AF_INET:
                     f = FAMILY_IPV4
-                    ip = struct.unpack('!L', n)[0]
+                    ip = struct.unpack("!L", n)[0]
             except Exception:
                 pass
 
@@ -117,13 +118,13 @@ class ClientSubnetOption(dns.edns.Option):
 
         ip = self.ip >> bits - self.mask
 
-        if (self.mask % 8 != 0):
+        if self.mask % 8 != 0:
             ip = ip << 8 - (self.mask % 8)
 
         return ip
 
     def is_draft(self):
-        """" Determines whether this instance is using the draft option code """
+        """ " Determines whether this instance is using the draft option code"""
         return self.option == DRAFT_OPTION_CODE
 
     def to_wire(self, file=None):
@@ -133,13 +134,13 @@ class ClientSubnetOption(dns.edns.Option):
 
         mask_bits = self.mask
         if mask_bits % 8 != 0:
-                mask_bits += 8 - (self.mask % 8)
+            mask_bits += 8 - (self.mask % 8)
 
         if self.family == FAMILY_IPV4:
             test = struct.pack("!L", ip)
         elif self.family == FAMILY_IPV6:
-            test = struct.pack("!QQ", ip >> 64, ip & (2 ** 64 - 1))
-        test = test[-(mask_bits // 8):]
+            test = struct.pack("!QQ", ip >> 64, ip & (2**64 - 1))
+        test = test[-(mask_bits // 8) :]
 
         format = "!HBB%ds" % (mask_bits // 8)
         data = struct.pack(format, self.family, self.mask, self.scope, test)
@@ -155,7 +156,7 @@ class ClientSubnetOption(dns.edns.Option):
             An instance of ClientSubnetOption based on the ENDS packet
         """
 
-        data = wire[current:current + olen]
+        data = wire[current : current + olen]
         (family, mask, scope) = struct.unpack("!HBB", data[:4])
 
         c_mask = mask
@@ -164,11 +165,11 @@ class ClientSubnetOption(dns.edns.Option):
 
         ip = struct.unpack_from("!%ds" % (c_mask // 8), data, 4)[0]
 
-        if (family == FAMILY_IPV4):
-            ip = ip + b'\0' * ((32 - c_mask) // 8)
+        if family == FAMILY_IPV4:
+            ip = ip + b"\0" * ((32 - c_mask) // 8)
             ip = socket.inet_ntop(socket.AF_INET, ip)
-        elif (family == FAMILY_IPV6):
-            ip = ip + b'\0' * ((128 - c_mask) // 8)
+        elif family == FAMILY_IPV6:
+            ip = ip + b"\0" * ((128 - c_mask) // 8)
             ip = socket.inet_ntop(socket.AF_INET6, ip)
         else:
             raise Exception("Returned a family other then IPv4 or IPv6")
@@ -180,35 +181,27 @@ class ClientSubnetOption(dns.edns.Option):
     # needed in 2.0.0..
     @classmethod
     def from_wire_parser(cls, otype, parser):
-        family, src, scope = parser.get_struct('!HBB')
+        family, src, scope = parser.get_struct("!HBB")
         addrlen = int(math.ceil(src / 8.0))
         prefix = parser.get_bytes(addrlen)
         if family == 1:
             pad = 4 - addrlen
-            addr = dns.ipv4.inet_ntoa(prefix + b'\x00' * pad)
+            addr = dns.ipv4.inet_ntoa(prefix + b"\x00" * pad)
         elif family == 2:
             pad = 16 - addrlen
-            addr = dns.ipv6.inet_ntoa(prefix + b'\x00' * pad)
+            addr = dns.ipv6.inet_ntoa(prefix + b"\x00" * pad)
         else:
-            raise ValueError('unsupported family')
+            raise ValueError("unsupported family")
 
         return cls(addr, src, scope, otype)
 
     def __repr__(self):
         if self.family == FAMILY_IPV4:
-            ip = socket.inet_ntop(socket.AF_INET, struct.pack('!L', self.ip))
+            ip = socket.inet_ntop(socket.AF_INET, struct.pack("!L", self.ip))
         elif self.family == FAMILY_IPV6:
-            ip = socket.inet_ntop(socket.AF_INET6,
-                                  struct.pack('!QQ',
-                                              self.ip >> 64,
-                                              self.ip & (2 ** 64 - 1)))
-
-        return "%s(%s, %s, %s)" % (
-            self.__class__.__name__,
-            ip,
-            self.mask,
-            self.scope
-        )
+            ip = socket.inet_ntop(socket.AF_INET6, struct.pack("!QQ", self.ip >> 64, self.ip & (2**64 - 1)))
+
+        return "%s(%s, %s, %s)" % (self.__class__.__name__, ip, self.mask, self.scope)
 
     def to_text(self):
         return self.__repr__()
@@ -280,13 +273,25 @@ if __name__ == "__main__":
                 print("Found ClientSubnetOption...", end=None, file=sys.stderr)
                 if not cso.family == options.family:
                     error = True
-                    print("\nFailed: returned family (%d) is different from the passed family (%d)" % (options.family, cso.family), file=sys.stderr)
+                    print(
+                        "\nFailed: returned family (%d) is different from the passed family (%d)"
+                        % (options.family, cso.family),
+                        file=sys.stderr,
+                    )
                 if not cso.calculate_ip() == options.calculate_ip():
                     error = True
-                    print("\nFailed: returned ip (%s) is different from the passed ip (%s)." % (options.calculate_ip(), cso.calculate_ip()), file=sys.stderr)
+                    print(
+                        "\nFailed: returned ip (%s) is different from the passed ip (%s)."
+                        % (options.calculate_ip(), cso.calculate_ip()),
+                        file=sys.stderr,
+                    )
                 if not options.mask == cso.mask:
                     error = True
-                    print("\nFailed: returned mask bits (%d) is different from the passed mask bits (%d)" % (options.mask, cso.mask), file=sys.stderr)
+                    print(
+                        "\nFailed: returned mask bits (%d) is different from the passed mask bits (%d)"
+                        % (options.mask, cso.mask),
+                        file=sys.stderr,
+                    )
                 if not options.scope != 0:
                     print("\nWarning: scope indicates edns-clientsubnet data is not used", file=sys.stderr)
                 if options.is_draft():
@@ -299,17 +304,19 @@ if __name__ == "__main__":
         else:
             print("Failed: No ClientSubnetOption returned", file=sys.stderr)
 
-    parser = argparse.ArgumentParser(description='draft-vandergaast-edns-client-subnet-01 tester')
-    parser.add_argument('nameserver', help='The nameserver to test')
-    parser.add_argument('rr', help='DNS record that should return an EDNS enabled response')
-    parser.add_argument('-s', '--subnet', help='Specifies an IP to pass as the client subnet.', default='192.0.2.0')
-    parser.add_argument('-m', '--mask', type=int, help='CIDR mask to use for subnet')
-    parser.add_argument('--timeout', type=int, help='Set the timeout for query to TIMEOUT seconds, default=10', default=10)
-    parser.add_argument('-t', '--type', help='DNS query type, default=A', default='A')
+    parser = argparse.ArgumentParser(description="draft-vandergaast-edns-client-subnet-01 tester")
+    parser.add_argument("nameserver", help="The nameserver to test")
+    parser.add_argument("rr", help="DNS record that should return an EDNS enabled response")
+    parser.add_argument("-s", "--subnet", help="Specifies an IP to pass as the client subnet.", default="192.0.2.0")
+    parser.add_argument("-m", "--mask", type=int, help="CIDR mask to use for subnet")
+    parser.add_argument(
+        "--timeout", type=int, help="Set the timeout for query to TIMEOUT seconds, default=10", default=10
+    )
+    parser.add_argument("-t", "--type", help="DNS query type, default=A", default="A")
     args = parser.parse_args()
 
     if not args.mask:
-        if ':' in args.subnet:
+        if ":" in args.subnet:
             args.mask = 48
         else:
             args.mask = 24
index 3834ba6d4c6680a61f1f5a2a9239892329edf20f..905f0f1d6b429486a375bcf53ac6982954c7b6b4 100644 (file)
@@ -3,14 +3,15 @@ import shutil
 from recursortests import RecursorTest
 import pytest
 
-@pytest.fixture(scope='session')
+
+@pytest.fixture(scope="session")
 def run_auths() -> str:
-    confdir = 'configs/auths'
+    confdir = "configs/auths"
     shutil.rmtree(confdir, True)
     os.mkdir(confdir)
-    print('\nStarting auths from fixture...')
+    print("\nStarting auths from fixture...")
     RecursorTest.generateAllAuthConfig(confdir)
     RecursorTest.startAllAuth(confdir)
     yield "Here's Johnny!"
-    print('\nStopping auths by fixture')
+    print("\nStopping auths by fixture")
     RecursorTest.tearDownAuth()
index 5646d8b761aea2d076f8bf6670f331049faec94f..785d8970da7adf9af2d95baff87e941f3b592272 100644 (file)
@@ -7,9 +7,9 @@ import dns.flags
 import dns.message
 import dns.query
 
+
 class ExtendedErrorOption(dns.edns.Option):
-    """Implementation of rfc8914
-    """
+    """Implementation of rfc8914"""
 
     def __init__(self, code, extra):
         super(ExtendedErrorOption, self).__init__(15)
@@ -20,7 +20,7 @@ class ExtendedErrorOption(dns.edns.Option):
     def to_wire(self, file=None):
         """Create EDNS packet."""
 
-        data = struct.pack('!H', self.code)
+        data = struct.pack("!H", self.code)
         data = data + self.extra
         if not file:
             return data
@@ -35,13 +35,13 @@ class ExtendedErrorOption(dns.edns.Option):
         """
 
         if olen < 2:
-            raise Exception('Invalid EDNS Extended Error option')
+            raise Exception("Invalid EDNS Extended Error option")
 
-        (code,) = struct.unpack('!H', wire[current:current+2])
+        (code,) = struct.unpack("!H", wire[current : current + 2])
         if olen > 2:
-            extra = wire[current + 2:current + olen]
+            extra = wire[current + 2 : current + olen]
         else:
-            extra = b''
+            extra = b""
 
         return cls(code, extra)
 
@@ -53,22 +53,18 @@ class ExtendedErrorOption(dns.edns.Option):
         data = parser.get_remaining()
 
         if len(data) < 2:
-            raise Exception('Invalid EDNS Extended Error option')
+            raise Exception("Invalid EDNS Extended Error option")
 
-        (code,) = struct.unpack('!H', data[0:2])
+        (code,) = struct.unpack("!H", data[0:2])
         if len(data) > 2:
             extra = data[2:]
         else:
-            extra = b''
+            extra = b""
 
         return cls(code, extra)
 
     def __repr__(self):
-        return '%s(%d, %s)' % (
-            self.__class__.__name__,
-            self.code,
-            self.extra
-        )
+        return "%s(%d, %s)" % (self.__class__.__name__, self.code, self.extra)
 
     def to_text(self):
         return self.__repr__()
index cb085d5bc0ea7652765627039097205b67ec7256..bb3382e1a129442a1abb5e4bc13e17d1aacf8de6 100644 (file)
@@ -6,9 +6,9 @@ import dns.flags
 import dns.message
 import dns.query
 
+
 class PaddingOption(dns.edns.Option):
-    """Implementation of rfc7830.
-    """
+    """Implementation of rfc7830."""
 
     def __init__(self, numberOfBytes):
         super(PaddingOption, self).__init__(12)
@@ -42,10 +42,7 @@ class PaddingOption(dns.edns.Option):
         return cls(len(data))
 
     def __repr__(self):
-        return '%s(%d)' % (
-            self.__class__.__name__,
-            self.numberOfBytes
-        )
+        return "%s(%d)" % (self.__class__.__name__, self.numberOfBytes)
 
     def to_text(self):
         return self.__repr__()
index 8533744504bbe90d97f54f4db35c02daba67e519..92658f37891781ca95dfcb510a36f1309076b157 100755 (executable)
@@ -5,7 +5,7 @@ import xml.etree.ElementTree
 import os.path
 import glob
 
-e = xml.etree.ElementTree.parse('pytest.xml')
+e = xml.etree.ElementTree.parse("pytest.xml")
 testsuites = e.getroot()
 
 for testsuite in testsuites:
@@ -14,12 +14,12 @@ for testsuite in testsuites:
         for testcase in testsuite:
             cls = testcase.get("classname")
             name = testcase.get("name")
-            if '_' not in cls or '.' not in cls:
-                print('Unexpected classname %s; name %s' % (cls, name))
+            if "_" not in cls or "." not in cls:
+                print("Unexpected classname %s; name %s" % (cls, name))
                 getstdout = True
                 continue
 
-            confdirnames = [cls.split('_')[1].split('.')[0], cls.split('.')[1].split('Test')[0]]
+            confdirnames = [cls.split("_")[1].split(".")[0], cls.split(".")[1].split("Test")[0]]
             found = False
             for confdirname in confdirnames:
                 confdir = os.path.join("configs", confdirname)
@@ -30,17 +30,17 @@ for testsuite in testsuites:
                         if elem.tag in ["failure", "error"]:
                             print("==============> %s <==============" % recursorlog)
                             with open(recursorlog) as f:
-                                print(''.join(f.readlines()))
+                                print("".join(f.readlines()))
                                 authdirs = glob.glob(os.path.join(confdir, "auth-*"))
                                 for authdir in authdirs:
                                     authlog = os.path.join(authdir, "pdns.log")
                                     if os.path.exists(recursorlog):
                                         print("==============> %s <==============" % authlog)
                                         with open(authlog) as f:
-                                            print(''.join(f.readlines()))
-            if not found and confdirnames[0] != 'Flags': 
+                                            print("".join(f.readlines()))
+            if not found and confdirnames[0] != "Flags":
                 print("%s not found, configdir does not mach expected pattern" % confdirnames)
-        if getstdout and elem.tag == 'system-out':
+        if getstdout and elem.tag == "system-out":
             print("==============> STDOUT LOG FROM XML <==============")
             print(elem.text)
             print("==============> END STDOUT LOG FROM XML <==============")
index 2859bf9ea5d1711e174d66e589f738242dc3e323..3be957c9e415c28b7ff6a31deea86088a30fd6fc 100644 (file)
@@ -29,7 +29,7 @@ def have_ipv6():
     """
     try:
         sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
-        sock.bind(('::1', 56581))
+        sock.bind(("::1", 56581))
         sock.close()
         return True
     except Exception:
@@ -42,13 +42,13 @@ class RecursorTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     Setup all recursors and auths required for the tests
     """
 
-    _confdir = 'recursor'
+    _confdir = "recursor"
 
     _recursorPort = 5300
 
     _recursor = None
 
-    _PREFIX = os.environ['PREFIX']
+    _PREFIX = os.environ["PREFIX"]
 
     _config_template_default = """
 daemon=no
@@ -91,11 +91,14 @@ logging:
     _config_params = []
     _lua_config_file = None
     _lua_dns_script_file = None
-    _roothints = """
+    _roothints = (
+        """
 .                        3600 IN NS  ns.root.
 ns.root.                 3600 IN A   %s.8
 ns.root.                 3600 IN AAAA ::1
-""" % _PREFIX
+"""
+        % _PREFIX
+    )
     _root_DS = "63149 13 1 a59da3f5c1b97fcd5fa2b3b2b0ac91d38a60d33a"
 
     # The default SOA for zones in the authoritative servers
@@ -106,7 +109,7 @@ ns.root.                 3600 IN AAAA ::1
     #   - {soa} => value of _SOA
     #   - {prefix} value of _PREFIX
     _zones = {
-        'ROOT': """
+        "ROOT": """
 .                        3600 IN SOA  {soa}
 .                        3600 IN NS   ns.root.
 ns.root.                 3600 IN A    {prefix}.8
@@ -118,7 +121,7 @@ example.                 3600 IN DS   53174 13 1 50c9e913818767c236c06c2d8272723
 ns1.example.             3600 IN A    {prefix}.10
 ns2.example.             3600 IN A    {prefix}.18
         """,
-        'example': """
+        "example": """
 example.                 3600 IN SOA  {soa}
 example.                 3600 IN NS   ns1.example.
 example.                 3600 IN NS   ns2.example.
@@ -183,7 +186,7 @@ cname-nodata-target.example.        3600 IN A 192.0.2.101
 cname-custom-a.example.             3600 IN CNAME cname-custom-a-target.example.
 cname-custom-a-target.example.      3600 IN A 192.0.2.102
         """,
-        'secure.example': """
+        "secure.example": """
 secure.example.          3600 IN SOA  {soa}
 secure.example.          3600 IN NS   ns.secure.example.
 ns.secure.example.       3600 IN A    {prefix}.9
@@ -236,7 +239,7 @@ non-apex-dnskey.secure.example. 3600 IN DNSKEY 257 3 13 CT6AJ4MEOtNDgj0+xLtTLGHf
 non-apex-dnskey2.secure.example. 3600 IN DNSKEY 256 3 13 CT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==
 non-apex-dnskey3.secure.example. 3600 IN DNSKEY 256 3 13 DT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==
         """,
-        'dname-secure.example': """
+        "dname-secure.example": """
 dname-secure.example. 3600 IN SOA {soa}
 dname-secure.example. 3600 IN NS ns.dname-secure.example.
 ns.dname-secure.example. 3600 IN A {prefix}.13
@@ -247,26 +250,26 @@ cname-to-secure.dname-secure.example. 3600 IN CNAME host1.secure.example.
 cname-to-insecure.dname-secure.example. 3600 IN CNAME node1.insecure.example.
 cname-to-bogus.dname-secure.example.    3600 IN CNAME ted.bogus.example.
 """,
-        'cname-secure.example': """
+        "cname-secure.example": """
 cname-secure.example.          3600 IN SOA   {soa}
 cname-secure.example.          3600 IN NS    ns.cname-secure.example.
 ns.cname-secure.example.       3600 IN A     {prefix}.15
 cname-secure.example.          3600 IN CNAME secure.example.
         """,
-        'bogus.example': """
+        "bogus.example": """
 bogus.example.           3600 IN SOA  {soa}
 bogus.example.           3600 IN NS   ns1.bogus.example.
 ns1.bogus.example.       3600 IN A    {prefix}.12
 ted.bogus.example.       3600 IN A    192.0.2.1
 bill.bogus.example.      3600 IN AAAA 2001:db8:12::3
         """,
-        'insecure.sub2.secure.example': """
+        "insecure.sub2.secure.example": """
 insecure.sub2.secure.example.        3600 IN SOA  {soa}
 insecure.sub2.secure.example.        3600 IN NS   ns1.insecure.example.
 
 node1.insecure.sub2.secure.example.  3600 IN A    192.0.2.18
         """,
-        'insecure.example': """
+        "insecure.example": """
 insecure.example.        3600 IN SOA  {soa}
 insecure.example.        3600 IN NS   ns1.insecure.example.
 ns1.insecure.example.    3600 IN A    {prefix}.13
@@ -277,7 +280,7 @@ cname-to-secure.insecure.example. 3600 IN CNAME host1.secure.example.
 
 dname-to-secure.insecure.example. 3600 IN DNAME dname-secure.example.
         """,
-        'optout.example': """
+        "optout.example": """
 optout.example.        3600 IN SOA  {soa}
 optout.example.        3600 IN NS   ns1.optout.example.
 ns1.optout.example.    3600 IN A    {prefix}.14
@@ -289,41 +292,40 @@ secure.optout.example.     3600 IN NS ns1.secure.optout.example.
 secure.optout.example.     3600 IN DS 64215 13 1 b88284d7a8d8605c398e8942262f97b9a5a31787
 ns1.secure.optout.example. 3600 IN A  {prefix}.15
         """,
-        'insecure.optout.example': """
+        "insecure.optout.example": """
 insecure.optout.example.        3600 IN SOA  {soa}
 insecure.optout.example.        3600 IN NS   ns1.insecure.optout.example.
 ns1.insecure.optout.example.    3600 IN A    {prefix}.15
 
 node1.insecure.optout.example.  3600 IN A    192.0.2.7
         """,
-        'secure.optout.example': """
+        "secure.optout.example": """
 secure.optout.example.          3600 IN SOA  {soa}
 secure.optout.example.          3600 IN NS   ns1.secure.optout.example.
 ns1.secure.optout.example.      3600 IN A    {prefix}.15
 
 node1.secure.optout.example.    3600 IN A    192.0.2.8
         """,
-        'islandofsecurity.example': """
+        "islandofsecurity.example": """
 islandofsecurity.example.          3600 IN SOA  {soa}
 islandofsecurity.example.          3600 IN NS   ns1.islandofsecurity.example.
 ns1.islandofsecurity.example.      3600 IN A    {prefix}.9
 
 node1.islandofsecurity.example.    3600 IN A    192.0.2.20
         """,
-        'undelegated.secure.example': """
+        "undelegated.secure.example": """
 undelegated.secure.example.        3600 IN SOA  {soa}
 undelegated.secure.example.        3600 IN NS   ns1.undelegated.secure.example.
 
 node1.undelegated.secure.example.  3600 IN A    192.0.2.21
         """,
-        'undelegated.insecure.example': """
+        "undelegated.insecure.example": """
 undelegated.insecure.example.        3600 IN SOA  {soa}
 undelegated.insecure.example.        3600 IN NS   ns1.undelegated.insecure.example.
 
 node1.undelegated.insecure.example.  3600 IN A    192.0.2.22
         """,
-
-        'delay1.example': """
+        "delay1.example": """
 delay1.example.                       3600 IN SOA  {soa}
 delay1.example.                       3600 IN NS n1.delay1.example.
 ns1.delay1.example.                   3600 IN A    {prefix}.16
@@ -331,112 +333,89 @@ ns1.delay1.example.                   3600 IN A    {prefix}.16
 *.delay1.example.                     0    LUA TXT ";" "local socket=require('socket')" "socket.sleep(tonumber(qname:getRawLabels()[1])/10)" "return 'a'"
 *.delay1.example.                     0    LUA AAAA ";" "local socket=require('socket')" "socket.sleep(tonumber(qname:getRawLabels()[1])/10)" "return '1::2'"
         """,
-        
-        'delay2.example': """
+        "delay2.example": """
 delay2.example.                       3600 IN SOA  {soa}
 delay2.example.                       3600 IN NS n1.delay2.example.
 ns1.delay2.example.                   3600 IN A    {prefix}.17
 *.delay2.example.                     0    LUA TXT ";" "local socket=require('socket')" "socket.sleep(tonumber(qname:getRawLabels()[1])/10)" "return 'a'"
-        """
+        """,
     }
 
     # The private keys for the zones (note that DS records should go into
     # the zonecontent in _zones
     _zone_keys = {
-        'ROOT': """
+        "ROOT": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: rhWuEydDz3QaIspSVj683B8Xq5q/ozzA38XUgzD4Fbo=
         """,
-
-        'example': """
+        "example": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: Lt0v0Gol3pRUFM7fDdcy0IWN0O/MnEmVPA+VylL8Y4U=
         """,
-
-        'secure.example': """
+        "secure.example": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: 1G4WRoOFJJXk+fotDCHVORtJmIG2OUhKi8AO2jDPGZA=
         """,
-
-        'bogus.example': """
+        "bogus.example": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: f5jV7Q8kd5hDpMWObsuQ6SQda0ftf+JrO3uZwEg6nVw=
         """,
-
-        'optout.example': """
+        "optout.example": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: efmq9G+J4Y2iPnIBRwJiy6Z/nIHSzpsCy/7XHhlS19A=
         """,
-
-        'secure.optout.example': """
+        "secure.optout.example": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: xcNUxt1Knj14A00lKQFDboluiJyM2f7FxpgsQaQ3AQ4=
         """,
-
-        'islandofsecurity.example': """
+        "islandofsecurity.example": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: o9F5iix8V68tnMcuOaM2Lt8XXhIIY//SgHIHEePk6cM=
         """,
-
-        'cname-secure.example': """
+        "cname-secure.example": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: kvoV/g4IO/tefSro+FLJ5UC7H3BUf0IUtZQSUOfQGyA=
 """,
-
-        'dname-secure.example': """
+        "dname-secure.example": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
 """,
-
-        'delay1.example': """
+        "delay1.example": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
 """,
-
-        'delay2.example': """
+        "delay2.example": """
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
-"""
+""",
     }
 
     # This dict is keyed with the suffix of the IP address and its value
     # is a list of zones hosted on that IP. Note that delegations should
     # go into the _zones's zonecontent
     _default_auth_zones = {
-        '8': {'threads': 1,
-              'zones': ['ROOT']},
-        '9': {'threads': 1,
-              'zones': ['secure.example', 'islandofsecurity.example']},
-        '10': {'threads': 1,
-               'zones': ['example']},
-
+        "8": {"threads": 1, "zones": ["ROOT"]},
+        "9": {"threads": 1, "zones": ["secure.example", "islandofsecurity.example"]},
+        "10": {"threads": 1, "zones": ["example"]},
         # 11 is used by CircleCI provided resolver
-
-        '12': {'threads': 1,
-               'zones': ['bogus.example', 'undelegated.secure.example', 'undelegated.insecure.example']},
-        '13': {'threads': 1,
-               'zones': ['insecure.example', 'insecure.sub2.secure.example', 'dname-secure.example']},
-        '14': {'threads': 1,
-               'zones': ['optout.example']},
-        '15': {'threads': 1,
-               'zones': ['insecure.optout.example', 'secure.optout.example', 'cname-secure.example']},
-        '16': {'threads': 10,
-               'zones': ['delay1.example']},
-        '17': {'threads': 10,
-               'zones': ['delay2.example']},
-        '18': {'threads': 1,
-               'zones': ['example']}
+        "12": {"threads": 1, "zones": ["bogus.example", "undelegated.secure.example", "undelegated.insecure.example"]},
+        "13": {"threads": 1, "zones": ["insecure.example", "insecure.sub2.secure.example", "dname-secure.example"]},
+        "14": {"threads": 1, "zones": ["optout.example"]},
+        "15": {"threads": 1, "zones": ["insecure.optout.example", "secure.optout.example", "cname-secure.example"]},
+        "16": {"threads": 10, "zones": ["delay1.example"]},
+        "17": {"threads": 10, "zones": ["delay2.example"]},
+        "18": {"threads": 1, "zones": ["example"]},
     }
     _auth_zones = _default_auth_zones
     # Other IPs used:
@@ -451,8 +430,7 @@ PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
     # 25: test_Cookies.py
     # 26: test_Cookies.py
 
-    _auth_cmd = ['authbind',
-                 os.environ['PDNS']]
+    _auth_cmd = ["authbind", os.environ["PDNS"]]
     _auth_env = {}
     _auths = {}
 
@@ -464,34 +442,41 @@ PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
             if e.errno != errno.ENOENT:
                 raise
         os.mkdir(confdir, 0o755)
-        os.mkdir(confdir + '/include', 0o755)
+        os.mkdir(confdir + "/include", 0o755)
 
     @classmethod
     def generateAuthZone(cls, confdir, zonename, zonecontent):
-        with open(os.path.join(confdir, '%s.zone' % zonename), 'w') as zonefile:
+        with open(os.path.join(confdir, "%s.zone" % zonename), "w") as zonefile:
             zonefile.write(zonecontent.format(prefix=cls._PREFIX, soa=cls._SOA))
 
     @classmethod
     def generateAuthNamedConf(cls, confdir, zones):
-        with open(os.path.join(confdir, 'named.conf'), 'w') as namedconf:
-            namedconf.write("""
+        with open(os.path.join(confdir, "named.conf"), "w") as namedconf:
+            namedconf.write(
+                """
 options {
     directory "%s";
-};""" % confdir)
+};"""
+                % confdir
+            )
             for zonename in zones:
-                zone = '.' if zonename == 'ROOT' else zonename
+                zone = "." if zonename == "ROOT" else zonename
 
-                namedconf.write("""
+                namedconf.write(
+                    """
         zone "%s" {
             type master;
             file "%s.zone";
-        };""" % (zone, zonename))
+        };"""
+                    % (zone, zonename)
+                )
 
     @classmethod
-    def generateAuthConfig(cls, confdir, threads, extra=''):
-        bind_dnssec_db = os.path.join(confdir, 'bind-dnssec.sqlite3')
-        with open(os.path.join(confdir, 'pdns.conf'), 'w') as pdnsconf:
-            pdnsconf.write("""
+    def generateAuthConfig(cls, confdir, threads, extra=""):
+        bind_dnssec_db = os.path.join(confdir, "bind-dnssec.sqlite3")
+        with open(os.path.join(confdir, "pdns.conf"), "w") as pdnsconf:
+            pdnsconf.write(
+                """
 module-dir={moduledir}
 launch=bind
 daemon=no
@@ -507,74 +492,71 @@ loglevel=9
 enable-lua-records
 dname-processing=yes
 distributor-threads={threads}
-{extra}""".format(moduledir=os.environ['PDNSMODULEDIR'],
-                  confdir=confdir,
-                  bind_dnssec_db=bind_dnssec_db,
-                  threads=threads,
-                  extra=extra))
+{extra}""".format(
+                    moduledir=os.environ["PDNSMODULEDIR"],
+                    confdir=confdir,
+                    bind_dnssec_db=bind_dnssec_db,
+                    threads=threads,
+                    extra=extra,
+                )
+            )
 
-        pdnsutilCmd = [os.environ['PDNSUTIL'],
-                       '--config-dir=%s' % confdir,
-                       'create-bind-db',
-                       bind_dnssec_db]
+        pdnsutilCmd = [os.environ["PDNSUTIL"], "--config-dir=%s" % confdir, "create-bind-db", bind_dnssec_db]
 
         try:
             subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
     @classmethod
     def secureZone(cls, confdir, zonename, key=None):
-        zone = '.' if zonename == 'ROOT' else zonename
+        zone = "." if zonename == "ROOT" else zonename
         if not key:
-            pdnsutilCmd = [os.environ['PDNSUTIL'],
-                           '--config-dir=%s' % confdir,
-                           'secure-zone',
-                           zone]
+            pdnsutilCmd = [os.environ["PDNSUTIL"], "--config-dir=%s" % confdir, "secure-zone", zone]
         else:
-            keyfile = os.path.join(confdir, 'dnssec.key')
-            with open(keyfile, 'w') as fdKeyfile:
+            keyfile = os.path.join(confdir, "dnssec.key")
+            with open(keyfile, "w") as fdKeyfile:
                 fdKeyfile.write(key)
 
-            pdnsutilCmd = [os.environ['PDNSUTIL'],
-                           '--config-dir=%s' % confdir,
-                           'import-zone-key',
-                           zone,
-                           keyfile,
-                           'active',
-                           'ksk']
-
-        print(' '.join(pdnsutilCmd))
+            pdnsutilCmd = [
+                os.environ["PDNSUTIL"],
+                "--config-dir=%s" % confdir,
+                "import-zone-key",
+                zone,
+                keyfile,
+                "active",
+                "ksk",
+            ]
+
+        print(" ".join(pdnsutilCmd))
         try:
             subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
     @classmethod
     def generateAllAuthConfig(cls, confdir):
         if cls._auth_zones:
             for auth_suffix, zoneinfo in cls._auth_zones.items():
-                threads = zoneinfo['threads']
-                zones = zoneinfo['zones']
-                authconfdir = os.path.join(confdir, 'auth-%s' % auth_suffix)
+                threads = zoneinfo["threads"]
+                zones = zoneinfo["zones"]
+                authconfdir = os.path.join(confdir, "auth-%s" % auth_suffix)
 
                 os.mkdir(authconfdir)
                 cls.generateAuthConfig(authconfdir, threads)
                 cls.generateAuthNamedConf(authconfdir, zones)
 
                 for zone in zones:
-                    cls.generateAuthZone(authconfdir,
-                                         zone,
-                                         cls._zones[zone])
+                    cls.generateAuthZone(authconfdir, zone, cls._zones[zone])
                     if cls._zone_keys.get(zone, None):
                         cls.secureZone(authconfdir, zone, cls._zone_keys.get(zone))
 
     @classmethod
     def setUpClassSpecialAuths(cls):
         # tear down existing auths, and start with our own special config
-        confdir = os.path.join('configs', 'auths')
+        confdir = os.path.join("configs", "auths")
         cls.tearDownAuth()
-        #confdir = os.path.join('configs', cls._confdir)
+        # confdir = os.path.join('configs', cls._confdir)
         print("Specialized auth setup" + confdir)
         cls.createConfigDir(confdir)
         cls.generateAllAuthConfig(confdir)
@@ -584,8 +566,8 @@ distributor-threads={threads}
     def startAllAuth(cls, confdir):
         if cls._auth_zones:
             for auth_suffix, _ in cls._auth_zones.items():
-                authconfdir = os.path.join(confdir, 'auth-%s' % auth_suffix)
-                ipaddress = cls._PREFIX + '.' + auth_suffix
+                authconfdir = os.path.join(confdir, "auth-%s" % auth_suffix)
+                ipaddress = cls._PREFIX + "." + auth_suffix
                 cls.startAuth(authconfdir, ipaddress)
 
     @classmethod
@@ -599,26 +581,26 @@ distributor-threads={threads}
                 return
             except Exception as err:
                 if err.errno != errno.ECONNREFUSED:
-                    print(f'Error occurred: {try_number} {err}', file=sys.stderr)
+                    print(f"Error occurred: {try_number} {err}", file=sys.stderr)
             time.sleep(0.01)
 
     @classmethod
     def startAuth(cls, confdir, ipaddress):
         print("Launching pdns_server..")
         authcmd = list(cls._auth_cmd)
-        authcmd.append('--config-dir=%s' % confdir)
+        authcmd.append("--config-dir=%s" % confdir)
         ipconfig = ipaddress
         # auth-8 is the auth serving the root, it gets an ipv6 address
         if (confdir[-6:] == "auth-8") and have_ipv6():
-            ipconfig += ',::1'
-        authcmd.append('--local-address=%s' % ipconfig)
-        print(' '.join(authcmd))
+            ipconfig += ",::1"
+        authcmd.append("--local-address=%s" % ipconfig)
+        print(" ".join(authcmd))
 
-        logFile = os.path.join(confdir, 'pdns.log')
-        with open(logFile, 'w') as fdLog:
-            cls._auths[ipaddress] = subprocess.Popen(authcmd, close_fds=True,
-                                                     stdout=fdLog, stderr=fdLog,
-                                                     env=cls._auth_env)
+        logFile = os.path.join(confdir, "pdns.log")
+        with open(logFile, "w") as fdLog:
+            cls._auths[ipaddress] = subprocess.Popen(
+                authcmd, close_fds=True, stdout=fdLog, stderr=fdLog, env=cls._auth_env
+            )
 
         cls.waitForTCPSocket(ipaddress, 53)
         cls.checkAuth(cls._auths[ipaddress], authcmd, logFile)
@@ -627,15 +609,15 @@ distributor-threads={threads}
     def checkAuth(cls, auth, authcmd, logFile):
         if auth.poll() is not None:
             print(f"\n*** startAuth log for {logFile} ***")
-            with open(logFile, 'r') as fdLog:
+            with open(logFile, "r") as fdLog:
                 print(fdLog.read())
             print(f"*** End startAuth log for {logFile} ***")
-            raise AssertionError('%s failed (%d)' % (authcmd, auth.returncode))
+            raise AssertionError("%s failed (%d)" % (authcmd, auth.returncode))
 
     @classmethod
     def checkConfdir(cls, confdir):
-        if cls.__name__ != 'FlagsTest' and os.path.basename(confdir) + 'Test' != cls.__name__:
-            raise AssertionError('conf dir ' + confdir + ' and ' + cls.__name__ + ' inconsistent with convention')
+        if cls.__name__ != "FlagsTest" and os.path.basename(confdir) + "Test" != cls.__name__:
+            raise AssertionError("conf dir " + confdir + " and " + cls.__name__ + " inconsistent with convention")
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
@@ -644,30 +626,30 @@ distributor-threads={threads}
         if len(params):
             print(params)
 
-        recursorconf = os.path.join(confdir, 'recursor.conf')
+        recursorconf = os.path.join(confdir, "recursor.conf")
 
-        with open(recursorconf, 'w') as conf:
+        with open(recursorconf, "w") as conf:
             conf.write("# Autogenerated by recursortests.py\n")
             conf.write(cls._config_template_default)
             conf.write(cls._config_template % params)
             conf.write("\n")
             conf.write("socket-dir=%s\n" % confdir)
             if cls._lua_config_file or cls._root_DS:
-                luaconfpath = os.path.join(confdir, 'conffile.lua')
-                with open(luaconfpath, 'w') as luaconf:
+                luaconfpath = os.path.join(confdir, "conffile.lua")
+                with open(luaconfpath, "w") as luaconf:
                     if cls._root_DS:
                         luaconf.write("addTA('.', '%s')\n" % cls._root_DS)
                     if cls._lua_config_file:
                         luaconf.write(cls._lua_config_file)
                 conf.write("lua-config-file=%s\n" % luaconfpath)
             if cls._lua_dns_script_file:
-                luascriptpath = os.path.join(confdir, 'dnsscript.lua')
-                with open(luascriptpath, 'w') as luascript:
+                luascriptpath = os.path.join(confdir, "dnsscript.lua")
+                with open(luascriptpath, "w") as luascript:
                     luascript.write(cls._lua_dns_script_file)
                 conf.write("lua-dns-script=%s\n" % luascriptpath)
             if cls._roothints:
-                roothintspath = os.path.join(confdir, 'root.hints')
-                with open(roothintspath, 'w') as roothints:
+                roothintspath = os.path.join(confdir, "root.hints")
+                with open(roothintspath, "w") as roothints:
                     roothints.write(cls._roothints)
                 conf.write("hint-file=%s\n" % roothintspath)
 
@@ -678,35 +660,35 @@ distributor-threads={threads}
         if len(params):
             print(params)
 
-        recursorconf = os.path.join(confdir, 'recursor.yml')
+        recursorconf = os.path.join(confdir, "recursor.yml")
 
-        with open(recursorconf, 'w') as conf:
+        with open(recursorconf, "w") as conf:
             conf.write("# Autogenerated by recursortests.py\n")
-            conf.write(cls._config_template_yaml_default % os.path.join(confdir, 'include'))
-        recursorconf = os.path.join(confdir, 'include', 'recursor01.yml')
-        with open(recursorconf, 'w') as conf:
+            conf.write(cls._config_template_yaml_default % os.path.join(confdir, "include"))
+        recursorconf = os.path.join(confdir, "include", "recursor01.yml")
+        with open(recursorconf, "w") as conf:
             conf.write(cls._config_template % params)
             conf.write("\n")
-        recursorconf = os.path.join(confdir, 'include', 'recursor02.yml')
-        with open(recursorconf, 'w') as conf:
+        recursorconf = os.path.join(confdir, "include", "recursor02.yml")
+        with open(recursorconf, "w") as conf:
             conf.write("recursor:\n")
             conf.write("  socket_dir: %s\n" % confdir)
             if luaConfig and (cls._lua_config_file or cls._root_DS):
-                luaconfpath = os.path.join(confdir, 'conffile.lua')
-                with open(luaconfpath, 'w') as luaconf:
+                luaconfpath = os.path.join(confdir, "conffile.lua")
+                with open(luaconfpath, "w") as luaconf:
                     if cls._root_DS:
                         luaconf.write("addTA('.', '%s')\n" % cls._root_DS)
                     if cls._lua_config_file:
                         luaconf.write(cls._lua_config_file)
                 conf.write("  lua_config_file: %s\n" % luaconfpath)
             if cls._lua_dns_script_file:
-                luascriptpath = os.path.join(confdir, 'dnsscript.lua')
-                with open(luascriptpath, 'w') as luascript:
+                luascriptpath = os.path.join(confdir, "dnsscript.lua")
+                with open(luascriptpath, "w") as luascript:
                     luascript.write(cls._lua_dns_script_file)
                 conf.write("  lua_dns_script: %s\n" % luascriptpath)
             if cls._roothints:
-                roothintspath = os.path.join(confdir, 'root.hints')
-                with open(roothintspath, 'w') as roothints:
+                roothintspath = os.path.join(confdir, "root.hints")
+                with open(roothintspath, "w") as roothints:
                     roothints.write(cls._roothints)
                 conf.write("  hint_file: %s\n" % roothintspath)
 
@@ -717,59 +699,54 @@ distributor-threads={threads}
     @classmethod
     def startRecursor(cls, confdir, port):
         print("Launching pdns_recursor..")
-        recursorcmd = [os.environ['PDNSRECURSOR'],
-                       '--config-dir=%s' % confdir,
-                       '--local-port=%s' % port,
-                       '--security-poll-suffix=',
-                       '--enable-old-settings']
-        print(' '.join(recursorcmd))
-
-        logFile = os.path.join(confdir, 'recursor.log')
-        with open(logFile, 'w') as fdLog:
-            cls._recursor = subprocess.Popen(recursorcmd, close_fds=True,
-                                             stdout=fdLog, stderr=fdLog)
+        recursorcmd = [
+            os.environ["PDNSRECURSOR"],
+            "--config-dir=%s" % confdir,
+            "--local-port=%s" % port,
+            "--security-poll-suffix=",
+            "--enable-old-settings",
+        ]
+        print(" ".join(recursorcmd))
+
+        logFile = os.path.join(confdir, "recursor.log")
+        with open(logFile, "w") as fdLog:
+            cls._recursor = subprocess.Popen(recursorcmd, close_fds=True, stdout=fdLog, stderr=fdLog)
 
         cls.waitForTCPSocket("127.0.0.1", port)
 
         if cls._recursor.poll() is not None:
             print(f"\n*** startRecursor log for {logFile} ***")
-            with open(logFile, 'r') as fdLog:
+            with open(logFile, "r") as fdLog:
                 print(fdLog.read())
             print(f"*** End startRecursor log for {logFile} ***")
-            raise AssertionError('%s failed (%d)' % (recursorcmd, cls._recursor.returncode))
+            raise AssertionError("%s failed (%d)" % (recursorcmd, cls._recursor.returncode))
 
     @classmethod
-    def wipeRecursorCache(cls, confdir, name='.$'):
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % confdir,
-                          'wipe-cache',
-                          name]
+    def wipeRecursorCache(cls, confdir, name=".$"):
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % confdir, "wipe-cache", name]
         try:
             subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (rec_controlCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (rec_controlCmd, e.returncode, e.output))
 
     @classmethod
     def recControl(cls, confdir, *command):
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % confdir
-                          ] + list(command)
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % confdir] + list(command)
         try:
             return subprocess.check_output(rec_controlCmd, text=True, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (rec_controlCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (rec_controlCmd, e.returncode, e.output))
 
     @classmethod
     def recFeatures(cls):
-        rec_versionCmd = [os.environ['PDNSRECURSOR'],
-                          '--version']
+        rec_versionCmd = [os.environ["PDNSRECURSOR"], "--version"]
         try:
             full = subprocess.check_output(rec_versionCmd, text=True, stderr=subprocess.STDOUT)
             for line in full.splitlines():
                 if line.startswith("Features: "):
                     return line
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (rec_versionCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (rec_versionCmd, e.returncode, e.output))
 
     @classmethod
     def setUpSockets(cls):
@@ -784,17 +761,17 @@ distributor-threads={threads}
 
         cls.startResponders()
 
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         cls.createConfigDir(confdir)
 
         cls.generateRecursorConfig(confdir)
         cls.startRecursor(confdir, cls._recursorPort)
 
-#        for auth_suffix, _ in RecursorTest._auth_zones.items():
-#            ip = RecursorTest._PREFIX + '.' + auth_suffix
-#            auth = RecursorTest._auths[ip]
-#            logFile = os.path.join(confdir, 'auth-'+ auth_suffix, 'pdns.log')
-#            RecursorTest.checkAuth(auth, 'auth-' + ip, logFile)
+        #        for auth_suffix, _ in RecursorTest._auth_zones.items():
+        #            ip = RecursorTest._PREFIX + '.' + auth_suffix
+        #            auth = RecursorTest._auths[ip]
+        #            logFile = os.path.join(confdir, 'auth-'+ auth_suffix, 'pdns.log')
+        #            RecursorTest.checkAuth(auth, 'auth-' + ip, logFile)
 
         print("Launching tests..")
 
@@ -834,7 +811,7 @@ distributor-threads={threads}
             return
         try:
             p.terminate()
-            for count in range(1000): # tsan can be slow
+            for count in range(1000):  # tsan can be slow
                 x = p.poll()
                 if x is not None:
                     break
@@ -861,27 +838,24 @@ distributor-threads={threads}
     def tearDownRecursor(cls, subdir=None):
         # We now kill the recursor in a friendly way, as systemd is doing the same.
         if subdir is None:
-            confdir = os.path.join('configs', cls._confdir)
+            confdir = os.path.join("configs", cls._confdir)
         else:
-            confdir = os.path.join('configs', cls._confdir, subdir)
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % confdir,
-                          '--timeout=20',
-                          'quit-nicely']
+            confdir = os.path.join("configs", cls._confdir, subdir)
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % confdir, "--timeout=20", "quit-nicely"]
         try:
             subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (rec_controlCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (rec_controlCmd, e.returncode, e.output))
         # Wait for it, as the process really should have exited
         p = cls._recursor
-        for count in range(1000): # tsan can be slow
+        for count in range(1000):  # tsan can be slow
             if p.poll() is not None:
                 break
             time.sleep(0.01)
         if p.poll() is None:
-            raise AssertionError('Process did not exit on request within 10s')
+            raise AssertionError("Process did not exit on request within 10s")
         if p.returncode not in (0, -15):
-            raise AssertionError('Process exited with return code %d' % (p.returncode))
+            raise AssertionError("Process exited with return code %d" % (p.returncode))
 
     @classmethod
     def sendUDPQuery(cls, query, timeout=2.0, decode=True, fwparams=dict()):
@@ -1004,10 +978,10 @@ distributor-threads={threads}
         missingEdnsFlags = [ednsflag for ednsflag in ednsflags if ednsflag not in msgEdnsFlags]
 
         if len(missingFlags) or len(missingEdnsFlags) or len(msgFlags) > len(flags):
-            raise AssertionError("Expected flags '%s' (EDNS: '%s'), found '%s' (EDNS: '%s') in query %s" %
-                                 (' '.join(flags), ' '.join(ednsflags),
-                                  ' '.join(msgFlags), ' '.join(msgEdnsFlags),
-                                  msg.question[0]))
+            raise AssertionError(
+                "Expected flags '%s' (EDNS: '%s'), found '%s' (EDNS: '%s') in query %s"
+                % (" ".join(flags), " ".join(ednsflags), " ".join(msgFlags), " ".join(msgEdnsFlags), msg.question[0])
+            )
 
     def assertMessageIsAuthenticated(self, msg):
         """Asserts that the message has the AD bit set
@@ -1018,7 +992,7 @@ distributor-threads={threads}
             raise TypeError("msg is not a dns.message.Message")
 
         msgFlags = dns.flags.to_text(msg.flags)
-        self.assertIn('AD', msgFlags, "No AD flag found in the message for %s" % msg.question[0].name)
+        self.assertIn("AD", msgFlags, "No AD flag found in the message for %s" % msg.question[0].name)
 
     def assertRRsetInAnswer(self, msg, rrset):
         """Asserts the rrset (without comparing TTL) exists in the
@@ -1027,7 +1001,7 @@ distributor-threads={threads}
         @param msg: the dns.message.Message to check
         @param rrset: a dns.rrset.RRset object"""
 
-        ret = ''
+        ret = ""
         if not isinstance(msg, dns.message.Message):
             raise TypeError("msg is not a dns.message.Message")
 
@@ -1051,7 +1025,7 @@ distributor-threads={threads}
         @param msg: the dns.message.Message to check
         @param rrset: a dns.rrset.RRset object"""
 
-        ret = ''
+        ret = ""
         if not isinstance(msg, dns.message.Message):
             raise TypeError("msg is not a dns.message.Message")
 
@@ -1086,7 +1060,7 @@ distributor-threads={threads}
         msgRRsigRRSet = None
         msgRRSet = None
 
-        ret = ''
+        ret = ""
         for ans in msg.answer:
             ret += ans.to_text() + "\n"
 
@@ -1101,7 +1075,9 @@ distributor-threads={threads}
             raise AssertionError("RRset for '%s' not found in answer" % msg.question[0].to_text())
 
         if not msgRRsigRRSet:
-            raise AssertionError("No RRSIGs found in answer for %s:\nFull answer:\n%s" % (msg.question[0].to_text(), ret))
+            raise AssertionError(
+                "No RRSIGs found in answer for %s:\nFull answer:\n%s" % (msg.question[0].to_text(), ret)
+            )
 
         if keys:
             try:
@@ -1127,7 +1103,7 @@ distributor-threads={threads}
         msgRRsigRRSet = None
         msgRRSet = None
 
-        ret = ''
+        ret = ""
         for ans in msg.additional:
             ret += ans.to_text() + "\n"
 
@@ -1142,7 +1118,9 @@ distributor-threads={threads}
             raise AssertionError("RRset for '%s' not found in additional" % msg.question[0].to_text())
 
         if not msgRRsigRRSet:
-            raise AssertionError("No RRSIGs found in additional for %s:\nFull answer:\n%s" % (msg.question[0].to_text(), ret))
+            raise AssertionError(
+                "No RRSIGs found in additional for %s:\nFull answer:\n%s" % (msg.question[0].to_text(), ret)
+            )
 
         if keys:
             try:
@@ -1165,10 +1143,20 @@ distributor-threads={threads}
             raise AssertionError("RRSIG found in answers for:\n%s" % ret)
 
     def assertAnswerEmpty(self, msg):
-        self.assertEqual(len(msg.answer), 0, "Data found in the answer section for %s:\n%s" % (msg.question[0].to_text(), '\n'.join([i.to_text() for i in msg.answer])))
+        self.assertEqual(
+            len(msg.answer),
+            0,
+            "Data found in the answer section for %s:\n%s"
+            % (msg.question[0].to_text(), "\n".join([i.to_text() for i in msg.answer])),
+        )
 
     def assertAdditionalEmpty(self, msg):
-        self.assertEqual(len(msg.additional), 0, "Data found in the additional section for %s:\n%s" % (msg.question[0].to_text(), '\n'.join([i.to_text() for i in msg.additional])))
+        self.assertEqual(
+            len(msg.additional),
+            0,
+            "Data found in the additional section for %s:\n%s"
+            % (msg.question[0].to_text(), "\n".join([i.to_text() for i in msg.additional])),
+        )
 
     def assertRcodeEqual(self, msg, rcode):
         if not isinstance(msg, dns.message.Message):
@@ -1184,7 +1172,9 @@ distributor-threads={threads}
             msgRcode = dns.rcode.to_text(msg.rcode())
             wantedRcode = dns.rcode.to_text(rcode)
 
-            raise AssertionError("Rcode for %s is %s, expected %s." % (msg.question[0].to_text(), msgRcode, wantedRcode))
+            raise AssertionError(
+                "Rcode for %s is %s, expected %s." % (msg.question[0].to_text(), msgRcode, wantedRcode)
+            )
 
     def assertAuthorityHasSOA(self, msg):
         if not isinstance(msg, dns.message.Message):
@@ -1227,12 +1217,14 @@ distributor-threads={threads}
         The flags need to be strings (no checking is performed atm)"""
         msg = dns.message.make_query(name, rdtype)
         msg.flags = dns.flags.from_text(flags)
-        msg.flags += dns.flags.from_text('RD')
+        msg.flags += dns.flags.from_text("RD")
         msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text(ednsflags))
         return msg
 
     @classmethod
-    def sendUDPQueryWithProxyProtocol(cls, query, v6, source, destination, sourcePort, destinationPort, values=[], timeout=2.0):
+    def sendUDPQueryWithProxyProtocol(
+        cls, query, v6, source, destination, sourcePort, destinationPort, values=[], timeout=2.0
+    ):
         queryPayload = query.to_wire()
         ppPayload = ProxyProtocol.getPayload(False, False, v6, source, destination, sourcePort, destinationPort, values)
         payload = ppPayload + queryPayload
@@ -1255,7 +1247,9 @@ distributor-threads={threads}
         return message
 
     @classmethod
-    def sendTCPQueryWithProxyProtocol(cls, query, v6, source, destination, sourcePort, destinationPort, values=[], timeout=2.0):
+    def sendTCPQueryWithProxyProtocol(
+        cls, query, v6, source, destination, sourcePort, destinationPort, values=[], timeout=2.0
+    ):
         queryPayload = query.to_wire()
         ppPayload = ProxyProtocol.getPayload(False, False, v6, source, destination, sourcePort, destinationPort, values)
 
@@ -1289,8 +1283,8 @@ distributor-threads={threads}
 
     def checkMetrics(self, map):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/statistics"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
@@ -1298,8 +1292,8 @@ distributor-threads={threads}
         count = 0
         for entry in content:
             for key, expected in map.items():
-                if entry['name'] == key:
-                    value = int(entry['value'])
+                if entry["name"] == key:
+                    value = int(entry["value"])
                     if callable(expected):
                         self.assertTrue(expected(value), key + ": value " + str(value) + " is not expected")
                     else:
@@ -1310,11 +1304,10 @@ distributor-threads={threads}
     @classmethod
     def startReactor(cls):
         if not reactor.running:
-            cls.Responder = threading.Thread(name='Responder', target=reactor.run, args=(False,))
+            cls.Responder = threading.Thread(name="Responder", target=reactor.run, args=(False,))
             cls.Responder.daemon = True
             cls.Responder.start()
 
-
     @classmethod
     def _ResponderIncrementCounter(cls):
         if threading.current_thread().name in cls._responsesCounter:
@@ -1337,8 +1330,8 @@ distributor-threads={threads}
                 response.id = request.id
 
         if synthesize is not None:
-          response = dns.message.make_response(request)
-          response.set_rcode(synthesize)
+            response = dns.message.make_response(request)
+            response.set_rcode(synthesize)
 
         if not response:
             if cls._answerUnexpected:
@@ -1348,87 +1341,110 @@ distributor-threads={threads}
         return response
 
     @classmethod
-    def handleTCPConnection(cls, conn, fromQueue, toQueue, trailingDataResponse=False, multipleResponses=False, callback=None, partialWrite=False,clientCert=False):
-      ignoreTrailing = trailingDataResponse is True
-      try:
-        data = conn.recv(2)
-      except Exception as err:
-        data = None
-        print(f'Error while reading query size in TCP responder thread {err=}, {type(err)=}')
-      if not data:
-        conn.close()
-        return
-
-      if clientCert:
-          print("Checking client cert")
-          cert = conn.getpeercert()
-          if cert is None:
-              raise AssertionError("Client certificate expected, got none")
-          if cert['subject'][0][0][1] != 'client.tests.powerdns.com':
-              print(cert)
-              raise AssertionError('Unexpected subject in cert')
-
-      (datalen,) = struct.unpack("!H", data)
-      data = conn.recv(datalen)
-      forceRcode = None
-      try:
-        request = dns.message.from_wire(data, ignore_trailing=ignoreTrailing)
-      except dns.message.TrailingJunk as e:
-        if trailingDataResponse is False or forceRcode is True:
-          raise
-        print("TCP query with trailing data, synthesizing response")
-        request = dns.message.from_wire(data, ignore_trailing=True)
-        forceRcode = trailingDataResponse
-
-      if callback:
-        wire = callback(request)
-      else:
-        if request.edns > 1:
-          forceRcode = dns.rcode.BADVERS
-        response = cls._getResponse(request, fromQueue, toQueue, synthesize=forceRcode)
-        if response:
-          wire = response.to_wire(max_size=65535)
-
-      if not wire:
-        conn.close()
-        return
-      elif isinstance(wire, ResponderDropAction):
-        return
-
-      wireLen = struct.pack("!H", len(wire))
-      if partialWrite:
-        for b in wireLen:
-          conn.send(bytes([b]))
-          time.sleep(0.5)
-      else:
-        conn.send(wireLen)
-      conn.send(wire)
-
-      while multipleResponses:
-        # do not block, and stop as soon as the queue is empty, either the next response is already here or we are done
-        # otherwise we might read responses intended for the next connection
-        if fromQueue.empty():
-          break
-
-        response = fromQueue.get(False)
-        if not response:
-          break
+    def handleTCPConnection(
+        cls,
+        conn,
+        fromQueue,
+        toQueue,
+        trailingDataResponse=False,
+        multipleResponses=False,
+        callback=None,
+        partialWrite=False,
+        clientCert=False,
+    ):
+        ignoreTrailing = trailingDataResponse is True
+        try:
+            data = conn.recv(2)
+        except Exception as err:
+            data = None
+            print(f"Error while reading query size in TCP responder thread {err=}, {type(err)=}")
+        if not data:
+            conn.close()
+            return
 
-        response = copy.copy(response)
-        response.id = request.id
-        wire = response.to_wire(max_size=65535)
+        if clientCert:
+            print("Checking client cert")
+            cert = conn.getpeercert()
+            if cert is None:
+                raise AssertionError("Client certificate expected, got none")
+            if cert["subject"][0][0][1] != "client.tests.powerdns.com":
+                print(cert)
+                raise AssertionError("Unexpected subject in cert")
+
+        (datalen,) = struct.unpack("!H", data)
+        data = conn.recv(datalen)
+        forceRcode = None
         try:
-          conn.send(struct.pack("!H", len(wire)))
-          conn.send(wire)
-        except socket.error as e:
-          # some of the tests are going to close
-          # the connection on us, just deal with it
-          break
+            request = dns.message.from_wire(data, ignore_trailing=ignoreTrailing)
+        except dns.message.TrailingJunk as e:
+            if trailingDataResponse is False or forceRcode is True:
+                raise
+            print("TCP query with trailing data, synthesizing response")
+            request = dns.message.from_wire(data, ignore_trailing=True)
+            forceRcode = trailingDataResponse
 
-      conn.close()
+        if callback:
+            wire = callback(request)
+        else:
+            if request.edns > 1:
+                forceRcode = dns.rcode.BADVERS
+            response = cls._getResponse(request, fromQueue, toQueue, synthesize=forceRcode)
+            if response:
+                wire = response.to_wire(max_size=65535)
+
+        if not wire:
+            conn.close()
+            return
+        elif isinstance(wire, ResponderDropAction):
+            return
+
+        wireLen = struct.pack("!H", len(wire))
+        if partialWrite:
+            for b in wireLen:
+                conn.send(bytes([b]))
+                time.sleep(0.5)
+        else:
+            conn.send(wireLen)
+        conn.send(wire)
+
+        while multipleResponses:
+            # do not block, and stop as soon as the queue is empty, either the next response is already here or we are done
+            # otherwise we might read responses intended for the next connection
+            if fromQueue.empty():
+                break
+
+            response = fromQueue.get(False)
+            if not response:
+                break
+
+            response = copy.copy(response)
+            response.id = request.id
+            wire = response.to_wire(max_size=65535)
+            try:
+                conn.send(struct.pack("!H", len(wire)))
+                conn.send(wire)
+            except socket.error as e:
+                # some of the tests are going to close
+                # the connection on us, just deal with it
+                break
+
+        conn.close()
 
     @classmethod
-    def TCPResponder(cls, port, fromQueue, toQueue, trailingDataResponse=False, multipleResponses=False, callback=None, tlsContext=None, multipleConnections=False, listeningAddr='127.0.0.1', partialWrite=False, clientCert=False):
+    def TCPResponder(
+        cls,
+        port,
+        fromQueue,
+        toQueue,
+        trailingDataResponse=False,
+        multipleResponses=False,
+        callback=None,
+        tlsContext=None,
+        multipleConnections=False,
+        listeningAddr="127.0.0.1",
+        partialWrite=False,
+        clientCert=False,
+    ):
         cls._backgroundThreads[threading.get_native_id()] = True
         # trailingDataResponse=True means "ignore trailing data".
         # Other values are either False (meaning "raise an exception")
@@ -1448,38 +1464,58 @@ distributor-threads={threads}
         sock.listen(100)
         sock.settimeout(0.5)
         if tlsContext:
-          sock = tlsContext.wrap_socket(sock, server_side=True)
+            sock = tlsContext.wrap_socket(sock, server_side=True)
 
         while True:
             try:
-              (conn, _) = sock.accept()
+                (conn, _) = sock.accept()
             except ssl.SSLError:
-              continue
+                continue
             except ConnectionResetError:
-              continue
-            except socket.timeout:
-              if cls._backgroundThreads.get(threading.get_native_id(), False) == False:
-                 del cls._backgroundThreads[threading.get_native_id()]
-                 break
-              else:
                 continue
+            except socket.timeout:
+                if cls._backgroundThreads.get(threading.get_native_id(), False) == False:
+                    del cls._backgroundThreads[threading.get_native_id()]
+                    break
+                else:
+                    continue
 
             conn.settimeout(5.0)
             if multipleConnections:
-              thread = threading.Thread(name='TCP Connection Handler',
-                                        target=cls.handleTCPConnection,
-                                        args=[conn, fromQueue, toQueue, trailingDataResponse, multipleResponses, callback, partialWrite, clientCert])
-              thread.daemon = True
-              thread.start()
+                thread = threading.Thread(
+                    name="TCP Connection Handler",
+                    target=cls.handleTCPConnection,
+                    args=[
+                        conn,
+                        fromQueue,
+                        toQueue,
+                        trailingDataResponse,
+                        multipleResponses,
+                        callback,
+                        partialWrite,
+                        clientCert,
+                    ],
+                )
+                thread.daemon = True
+                thread.start()
             else:
-              cls.handleTCPConnection(conn, fromQueue, toQueue, trailingDataResponse, multipleResponses, callback, partialWrite, clientCert)
+                cls.handleTCPConnection(
+                    conn,
+                    fromQueue,
+                    toQueue,
+                    trailingDataResponse,
+                    multipleResponses,
+                    callback,
+                    partialWrite,
+                    clientCert,
+                )
 
         sock.close()
 
+
 class ResponderDropAction(object):
     """
     An object to indicate a drop action shall be taken
     """
-    pass
-
 
+    pass
index d2016209540642c468203133e6cf21f0adbc1632..441111c73c486c51fb3aa5c59168ac94f358d7cc 100644 (file)
@@ -2,12 +2,13 @@ import requests
 
 from recursortests import RecursorTest
 
+
 class APIAllowedRecursorTest(RecursorTest):
-    _confdir = 'APIAllowedRecursor'
+    _confdir = "APIAllowedRecursor"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
 
     _config_template = """
 webserver=yes
@@ -20,19 +21,20 @@ api-key=%s
 
     def testAPI(self):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/statistics"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
 
+
 class APIDeniedRecursorTest(RecursorTest):
-    _confdir = 'APIDeniedRecursor'
+    _confdir = "APIDeniedRecursor"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
 
     _config_template = """
 webserver=yes
@@ -45,8 +47,8 @@ api-key=%s
 
     def testAPI(self):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/statistics"
         try:
             requests.get(url, headers=headers, timeout=self._wsTimeout)
             self.fail()
index 584a1d6947dbe880d1729ac7290a67d63b68f88f..3c22c14135029a9bc6750a4d1c774e3c7e30964a 100644 (file)
@@ -1,8 +1,9 @@
 import dns
 from recursortests import RecursorTest
 
+
 class AdditionalsDefaultTest(RecursorTest):
-    _confdir = 'AdditionalsDefault'
+    _confdir = "AdditionalsDefault"
     _auth_zones = RecursorTest._default_auth_zones
     _config_template = """
     dnssec=validate
@@ -13,14 +14,16 @@ class AdditionalsDefaultTest(RecursorTest):
     """
 
     def testMX(self):
-        expected = dns.rrset.from_text('secure.example.', 0, dns.rdataclass.IN, 'MX', '10 mx1.secure.example.', '20 mx2.secure.example.')
-        adds1 = dns.rrset.from_text('mx1.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.18')
-        adds2 = dns.rrset.from_text('mx2.secure.example.', 0, dns.rdataclass.IN, 'AAAA', '1::2')
-        query1 = dns.message.make_query('secure.example', 'MX', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "secure.example.", 0, dns.rdataclass.IN, "MX", "10 mx1.secure.example.", "20 mx2.secure.example."
+        )
+        adds1 = dns.rrset.from_text("mx1.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.18")
+        adds2 = dns.rrset.from_text("mx2.secure.example.", 0, dns.rdataclass.IN, "AAAA", "1::2")
+        query1 = dns.message.make_query("secure.example", "MX", want_dnssec=True)
         query1.flags |= dns.flags.AD
-        query2 = dns.message.make_query('mx1.secure.example', 'A', want_dnssec=True)
+        query2 = dns.message.make_query("mx1.secure.example", "A", want_dnssec=True)
         query2.flags |= dns.flags.AD
-        query3 = dns.message.make_query('mx2.secure.example', 'AAAA', want_dnssec=True)
+        query3 = dns.message.make_query("mx2.secure.example", "AAAA", want_dnssec=True)
         query3.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query1)
@@ -39,8 +42,9 @@ class AdditionalsDefaultTest(RecursorTest):
         self.assertRRsetInAdditional(res, adds1)
         self.assertRRsetInAdditional(res, adds2)
 
+
 class AdditionalsResolveImmediatelyTest(RecursorTest):
-    _confdir = 'AdditionalsResolveImmediately'
+    _confdir = "AdditionalsResolveImmediately"
     _auth_zones = RecursorTest._default_auth_zones
     _config_template = """
     dnssec=validate
@@ -53,10 +57,12 @@ class AdditionalsResolveImmediatelyTest(RecursorTest):
     """
 
     def testMX(self):
-        expected = dns.rrset.from_text('secure.example.', 0, dns.rdataclass.IN, 'MX', '10 mx1.secure.example.', '20 mx2.secure.example.')
-        adds1 = dns.rrset.from_text('mx1.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.18')
-        adds2 = dns.rrset.from_text('mx2.secure.example.', 0, dns.rdataclass.IN, 'AAAA', '1::2')
-        query1 = dns.message.make_query('secure.example', 'MX', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "secure.example.", 0, dns.rdataclass.IN, "MX", "10 mx1.secure.example.", "20 mx2.secure.example."
+        )
+        adds1 = dns.rrset.from_text("mx1.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.18")
+        adds2 = dns.rrset.from_text("mx2.secure.example.", 0, dns.rdataclass.IN, "AAAA", "1::2")
+        query1 = dns.message.make_query("secure.example", "MX", want_dnssec=True)
         query1.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query1)
@@ -69,19 +75,28 @@ class AdditionalsResolveImmediatelyTest(RecursorTest):
         self.assertMatchingRRSIGInAdditional(res, adds2)
 
     def testNAPTR(self):
-        exp = dns.rrset.from_text('naptr.secure.example.', 0, dns.rdataclass.IN, 'NAPTR',
-                                   '10 10 "s" "Z" "C" service2.secure.example.',
-                                   '10 10 "s" "Y" "B" service1.secure.example.',
-                                   '10 10 "a" "X" "A" s1.secure.example.');
-        adds1 = dns.rrset.from_text('s1.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.19')
-        adds2 = dns.rrset.from_text('service1.secure.example.', 0, dns.rdataclass.IN, 'SRV', '20 100 8080 a.secure.example.')
-        adds3 = dns.rrset.from_text('service2.secure.example.', 0, dns.rdataclass.IN, 'SRV', '20 100 8080 b.secure.example.')
-        adds4 = dns.rrset.from_text('a.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.20', '192.0.2.22')
-        adds5 = dns.rrset.from_text('b.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.21')
-        adds6 = dns.rrset.from_text('b.secure.example.', 0, dns.rdataclass.IN, 'AAAA', '1::3')
-        adds7 = dns.rrset.from_text('s1.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.19')
+        exp = dns.rrset.from_text(
+            "naptr.secure.example.",
+            0,
+            dns.rdataclass.IN,
+            "NAPTR",
+            '10 10 "s" "Z" "C" service2.secure.example.',
+            '10 10 "s" "Y" "B" service1.secure.example.',
+            '10 10 "a" "X" "A" s1.secure.example.',
+        )
+        adds1 = dns.rrset.from_text("s1.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.19")
+        adds2 = dns.rrset.from_text(
+            "service1.secure.example.", 0, dns.rdataclass.IN, "SRV", "20 100 8080 a.secure.example."
+        )
+        adds3 = dns.rrset.from_text(
+            "service2.secure.example.", 0, dns.rdataclass.IN, "SRV", "20 100 8080 b.secure.example."
+        )
+        adds4 = dns.rrset.from_text("a.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.20", "192.0.2.22")
+        adds5 = dns.rrset.from_text("b.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.21")
+        adds6 = dns.rrset.from_text("b.secure.example.", 0, dns.rdataclass.IN, "AAAA", "1::3")
+        adds7 = dns.rrset.from_text("s1.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.19")
 
-        query1 = dns.message.make_query('naptr.secure.example', 'NAPTR', want_dnssec=True)
+        query1 = dns.message.make_query("naptr.secure.example", "NAPTR", want_dnssec=True)
         query1.flags |= dns.flags.AD
         res = self.sendUDPQuery(query1)
         self.assertMessageIsAuthenticated(res)
@@ -102,8 +117,9 @@ class AdditionalsResolveImmediatelyTest(RecursorTest):
         self.assertRRsetInAdditional(res, adds7)
         self.assertMatchingRRSIGInAdditional(res, adds7)
 
+
 class AdditionalsResolveCacheOnlyTest(RecursorTest):
-    _confdir = 'AdditionalsResolveCacheOnly'
+    _confdir = "AdditionalsResolveCacheOnly"
     _auth_zones = RecursorTest._default_auth_zones
     _config_template = """
     dnssec=validate
@@ -114,10 +130,12 @@ class AdditionalsResolveCacheOnlyTest(RecursorTest):
     """
 
     def testMX(self):
-        expected = dns.rrset.from_text('secure.example.', 0, dns.rdataclass.IN, 'MX', '10 mx1.secure.example.', '20 mx2.secure.example.')
-        adds1 = dns.rrset.from_text('mx1.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.18')
-        adds2 = dns.rrset.from_text('mx2.secure.example.', 0, dns.rdataclass.IN, 'AAAA', '1::2')
-        query1 = dns.message.make_query('secure.example', 'MX', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "secure.example.", 0, dns.rdataclass.IN, "MX", "10 mx1.secure.example.", "20 mx2.secure.example."
+        )
+        adds1 = dns.rrset.from_text("mx1.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.18")
+        adds2 = dns.rrset.from_text("mx2.secure.example.", 0, dns.rdataclass.IN, "AAAA", "1::2")
+        query1 = dns.message.make_query("secure.example", "MX", want_dnssec=True)
         query1.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query1)
@@ -128,4 +146,3 @@ class AdditionalsResolveCacheOnlyTest(RecursorTest):
         self.assertRRsetInAdditional(res, adds2)
         self.assertMatchingRRSIGInAdditional(res, adds1)
         self.assertMatchingRRSIGInAdditional(res, adds2)
-
index 03aa04eea519ab6d13664cc05085e4879fc2d596..76f9d9d6a5b0667bba2d6e570b8239dca6fbb076 100644 (file)
@@ -7,12 +7,13 @@ import extendederrors
 import pytest
 import shutil
 
+
 class AggressiveNSECCacheBase(RecursorTest):
     __test__ = False
     _wsPort = 8042
     _wsTimeout = 10
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _auth_zones = RecursorTest._default_auth_zones
     _config_template = """
     dnssec=validate
@@ -30,13 +31,13 @@ class AggressiveNSECCacheBase(RecursorTest):
 
     @classmethod
     def wipe(cls):
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         # Only wipe examples, as wiping the root triggers root NS refreshes
         cls.wipeRecursorCache(confdir, "example$")
 
     def getMetric(self, name):
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/statistics"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -44,8 +45,8 @@ class AggressiveNSECCacheBase(RecursorTest):
         content = r.json()
 
         for entry in content:
-            if entry['name'] == name:
-                return int(entry['value'])
+            if entry["name"] == name:
+                return int(entry["value"])
 
         self.fail()
         return -1
@@ -57,7 +58,7 @@ class AggressiveNSECCacheBase(RecursorTest):
         # https://github.com/PowerDNS/pdns/pull/12694
         self.wipe()
 
-        res = self.sendQuery('host1.sub.secure.example.', 'TXT')
+        res = self.sendQuery("host1.sub.secure.example.", "TXT")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
@@ -65,7 +66,7 @@ class AggressiveNSECCacheBase(RecursorTest):
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 0)
 
-        res = self.sendQuery('host1.sub.secure.example.', 'A')
+        res = self.sendQuery("host1.sub.secure.example.", "A")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMessageIsAuthenticated(res)
         self.assertEqual(res.edns, 0)
@@ -75,32 +76,36 @@ class AggressiveNSECCacheBase(RecursorTest):
         self.wipe()
 
         # first we query a nonexistent type, to get the NSEC in our cache
-        entries = self.getMetric('aggressive-nsec-cache-entries')
-        res = self.sendQuery('host1.secure.example.', 'TXT')
+        entries = self.getMetric("aggressive-nsec-cache-entries")
+        res = self.sendQuery("host1.secure.example.", "TXT")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
-        self.assertGreater(self.getMetric('aggressive-nsec-cache-entries'), entries)
+        self.assertGreater(self.getMetric("aggressive-nsec-cache-entries"), entries)
 
         # now we ask for a different type, we should generate the answer from the NSEC,
         # and no outgoing query should be made
-        nbQueries = self.getMetric('all-outqueries')
-        entries = self.getMetric('aggressive-nsec-cache-entries')
-        res = self.sendQuery('host1.secure.example.', 'AAAA')
+        nbQueries = self.getMetric("all-outqueries")
+        entries = self.getMetric("aggressive-nsec-cache-entries")
+        res = self.sendQuery("host1.secure.example.", "AAAA")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
-        self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
-        self.assertEqual(self.getMetric('aggressive-nsec-cache-entries'), entries)
+        self.assertEqual(nbQueries, self.getMetric("all-outqueries"))
+        self.assertEqual(self.getMetric("aggressive-nsec-cache-entries"), entries)
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
+        self.assertEqual(
+            res.options[0],
+            extendederrors.ExtendedErrorOption(29, b"Result synthesized from aggressive NSEC cache (RFC8198)"),
+        )
+
 
 class AggressiveNSECCacheNSECTest(AggressiveNSECCacheBase):
-    _confdir = 'AggressiveNSECCacheNSEC'
+    _confdir = "AggressiveNSECCacheNSEC"
     __test__ = True
 
     # we can't use the same tests for NSEC and NSEC3 because the hashed NSEC3s
@@ -109,108 +114,124 @@ class AggressiveNSECCacheNSECTest(AggressiveNSECCacheBase):
         self.wipe()
 
         # first we query a nonexistent name, to get the needed NSECs (name + widcard) in our cache
-        entries = self.getMetric('aggressive-nsec-cache-entries')
-        hits = self.getMetric('aggressive-nsec-cache-nsec-hits')
-        res = self.sendQuery('host2.secure.example.', 'TXT')
+        entries = self.getMetric("aggressive-nsec-cache-entries")
+        hits = self.getMetric("aggressive-nsec-cache-nsec-hits")
+        res = self.sendQuery("host2.secure.example.", "TXT")
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
-        self.assertGreater(self.getMetric('aggressive-nsec-cache-entries'), entries)
-        self.assertEqual(self.getMetric('aggressive-nsec-cache-nsec-hits'), hits)
+        self.assertGreater(self.getMetric("aggressive-nsec-cache-entries"), entries)
+        self.assertEqual(self.getMetric("aggressive-nsec-cache-nsec-hits"), hits)
 
         # now we ask for a different name that is covered by the NSEC,
         # we should generate the answer from the NSEC and no outgoing query should be made
-        nbQueries = self.getMetric('all-outqueries')
-        entries = self.getMetric('aggressive-nsec-cache-entries')
-        hits = self.getMetric('aggressive-nsec-cache-nsec-hits')
-        res = self.sendQuery('host3.secure.example.', 'AAAA')
+        nbQueries = self.getMetric("all-outqueries")
+        entries = self.getMetric("aggressive-nsec-cache-entries")
+        hits = self.getMetric("aggressive-nsec-cache-nsec-hits")
+        res = self.sendQuery("host3.secure.example.", "AAAA")
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
-        self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
-        self.assertEqual(self.getMetric('aggressive-nsec-cache-entries'), entries)
-        self.assertGreater(self.getMetric('aggressive-nsec-cache-nsec-hits'), hits)
+        self.assertEqual(nbQueries, self.getMetric("all-outqueries"))
+        self.assertEqual(self.getMetric("aggressive-nsec-cache-entries"), entries)
+        self.assertGreater(self.getMetric("aggressive-nsec-cache-nsec-hits"), hits)
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
+        self.assertEqual(
+            res.options[0],
+            extendederrors.ExtendedErrorOption(29, b"Result synthesized from aggressive NSEC cache (RFC8198)"),
+        )
 
     def testWildcard(self):
         self.wipe()
 
         # first we query a nonexistent name, but for which a wildcard matches,
         # to get the NSEC in our cache
-        res = self.sendQuery('test1.wildcard.secure.example.', 'A')
-        expected = dns.rrset.from_text('test1.wildcard.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
+        res = self.sendQuery("test1.wildcard.secure.example.", "A")
+        expected = dns.rrset.from_text(
+            "test1.wildcard.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expected)
         self.assertMessageIsAuthenticated(res)
 
         # now we ask for a different name, we should generate the answer from the NSEC and the wildcard,
         # and no outgoing query should be made
-        hits = self.getMetric('aggressive-nsec-cache-nsec-wc-hits')
-        nbQueries = self.getMetric('all-outqueries')
-        res = self.sendQuery('test2.wildcard.secure.example.', 'A')
-        expected = dns.rrset.from_text('test2.wildcard.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
+        hits = self.getMetric("aggressive-nsec-cache-nsec-wc-hits")
+        nbQueries = self.getMetric("all-outqueries")
+        res = self.sendQuery("test2.wildcard.secure.example.", "A")
+        expected = dns.rrset.from_text(
+            "test2.wildcard.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expected)
         self.assertMessageIsAuthenticated(res)
-        self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
-        self.assertGreater(self.getMetric('aggressive-nsec-cache-nsec-wc-hits'), hits)
+        self.assertEqual(nbQueries, self.getMetric("all-outqueries"))
+        self.assertGreater(self.getMetric("aggressive-nsec-cache-nsec-wc-hits"), hits)
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
+        self.assertEqual(
+            res.options[0],
+            extendederrors.ExtendedErrorOption(29, b"Result synthesized from aggressive NSEC cache (RFC8198)"),
+        )
 
         # now we ask for a type that does not exist at the wildcard
-        hits = self.getMetric('aggressive-nsec-cache-nsec-hits')
-        nbQueries = self.getMetric('all-outqueries')
-        res = self.sendQuery('test1.wildcard.secure.example.', 'AAAA')
+        hits = self.getMetric("aggressive-nsec-cache-nsec-hits")
+        nbQueries = self.getMetric("all-outqueries")
+        res = self.sendQuery("test1.wildcard.secure.example.", "AAAA")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
-        self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
-        self.assertGreater(self.getMetric('aggressive-nsec-cache-nsec-hits'), hits)
+        self.assertEqual(nbQueries, self.getMetric("all-outqueries"))
+        self.assertGreater(self.getMetric("aggressive-nsec-cache-nsec-hits"), hits)
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
+        self.assertEqual(
+            res.options[0],
+            extendederrors.ExtendedErrorOption(29, b"Result synthesized from aggressive NSEC cache (RFC8198)"),
+        )
 
         # we can also ask a different type, for a different name that is covered
         # by the NSEC and matches the wildcard (but the type does not exist)
-        hits = self.getMetric('aggressive-nsec-cache-nsec-wc-hits')
-        nbQueries = self.getMetric('all-outqueries')
-        res = self.sendQuery('test3.wildcard.secure.example.', 'TXT')
+        hits = self.getMetric("aggressive-nsec-cache-nsec-wc-hits")
+        nbQueries = self.getMetric("all-outqueries")
+        res = self.sendQuery("test3.wildcard.secure.example.", "TXT")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
-        self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
-        self.assertGreater(self.getMetric('aggressive-nsec-cache-nsec-hits'), hits)
+        self.assertEqual(nbQueries, self.getMetric("all-outqueries"))
+        self.assertGreater(self.getMetric("aggressive-nsec-cache-nsec-hits"), hits)
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
+        self.assertEqual(
+            res.options[0],
+            extendederrors.ExtendedErrorOption(29, b"Result synthesized from aggressive NSEC cache (RFC8198)"),
+        )
 
     def test_Bogus(self):
         self.wipe()
 
         # query a name in example to fill the aggressive negcache
-        res = self.sendQuery('example.', 'A')
+        res = self.sendQuery("example.", "A")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnswerEmpty(res)
-        self.assertEqual(1, self.getMetric('aggressive-nsec-cache-entries'))
+        self.assertEqual(1, self.getMetric("aggressive-nsec-cache-entries"))
 
         # query a name in a Bogus zone
-        res = self.sendQuery('ted1.bogus.example.', 'A')
+        res = self.sendQuery("ted1.bogus.example.", "A")
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
 
         # disable validation
-        msg = dns.message.make_query('ted1.bogus.example.', 'A', want_dnssec=True)
+        msg = dns.message.make_query("ted1.bogus.example.", "A", want_dnssec=True)
         msg.flags |= dns.flags.CD
 
         res = self.sendUDPQuery(msg)
@@ -219,26 +240,27 @@ class AggressiveNSECCacheNSECTest(AggressiveNSECCacheBase):
         self.assertAuthorityHasSOA(res)
 
         # check that we _do not_ use the aggressive NSEC cache
-        nbQueries = self.getMetric('all-outqueries')
-        msg = dns.message.make_query('ted2.bogus.example.', 'A', want_dnssec=True)
+        nbQueries = self.getMetric("all-outqueries")
+        msg = dns.message.make_query("ted2.bogus.example.", "A", want_dnssec=True)
         msg.flags |= dns.flags.CD
 
         res = self.sendUDPQuery(msg)
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
-        self.assertGreater(self.getMetric('all-outqueries'), nbQueries)
+        self.assertGreater(self.getMetric("all-outqueries"), nbQueries)
 
         # Check that we still have one aggressive cache entry
-        self.assertEqual(1, self.getMetric('aggressive-nsec-cache-entries'))
+        self.assertEqual(1, self.getMetric("aggressive-nsec-cache-entries"))
         print(res.options)
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(9, b''))
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(9, b""))
+
 
 class AggressiveNSECCacheNSEC3Test(AggressiveNSECCacheBase):
-    _confdir = 'AggressiveNSECCacheNSEC3'
+    _confdir = "AggressiveNSECCacheNSEC3"
     __test__ = True
 
     @classmethod
@@ -248,12 +270,12 @@ class AggressiveNSECCacheNSEC3Test(AggressiveNSECCacheBase):
 
     @classmethod
     def tearDownClass(cls):
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         print("Specialized auth teardown " + confdir)
         # tear down specialized auths, and then start standard ones
         super().tearDownClass(True)
         print("Starting default auths")
-        confdir = 'configs/auths'
+        confdir = "configs/auths"
         shutil.rmtree(confdir, True)
         os.mkdir(confdir)
         # Be careful here, we don't want the overridden secureZone(), so call RecursorTest explicitly
@@ -262,53 +284,48 @@ class AggressiveNSECCacheNSEC3Test(AggressiveNSECCacheBase):
 
     @classmethod
     def secureZone(cls, confdir, zonename, key=None):
-        zone = '.' if zonename == 'ROOT' else zonename
+        zone = "." if zonename == "ROOT" else zonename
         if not key:
-            pdnsutilCmd = [os.environ['PDNSUTIL'],
-                           '--config-dir=%s' % confdir,
-                           'secure-zone',
-                           zone]
+            pdnsutilCmd = [os.environ["PDNSUTIL"], "--config-dir=%s" % confdir, "secure-zone", zone]
         else:
-            keyfile = os.path.join(confdir, 'dnssec.key')
-            with open(keyfile, 'w') as fdKeyfile:
+            keyfile = os.path.join(confdir, "dnssec.key")
+            with open(keyfile, "w") as fdKeyfile:
                 fdKeyfile.write(key)
 
-            pdnsutilCmd = [os.environ['PDNSUTIL'],
-                           '--config-dir=%s' % confdir,
-                           'import-zone-key',
-                           zone,
-                           keyfile,
-                           'active',
-                           'ksk']
-
-        print(' '.join(pdnsutilCmd))
+            pdnsutilCmd = [
+                os.environ["PDNSUTIL"],
+                "--config-dir=%s" % confdir,
+                "import-zone-key",
+                zone,
+                keyfile,
+                "active",
+                "ksk",
+            ]
+
+        print(" ".join(pdnsutilCmd))
         try:
             subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
         params = "1 0 100 AABBCCDDEEFF112233"
 
         if zone == "optout.example":
             params = "1 1 100 AABBCCDDEEFF112233"
 
-        pdnsutilCmd = [os.environ['PDNSUTIL'],
-                       '--config-dir=%s' % confdir,
-                       'set-nsec3',
-                       zone,
-                       params]
+        pdnsutilCmd = [os.environ["PDNSUTIL"], "--config-dir=%s" % confdir, "set-nsec3", zone, params]
 
-        print(' '.join(pdnsutilCmd))
+        print(" ".join(pdnsutilCmd))
         try:
             subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
     def testNXD(self):
         self.wipe()
 
         # first we query a nonexistent name, to get the needed NSEC3s in our cache
-        res = self.sendQuery('host2.secure.example.', 'TXT')
+        res = self.sendQuery("host2.secure.example.", "TXT")
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
@@ -316,24 +333,27 @@ class AggressiveNSECCacheNSEC3Test(AggressiveNSECCacheBase):
 
         # now we ask for a different name that is covered by the NSEC3s,
         # we should generate the answer from the NSEC3s and no outgoing query should be made
-        nbQueries = self.getMetric('all-outqueries')
-        res = self.sendQuery('host6.secure.example.', 'AAAA')
+        nbQueries = self.getMetric("all-outqueries")
+        res = self.sendQuery("host6.secure.example.", "AAAA")
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
-        self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
+        self.assertEqual(nbQueries, self.getMetric("all-outqueries"))
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
+        self.assertEqual(
+            res.options[0],
+            extendederrors.ExtendedErrorOption(29, b"Result synthesized from aggressive NSEC cache (RFC8198)"),
+        )
 
     def testWildcard(self):
         self.wipe()
 
         # first let's get the SOA and wildcard NSEC in our cache by asking a name that matches the wildcard
         # but a type that does not exist
-        res = self.sendQuery('test1.wildcard.secure.example.', 'AAAA')
+        res = self.sendQuery("test1.wildcard.secure.example.", "AAAA")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
@@ -341,68 +361,81 @@ class AggressiveNSECCacheNSEC3Test(AggressiveNSECCacheBase):
 
         # we query a nonexistent name, but for which a wildcard matches,
         # to get the NSEC3 in our cache
-        res = self.sendQuery('test5.wildcard.secure.example.', 'A')
-        expected = dns.rrset.from_text('test5.wildcard.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
+        res = self.sendQuery("test5.wildcard.secure.example.", "A")
+        expected = dns.rrset.from_text(
+            "test5.wildcard.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expected)
         self.assertMessageIsAuthenticated(res)
 
         # now we ask for a different name, we should generate the answer from the NSEC3s and the wildcard,
         # and no outgoing query should be made
-        nbQueries = self.getMetric('all-outqueries')
-        res = self.sendQuery('test6.wildcard.secure.example.', 'A')
-        expected = dns.rrset.from_text('test6.wildcard.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
+        nbQueries = self.getMetric("all-outqueries")
+        res = self.sendQuery("test6.wildcard.secure.example.", "A")
+        expected = dns.rrset.from_text(
+            "test6.wildcard.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertMatchingRRSIGInAnswer(res, expected)
         self.assertMessageIsAuthenticated(res)
-        self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
+        self.assertEqual(nbQueries, self.getMetric("all-outqueries"))
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
+        self.assertEqual(
+            res.options[0],
+            extendederrors.ExtendedErrorOption(29, b"Result synthesized from aggressive NSEC cache (RFC8198)"),
+        )
 
         # now we ask for a type that does not exist at the wildcard
-        nbQueries = self.getMetric('all-outqueries')
-        res = self.sendQuery('test5.wildcard.secure.example.', 'AAAA')
+        nbQueries = self.getMetric("all-outqueries")
+        res = self.sendQuery("test5.wildcard.secure.example.", "AAAA")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
-        self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
+        self.assertEqual(nbQueries, self.getMetric("all-outqueries"))
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
+        self.assertEqual(
+            res.options[0],
+            extendederrors.ExtendedErrorOption(29, b"Result synthesized from aggressive NSEC cache (RFC8198)"),
+        )
 
         # we can also ask a different type, for a different name that is covered
         # by the NSEC3s and matches the wildcard (but the type does not exist)
-        nbQueries = self.getMetric('all-outqueries')
-        res = self.sendQuery('test6.wildcard.secure.example.', 'TXT')
+        nbQueries = self.getMetric("all-outqueries")
+        res = self.sendQuery("test6.wildcard.secure.example.", "TXT")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
-        self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
+        self.assertEqual(nbQueries, self.getMetric("all-outqueries"))
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
+        self.assertEqual(
+            res.options[0],
+            extendederrors.ExtendedErrorOption(29, b"Result synthesized from aggressive NSEC cache (RFC8198)"),
+        )
 
     def test_OptOut(self):
         self.wipe()
 
         # query a name in an opt-out zone
-        res = self.sendQuery('ns2.optout.example.', 'A')
+        res = self.sendQuery("ns2.optout.example.", "A")
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
 
         # check that we _do not_ use the aggressive NSEC cache
-        nbQueries = self.getMetric('all-outqueries')
-        res = self.sendQuery('ns3.optout.example.', 'A')
+        nbQueries = self.getMetric("all-outqueries")
+        res = self.sendQuery("ns3.optout.example.", "A")
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
-        self.assertGreater(self.getMetric('all-outqueries'), nbQueries)
+        self.assertGreater(self.getMetric("all-outqueries"), nbQueries)
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 0)
index dd9b4db5e9985a1a99b68c71547bcd8720948779..b239ce0732bb8030508a09ea8d4fbbd1b90e03f9 100644 (file)
@@ -3,22 +3,28 @@ import os
 import socket
 from recursortests import RecursorTest
 
+
 class AnyBindTest(RecursorTest):
-    _confdir = 'AnyBind'
+    _confdir = "AnyBind"
     _auth_zones = RecursorTest._default_auth_zones
 
-    _config_template = """dnssec=validate
+    _config_template = (
+        """dnssec=validate
     local-address=0.0.0.0
-auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
+auth-zones=authzone.example=configs/%s/authzone.zone"""
+        % _confdir
+    )
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'authzone.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN authzone.example.
+        authzonepath = os.path.join(confdir, "authzone.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN authzone.example.
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(AnyBindTest, cls).generateRecursorConfig(confdir)
 
     @classmethod
@@ -30,8 +36,10 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
 
     def testA(self):
         """Test to see if we get a reply from 127.0.0.2 if rec is bound to ANY address"""
-        expected = dns.rrset.from_text('ns.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.9'.format(prefix=self._PREFIX))
-        query = dns.message.make_query('ns.secure.example', 'A', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "ns.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.9".format(prefix=self._PREFIX)
+        )
+        query = dns.message.make_query("ns.secure.example", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
@@ -39,4 +47,3 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertMessageIsAuthenticated(res)
         self.assertRRsetInAnswer(res, expected)
         self.assertMatchingRRSIGInAnswer(res, expected)
-
index 6b51bf78562a993b6759d28b31a5110f006a649b..71ee17b6262d77256c300b73def29091187e8655 100644 (file)
@@ -7,10 +7,11 @@ from queue import Queue
 
 from recursortests import RecursorTest
 
+
 class CarbonTest(RecursorTest):
-    _confdir = 'Carbon'
-    _carbonNamespace = 'NS'
-    _carbonInstance = 'Instance'
+    _confdir = "Carbon"
+    _carbonNamespace = "NS"
+    _carbonInstance = "Instance"
     _carbonServerName = "carbonname1"
     _carbonInterval = 1
     _carbonServer1Port = 8000
@@ -24,7 +25,14 @@ class CarbonTest(RecursorTest):
     carbon-interval=%s
     carbon-ourname=%s
     carbon-server=127.0.0.1:%s,127.0.01:%s
-    """ % (_carbonNamespace, _carbonInstance, _carbonInterval, _carbonServerName, _carbonServer1Port,  _carbonServer2Port)
+    """ % (
+        _carbonNamespace,
+        _carbonInstance,
+        _carbonInterval,
+        _carbonServerName,
+        _carbonServer1Port,
+        _carbonServer2Port,
+    )
 
     @classmethod
     def CarbonResponder(cls, port):
@@ -40,7 +48,7 @@ class CarbonTest(RecursorTest):
         while True:
             (conn, _) = sock.accept()
             conn.settimeout(2.0)
-            lines = b''
+            lines = b""
             while True:
                 data = conn.recv(4096)
                 if not data:
@@ -60,11 +68,15 @@ class CarbonTest(RecursorTest):
 
     @classmethod
     def startResponders(cls):
-        cls._CarbonResponder1 = threading.Thread(name='Carbon Responder 1', target=cls.CarbonResponder, args=[cls._carbonServer1Port])
+        cls._CarbonResponder1 = threading.Thread(
+            name="Carbon Responder 1", target=cls.CarbonResponder, args=[cls._carbonServer1Port]
+        )
         cls._CarbonResponder1.daemon = True
         cls._CarbonResponder1.start()
 
-        cls._CarbonResponder2 = threading.Thread(name='Carbon Responder 2', target=cls.CarbonResponder, args=[cls._carbonServer2Port])
+        cls._CarbonResponder2 = threading.Thread(
+            name="Carbon Responder 2", target=cls.CarbonResponder, args=[cls._carbonServer2Port]
+        )
         cls._CarbonResponder2.daemon = True
         cls._CarbonResponder2.start()
 
@@ -86,10 +98,14 @@ class CarbonTest(RecursorTest):
 
         self.assertTrue(data1)
         self.assertGreater(len(data1.splitlines()), 1)
-        expectedStart = b"%s.%s.%s." % (self._carbonNamespace.encode('UTF8'), self._carbonServerName.encode('UTF-8'), self._carbonInstance.encode('UTF8'))
+        expectedStart = b"%s.%s.%s." % (
+            self._carbonNamespace.encode("UTF8"),
+            self._carbonServerName.encode("UTF-8"),
+            self._carbonInstance.encode("UTF8"),
+        )
         for line in data1.splitlines():
             self.assertTrue(line.startswith(expectedStart))
-            parts = line.split(b' ')
+            parts = line.split(b" ")
             self.assertEqual(len(parts), 3)
             self.assertTrue(parts[1].isdigit())
             self.assertTrue(parts[2].isdigit())
@@ -97,10 +113,14 @@ class CarbonTest(RecursorTest):
 
         self.assertTrue(data2)
         self.assertGreater(len(data2.splitlines()), 1)
-        expectedStart = b"%s.%s.%s." % (self._carbonNamespace.encode('UTF8'), self._carbonServerName.encode('UTF-8'), self._carbonInstance.encode('UTF8'))
+        expectedStart = b"%s.%s.%s." % (
+            self._carbonNamespace.encode("UTF8"),
+            self._carbonServerName.encode("UTF-8"),
+            self._carbonInstance.encode("UTF8"),
+        )
         for line in data2.splitlines():
             self.assertTrue(line.startswith(expectedStart))
-            parts = line.split(b' ')
+            parts = line.split(b" ")
             self.assertEqual(len(parts), 3)
             self.assertTrue(parts[1].isdigit())
             self.assertTrue(parts[2].isdigit())
@@ -110,4 +130,3 @@ class CarbonTest(RecursorTest):
         for key in self._carbonCounters:
             value = self._carbonCounters[key]
             self.assertGreaterEqual(value, 1)
-
index d4871718ce41bd2fdae0adbd02490b517fd0fdc3..bb255850eca18fa7a19333109378f3ff9b9c3d03 100644 (file)
@@ -2,17 +2,19 @@ import dns
 import clientsubnetoption
 from recursortests import RecursorTest
 
+
 class ChainTest(RecursorTest):
     """
     These regression tests test the chaining of outgoing requests.
     """
+
     _auth_zones = RecursorTest._default_auth_zones
     _chainSize = 200
-    _confdir = 'Chain'
+    _confdir = "Chain"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
 
     _config_template = """dnssec=validate
     trace=no
@@ -32,11 +34,11 @@ class ChainTest(RecursorTest):
         clashing waiter ids.
         """
         count = self._chainSize
-        name = '9.delay1.example.'
-        exp = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', 'a')
+        name = "9.delay1.example."
+        exp = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", "a")
         queries = []
         for i in range(count):
-            query = dns.message.make_query(name, 'TXT', want_dnssec=True)
+            query = dns.message.make_query(name, "TXT", want_dnssec=True)
             query.flags |= dns.flags.AD
             queries.append(query)
 
@@ -50,23 +52,27 @@ class ChainTest(RecursorTest):
             self.assertRRsetInAnswer(res, exp)
             self.assertMatchingRRSIGInAnswer(res, exp)
 
-        self.checkMetrics({
-            'max-chain-length': count - 1, # first request has count - 1 requests chained to it
-            'servfail-answers': 0,
-            'noerror-answers': count,
-        })
+        self.checkMetrics(
+            {
+                "max-chain-length": count - 1,  # first request has count - 1 requests chained to it
+                "servfail-answers": 0,
+                "noerror-answers": count,
+            }
+        )
+
 
 class ChainECSTest(RecursorTest):
     """
     These regression tests test the chaining of outgoing requests with ECS
     """
+
     _auth_zones = RecursorTest._default_auth_zones
     _chainSize = 200
-    _confdir = 'ChainECS'
+    _confdir = "ChainECS"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
 
     _config_template = """dnssec=validate
     trace=no
@@ -88,21 +94,21 @@ class ChainECSTest(RecursorTest):
         clashing waiter ids.
         """
         count = self._chainSize
-        name1 = '1.delay1.example.'
-        name2 = '2.delay1.example.'
-        exp1 = dns.rrset.from_text(name1, 0, dns.rdataclass.IN, 'TXT', 'a')
-        exp2 = dns.rrset.from_text(name2, 0, dns.rdataclass.IN, 'TXT', 'a')
+        name1 = "1.delay1.example."
+        name2 = "2.delay1.example."
+        exp1 = dns.rrset.from_text(name1, 0, dns.rdataclass.IN, "TXT", "a")
+        exp2 = dns.rrset.from_text(name2, 0, dns.rdataclass.IN, "TXT", "a")
         queries = []
         for i in range(count):
             if i % 3 == 0:
                 name = name1
             else:
-               name = name2
+                name = name2
             if i % 2 == 0:
-                ecso = clientsubnetoption.ClientSubnetOption('192.0.2.0', 24)
+                ecso = clientsubnetoption.ClientSubnetOption("192.0.2.0", 24)
             else:
-                ecso = clientsubnetoption.ClientSubnetOption('192.0.3.0', 24)
-            query = dns.message.make_query(name, 'TXT', use_edns=True, options=[ecso], want_dnssec=True)
+                ecso = clientsubnetoption.ClientSubnetOption("192.0.3.0", 24)
+            query = dns.message.make_query(name, "TXT", use_edns=True, options=[ecso], want_dnssec=True)
             query.flags |= dns.flags.AD
             queries.append(query)
 
@@ -123,22 +129,26 @@ class ChainECSTest(RecursorTest):
                 print("?? " + res.question[0].name.to_text())
                 self.assertEqual(0, 1)
 
-        self.checkMetrics({
-            'servfail-answers': 0,
-            'noerror-answers': count,
-        })
+        self.checkMetrics(
+            {
+                "servfail-answers": 0,
+                "noerror-answers": count,
+            }
+        )
+
 
 class ChainECSHardenedTest(RecursorTest):
     """
     These regression tests test the chaining of outgoing requests with ECS
     """
+
     _auth_zones = RecursorTest._default_auth_zones
     _chainSize = 200
-    _confdir = 'ChainECSHardened'
+    _confdir = "ChainECSHardened"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
 
     _config_template = """dnssec=validate
     trace=no
@@ -161,21 +171,21 @@ class ChainECSHardenedTest(RecursorTest):
         clashing waiter ids.
         """
         count = self._chainSize
-        name1 = '1.delay1.example.'
-        name2 = '2.delay1.example.'
-        exp1 = dns.rrset.from_text(name1, 0, dns.rdataclass.IN, 'TXT', 'a')
-        exp2 = dns.rrset.from_text(name2, 0, dns.rdataclass.IN, 'TXT', 'a')
+        name1 = "1.delay1.example."
+        name2 = "2.delay1.example."
+        exp1 = dns.rrset.from_text(name1, 0, dns.rdataclass.IN, "TXT", "a")
+        exp2 = dns.rrset.from_text(name2, 0, dns.rdataclass.IN, "TXT", "a")
         queries = []
         for i in range(count):
             if i % 3 == 0:
                 name = name1
             else:
-               name = name2
+                name = name2
             if i % 2 == 0:
-                ecso = clientsubnetoption.ClientSubnetOption('192.0.2.0', 24)
+                ecso = clientsubnetoption.ClientSubnetOption("192.0.2.0", 24)
             else:
-                ecso = clientsubnetoption.ClientSubnetOption('192.0.3.0', 24)
-            query = dns.message.make_query(name, 'TXT', use_edns=True, options=[ecso], want_dnssec=True)
+                ecso = clientsubnetoption.ClientSubnetOption("192.0.3.0", 24)
+            query = dns.message.make_query(name, "TXT", use_edns=True, options=[ecso], want_dnssec=True)
             query.flags |= dns.flags.AD
             queries.append(query)
 
@@ -196,8 +206,9 @@ class ChainECSHardenedTest(RecursorTest):
                 print("?? " + res.question[0].name.to_text())
                 self.assertEqual(0, 1)
 
-        self.checkMetrics({
-            'servfail-answers': 0,
-            'noerror-answers': count,
-        })
-
+        self.checkMetrics(
+            {
+                "servfail-answers": 0,
+                "noerror-answers": count,
+            }
+        )
index fdd6c8cf2c3f1ead2f2e9d0242bd5cf6304d206b..53934dbcc6442375fd29f69c9c6772e0ad14bb52 100644 (file)
@@ -13,8 +13,9 @@ from recursortests import RecursorTest
 
 cookieReactorRunning = False
 
+
 class CookiesTest(RecursorTest):
-    _confdir = 'Cookies'
+    _confdir = "Cookies"
     _config_template = """
 recursor:
   forward_zones:
@@ -25,9 +26,9 @@ outgoing:
   cookies: true
 packetcache:
   disable: true
-""" % (os.environ['PREFIX'], os.environ['PREFIX'])
+""" % (os.environ["PREFIX"], os.environ["PREFIX"])
 
-    _expectedCookies = 'no'
+    _expectedCookies = "no"
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
@@ -39,7 +40,7 @@ packetcache:
 
         cls.startResponders()
 
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         cls.createConfigDir(confdir)
 
         cls.generateRecursorConfig(confdir)
@@ -52,8 +53,8 @@ packetcache:
         global cookieReactorRunning
         print("Launching responders..")
 
-        address1 = cls._PREFIX + '.25'
-        address2 = cls._PREFIX + '.26'
+        address1 = cls._PREFIX + ".25"
+        address2 = cls._PREFIX + ".26"
         port = 53
 
         if not cookieReactorRunning:
@@ -65,20 +66,20 @@ packetcache:
 
         cls.startReactor()
 
-    def checkCookies(self, support, server='127.0.0.25'):
-        confdir = os.path.join('configs', self._confdir)
-        output = self.recControl(confdir, 'dump-cookies', '-')
+    def checkCookies(self, support, server="127.0.0.25"):
+        confdir = os.path.join("configs", self._confdir)
+        output = self.recControl(confdir, "dump-cookies", "-")
         for line in output.splitlines():
             tokens = line.split()
             if tokens[0] != server:
                 continue
-            #print(tokens)
+            # print(tokens)
             self.assertEqual(len(tokens), 5)
             self.assertEqual(tokens[3], support)
 
     def checkAtLeastOneCookies(self, support):
-        confdir = os.path.join('configs', self._confdir)
-        output = self.recControl(confdir, 'dump-cookies', '-')
+        confdir = os.path.join("configs", self._confdir)
+        output = self.recControl(confdir, "dump-cookies", "-")
         ok = False
         for line in output.splitlines():
             tokens = line.split()
@@ -86,100 +87,101 @@ packetcache:
                 continue
             if tokens[3] == support:
                 ok = True
-        assert(ok)
+        assert ok
 
     def testAuthDoesnotSendCookies(self):
         # Case: rec does not get a cookie back
-        expected = dns.rrset.from_text('unsupported.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
-        query = dns.message.make_query('unsupported.cookies.example.', 'A')
+        expected = dns.rrset.from_text("unsupported.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
+        query = dns.message.make_query("unsupported.cookies.example.", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
-        self.checkCookies('Unsupported')
+        self.checkCookies("Unsupported")
 
     def testAuthRepliesWithCookie(self):
-        confdir = os.path.join('configs', self._confdir)
+        confdir = os.path.join("configs", self._confdir)
         # Case: rec gets a proper client and server cookie back
-        self.recControl(confdir, 'clear-cookies', '*')
-        tcp1 = self.recControl(confdir, 'get tcp-outqueries')
-        query = dns.message.make_query('supported.cookies.example.', 'A')
-        expected = dns.rrset.from_text('supported.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        self.recControl(confdir, "clear-cookies", "*")
+        tcp1 = self.recControl(confdir, "get tcp-outqueries")
+        query = dns.message.make_query("supported.cookies.example.", "A")
+        expected = dns.rrset.from_text("supported.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
-        self.checkAtLeastOneCookies('Supported')
-        tcp2 = self.recControl(confdir, 'get tcp-outqueries')
+        self.checkAtLeastOneCookies("Supported")
+        tcp2 = self.recControl(confdir, "get tcp-outqueries")
         self.assertEqual(tcp1, tcp2)
 
         # Case: we get a correct client and server cookie back
         # We do not clear the cookie tables, so the old server cookie gets re-used
-        query = dns.message.make_query('supported2.cookies.example.', 'A')
-        expected = dns.rrset.from_text('supported2.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        query = dns.message.make_query("supported2.cookies.example.", "A")
+        expected = dns.rrset.from_text("supported2.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
-        self.checkAtLeastOneCookies('Supported')
+        self.checkAtLeastOneCookies("Supported")
 
     def testAuthSendsIncorrectClientCookie(self):
-        confdir = os.path.join('configs', self._confdir)
+        confdir = os.path.join("configs", self._confdir)
         # Case: rec gets an incorrect client cookie back, we ignore that and go to TCP
-        self.recControl(confdir, 'clear-cookies', '*')
-        tcp1 = self.recControl(confdir, 'get tcp-outqueries')
-        query = dns.message.make_query('wrongcc.cookies.example.', 'A')
-        expected = dns.rrset.from_text('wrongcc.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        self.recControl(confdir, "clear-cookies", "*")
+        tcp1 = self.recControl(confdir, "get tcp-outqueries")
+        query = dns.message.make_query("wrongcc.cookies.example.", "A")
+        expected = dns.rrset.from_text("wrongcc.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
-        self.checkCookies('Probing')
-        tcp2 = int(self.recControl(confdir, 'get tcp-outqueries'))
+        self.checkCookies("Probing")
+        tcp2 = int(self.recControl(confdir, "get tcp-outqueries"))
         self.assertEqual(int(tcp1) + 1, int(tcp2))
 
     def testAuthSendsBADCOOKIEOverUDP(self):
-        confdir = os.path.join('configs', self._confdir)
+        confdir = os.path.join("configs", self._confdir)
         # Case: rec gets a BADCOOKIE, even on retry and should fall back to TCP
-        self.recControl(confdir, 'clear-cookies', '*')
-        tcp1 = self.recControl(confdir, 'get tcp-outqueries')
-        query = dns.message.make_query('badcookie.cookies.example.', 'A')
-        expected = dns.rrset.from_text('badcookie.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        self.recControl(confdir, "clear-cookies", "*")
+        tcp1 = self.recControl(confdir, "get tcp-outqueries")
+        query = dns.message.make_query("badcookie.cookies.example.", "A")
+        expected = dns.rrset.from_text("badcookie.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
-        self.checkCookies('Supported')
-        tcp2 = int(self.recControl(confdir, 'get tcp-outqueries'))
+        self.checkCookies("Supported")
+        tcp2 = int(self.recControl(confdir, "get tcp-outqueries"))
         self.assertEqual(int(tcp1) + 1, int(tcp2))
 
     def testAuthSendsMalformedCookie(self):
-        confdir = os.path.join('configs', self._confdir)
+        confdir = os.path.join("configs", self._confdir)
         # Case: rec gets a malformed cookie, should ignore packet
-        self.recControl(confdir, 'clear-cookies', '*')
-        query = dns.message.make_query('malformed.cookies.example.', 'A')
-        expected = dns.rrset.from_text('malformed.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        self.recControl(confdir, "clear-cookies", "*")
+        query = dns.message.make_query("malformed.cookies.example.", "A")
+        expected = dns.rrset.from_text("malformed.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
-        self.checkCookies('Probing', '127.0.0.25')
-        self.checkCookies('Supported', '127.0.0.26')
+        self.checkCookies("Probing", "127.0.0.25")
+        self.checkCookies("Supported", "127.0.0.26")
 
     def testForgottenCookie(self):
-        confdir = os.path.join('configs', self._confdir)
+        confdir = os.path.join("configs", self._confdir)
         # Case: rec gets a proper client and server cookie back
-        self.recControl(confdir, 'clear-cookies', '*')
-        query = dns.message.make_query('supported3.cookies.example.', 'A')
-        expected = dns.rrset.from_text('supported3.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        self.recControl(confdir, "clear-cookies", "*")
+        query = dns.message.make_query("supported3.cookies.example.", "A")
+        expected = dns.rrset.from_text("supported3.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
-        self.checkCookies('Supported')
+        self.checkCookies("Supported")
 
         # Case: we get a correct client and server cookie back
         # We HAVE cleared the cookie tables, so the old server cookie is forgotten
-        self.recControl(confdir, 'clear-cookies', '*')
-        query = dns.message.make_query('supported4.cookies.example.', 'A')
-        expected = dns.rrset.from_text('supported4.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        self.recControl(confdir, "clear-cookies", "*")
+        query = dns.message.make_query("supported4.cookies.example.", "A")
+        expected = dns.rrset.from_text("supported4.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
-        self.checkCookies('Supported')
+        self.checkCookies("Supported")
+
 
 class UDPResponder(DatagramProtocol):
     def getCookie(self, message):
@@ -194,9 +196,9 @@ class UDPResponder(DatagramProtocol):
     def createCookie(self, clientcookie):
         clientcookie = clientcookie[0:8]
         timestamp = int(time.time())
-        server = clientcookie + b'\x01\x00\x00\x00' + timestamp.to_bytes(4, 'big')
-        h = hash(server +  b'\x01\x00\x00\x7f' + b'secret') % pow(2, 64)
-        full = dns.edns.GenericOption(dns.edns.COOKIE, server + h.to_bytes(8, 'big'))
+        server = clientcookie + b"\x01\x00\x00\x00" + timestamp.to_bytes(4, "big")
+        h = hash(server + b"\x01\x00\x00\x7f" + b"secret") % pow(2, 64)
+        full = dns.edns.GenericOption(dns.edns.COOKIE, server + h.to_bytes(8, "big"))
         return full
 
     def question(self, datagram, tcp=False):
@@ -208,73 +210,73 @@ class UDPResponder(DatagramProtocol):
         question = request.question[0]
 
         # Case: do not send cookie back
-        if question.name == dns.name.from_text('unsupported.cookies.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('unsupported.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        if question.name == dns.name.from_text("unsupported.cookies.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("unsupported.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             response.answer.append(answer)
 
         # Case: do send cookie back
-        elif question.name == dns.name.from_text('supported.cookies.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('supported.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        elif question.name == dns.name.from_text("supported.cookies.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("supported.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             clientcookie = self.getCookie(request)
             if clientcookie is not None:
-                response.use_edns(options = [self.createCookie(clientcookie)])
+                response.use_edns(options=[self.createCookie(clientcookie)])
             response.answer.append(answer)
 
         # We get a good client and server cookie
-        elif question.name == dns.name.from_text('supported2.cookies.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('supported2.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        elif question.name == dns.name.from_text("supported2.cookies.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("supported2.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             clientcookie = self.getCookie(request)
             if clientcookie is not None:
-                response.use_edns(options = [self.createCookie(clientcookie)])
+                response.use_edns(options=[self.createCookie(clientcookie)])
             response.answer.append(answer)
 
         # Case: do send cookie back
-        elif question.name == dns.name.from_text('supported3.cookies.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('supported3.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        elif question.name == dns.name.from_text("supported3.cookies.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("supported3.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             clientcookie = self.getCookie(request)
             if clientcookie is not None:
-                response.use_edns(options = [self.createCookie(clientcookie)])
+                response.use_edns(options=[self.createCookie(clientcookie)])
             response.answer.append(answer)
 
         # We get a new client cookie as the cookie store was cleared
-        elif question.name == dns.name.from_text('supported4.cookies.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('supported4.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        elif question.name == dns.name.from_text("supported4.cookies.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("supported4.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             clientcookie = self.getCookie(request)
             if clientcookie is not None:
-                response.use_edns(options = [self.createCookie(clientcookie)])
+                response.use_edns(options=[self.createCookie(clientcookie)])
             response.answer.append(answer)
 
         # Case: do send incorrect client cookie back
-        elif question.name == dns.name.from_text('wrongcc.cookies.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('wrongcc.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        elif question.name == dns.name.from_text("wrongcc.cookies.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("wrongcc.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             clientcookie = self.getCookie(request)
             if clientcookie is not None:
                 mod = bytearray(clientcookie)
                 mod[0] = 1
-                response.use_edns(options = [self.createCookie(bytes(mod))])
+                response.use_edns(options=[self.createCookie(bytes(mod))])
             response.answer.append(answer)
 
         # Case: do send BADCOOKIE cookie back if UDP
-        elif question.name == dns.name.from_text('badcookie.cookies.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('badcookie.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        elif question.name == dns.name.from_text("badcookie.cookies.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("badcookie.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             clientcookie = self.getCookie(request)
             if clientcookie is not None:
-                response.use_edns(options = [self.createCookie(clientcookie)])
+                response.use_edns(options=[self.createCookie(clientcookie)])
                 if not tcp:
-                    response.set_rcode(23) # BADCOOKIE
+                    response.set_rcode(23)  # BADCOOKIE
             response.answer.append(answer)
 
         # Case send malformed cookie for server .25
-        elif question.name == dns.name.from_text('malformed.cookies.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('malformed.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        elif question.name == dns.name.from_text("malformed.cookies.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("malformed.cookies.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             clientcookie = self.getCookie(request)
             print(self.transport.getHost().host)
-            if self.transport.getHost().host == os.environ['PREFIX'] + '.26':
+            if self.transport.getHost().host == os.environ["PREFIX"] + ".26":
                 if clientcookie is not None:
-                    response.use_edns(options = [self.createCookie(clientcookie)])
+                    response.use_edns(options=[self.createCookie(clientcookie)])
             else:
-                full = dns.edns.GenericOption(dns.edns.COOKIE, '')
-                response.use_edns(options = [full])
+                full = dns.edns.GenericOption(dns.edns.COOKIE, "")
+                response.use_edns(options=[full])
             response.answer.append(answer)
 
         return response.to_wire()
@@ -283,14 +285,16 @@ class UDPResponder(DatagramProtocol):
         response = self.question(datagram)
         self.transport.write(response, address)
 
+
 class TCPResponder(Protocol):
     def dataReceived(self, data):
         handler = UDPResponder()
         response = handler.question(data[2:], True)
         length = len(response)
-        header = length.to_bytes(2, 'big')
+        header = length.to_bytes(2, "big")
         self.transport.write(header + response)
 
+
 class TCPFactory(Factory):
     def buildProtocol(self, addr):
         return TCPResponder()
index ae87d7d0e9b55255dfe968414f3e2c924d5507c2..c8253f9d07389f82738304e29fbee42cc44fd185 100644 (file)
@@ -3,9 +3,9 @@ import os
 
 from recursortests import RecursorTest
 
-class DNS64Test(RecursorTest):
 
-    _confdir = 'DNS64'
+class DNS64Test(RecursorTest):
+    _confdir = "DNS64"
     _auth_zones = RecursorTest._default_auth_zones
     _config_template = """
     serve-rfc6303=no
@@ -28,9 +28,10 @@ class DNS64Test(RecursorTest):
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.dns64.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.dns64
+        authzonepath = os.path.join(confdir, "example.dns64.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.dns64
 @ 3600 IN SOA {soa}
 www 3600 IN A 192.0.2.42
 www 3600 IN TXT "does exist"
@@ -40,30 +41,35 @@ cname 3600 IN CNAME cname2.example.dns64.
 cname2 3600 IN CNAME www.example.dns64.
 cname3 3600 IN CNAME txt.example.dns64.
 formerr 3600 IN A 192.0.2.43
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        authzonepath = os.path.join(confdir, 'in-addr.arpa.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN in-addr.arpa
+        authzonepath = os.path.join(confdir, "in-addr.arpa.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN in-addr.arpa
 @ 3600 IN SOA {soa}
 42.2.0.192 IN PTR www.example.dns64.
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        authzonepath = os.path.join(confdir, 'ip6.arpa.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN ip6.arpa
+        authzonepath = os.path.join(confdir, "ip6.arpa.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN ip6.arpa
 @ 3600 IN SOA {soa}
 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2 IN PTR aaaa.example.dns64.
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
         super(DNS64Test, cls).generateRecursorConfig(confdir)
 
     # this type (A) exists for this name
     def testExistingA(self):
-        qname = 'www.example.dns64.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
+        qname = "www.example.dns64."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.42")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -72,9 +78,9 @@ formerr 3600 IN A 192.0.2.43
 
     # there is no A record, we should get a NODATA
     def testNonExistingA(self):
-        qname = 'aaaa.example.dns64.'
+        qname = "aaaa.example.dns64."
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -83,10 +89,10 @@ formerr 3600 IN A 192.0.2.43
 
     # this type (AAAA) does not exist for this name but there is an A record, we should get a DNS64-wrapped AAAA
     def testNonExistingAAAA(self):
-        qname = 'www.example.dns64.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'AAAA', '64:ff9b::c000:22a')
+        qname = "www.example.dns64."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "AAAA", "64:ff9b::c000:22a")
 
-        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        query = dns.message.make_query(qname, "AAAA", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -96,14 +102,14 @@ formerr 3600 IN A 192.0.2.43
     # there is a CNAME from that name to a second one, then to a name for which this type (AAAA)
     # does not exist, but an A record does, so we should get a DNS64-wrapped AAAA
     def testCNAMEToA(self):
-        qname = 'cname.example.dns64.'
+        qname = "cname.example.dns64."
         expectedResults = [
-            dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'CNAME', 'cname2.example.dns64.'),
-            dns.rrset.from_text('cname2.example.dns64.', 0, dns.rdataclass.IN, 'CNAME', 'www.example.dns64.'),
-            dns.rrset.from_text('www.example.dns64.', 0, dns.rdataclass.IN, 'AAAA', '64:ff9b::c000:22a')
+            dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "CNAME", "cname2.example.dns64."),
+            dns.rrset.from_text("cname2.example.dns64.", 0, dns.rdataclass.IN, "CNAME", "www.example.dns64."),
+            dns.rrset.from_text("www.example.dns64.", 0, dns.rdataclass.IN, "AAAA", "64:ff9b::c000:22a"),
         ]
 
-        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        query = dns.message.make_query(qname, "AAAA", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -114,13 +120,13 @@ formerr 3600 IN A 192.0.2.43
     # there is a CNAME from the name to a name that is NODATA for both A and AAAA
     # so we should get a NODATA with a single SOA record (#14362)
     def testCNAMEToNoData(self):
-        qname = 'cname3.example.dns64.'
+        qname = "cname3.example.dns64."
 
-        expectedAnswer = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'CNAME', 'txt.example.dns64.')
-        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        expectedAnswer = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "CNAME", "txt.example.dns64.")
+        query = dns.message.make_query(qname, "AAAA", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
-            res = sender(query, 2.0, True, {"one_rr_per_rrset": True}) # we want to detect dups
+            res = sender(query, 2.0, True, {"one_rr_per_rrset": True})  # we want to detect dups
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertEqual(len(res.answer), 1)
             self.assertEqual(len(res.authority), 1)
@@ -129,9 +135,9 @@ formerr 3600 IN A 192.0.2.43
 
     # this type (AAAA) does not exist for this name and there is no A record either, we should get a NXDomain
     def testNXD(self):
-        qname = 'nxd.example.dns64.'
+        qname = "nxd.example.dns64."
 
-        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        query = dns.message.make_query(qname, "AAAA", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -139,22 +145,22 @@ formerr 3600 IN A 192.0.2.43
 
     # this type (AAAA) does not exist for this name and there is no A record either, we should get a NODATA as TXT does exist
     def testNoData(self):
-        qname = 'txt.example.dns64.'
+        qname = "txt.example.dns64."
 
-        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        query = dns.message.make_query(qname, "AAAA", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
-            res = sender(query, 2.0, True, {"one_rr_per_rrset": True}) # we want to detect dups
+            res = sender(query, 2.0, True, {"one_rr_per_rrset": True})  # we want to detect dups
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertEqual(len(res.answer), 0)
             self.assertEqual(len(res.authority), 1)
 
     # there is an AAAA record, we should get it
     def testExistingAAAA(self):
-        qname = 'aaaa.example.dns64.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'AAAA', '2001:db8::1')
+        qname = "aaaa.example.dns64."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "AAAA", "2001:db8::1")
 
-        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        query = dns.message.make_query(qname, "AAAA", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -163,9 +169,9 @@ formerr 3600 IN A 192.0.2.43
 
     # If the AAAA is handled by Lua code, we should not get a dns64 result
     def testFormerr(self):
-        qname = 'formerr.example.dns64'
+        qname = "formerr.example.dns64"
 
-        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        query = dns.message.make_query(qname, "AAAA", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -173,10 +179,10 @@ formerr 3600 IN A 192.0.2.43
 
     # If the AAAA times out, we still should get a dns64 result
     def testTimeout(self):
-        qname = '8.delay1.example.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'AAAA', '64:ff9b::c000:264')
+        qname = "8.delay1.example."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "AAAA", "64:ff9b::c000:264")
 
-        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        query = dns.message.make_query(qname, "AAAA", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -185,10 +191,10 @@ formerr 3600 IN A 192.0.2.43
 
     # there is a TXT record, we should get it
     def testExistingTXT(self):
-        qname = 'www.example.dns64.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'TXT', '"does exist"')
+        qname = "www.example.dns64."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "TXT", '"does exist"')
 
-        query = dns.message.make_query(qname, 'TXT', want_dnssec=True)
+        query = dns.message.make_query(qname, "TXT", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -197,11 +203,11 @@ formerr 3600 IN A 192.0.2.43
 
     # the PTR records for the DNS64 prefix should be generated
     def testNonExistingPTR(self):
-        qname = 'a.2.2.0.0.0.0.c.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.9.f.f.4.6.0.0.ip6.arpa.'
-        expectedCNAME = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'CNAME', '42.2.0.192.in-addr.arpa.')
-        expected = dns.rrset.from_text('42.2.0.192.in-addr.arpa.', 0, dns.rdataclass.IN, 'PTR', 'www.example.dns64.')
+        qname = "a.2.2.0.0.0.0.c.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.9.f.f.4.6.0.0.ip6.arpa."
+        expectedCNAME = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "CNAME", "42.2.0.192.in-addr.arpa.")
+        expected = dns.rrset.from_text("42.2.0.192.in-addr.arpa.", 0, dns.rdataclass.IN, "PTR", "www.example.dns64.")
 
-        query = dns.message.make_query(qname, 'PTR', want_dnssec=True)
+        query = dns.message.make_query(qname, "PTR", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -212,10 +218,10 @@ formerr 3600 IN A 192.0.2.43
 
     # but not for other prefixes
     def testExistingPTR(self):
-        qname = '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'PTR', 'aaaa.example.dns64.')
+        qname = "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "PTR", "aaaa.example.dns64.")
 
-        query = dns.message.make_query(qname, 'PTR', want_dnssec=True)
+        query = dns.message.make_query(qname, "PTR", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
index 5e7dd30a8810d90e4f23c52cb515595ea14fcdc9..a81e8fb9bd673a442d631f0659e6c89aca9567c0 100644 (file)
@@ -10,12 +10,13 @@ from queue import Queue
 
 from recursortests import RecursorTest
 
+
 class SimpleDoTTest(RecursorTest):
     """
     This tests DoT to auth server in a very basic way and is dependent on powerdns.com nameservers having DoT enabled.
     """
 
-    _confdir = 'SimpleDoT'
+    _confdir = "SimpleDoT"
     _config_template = """
 dnssec=validate
 dot-to-auth-names=powerdns.com
@@ -26,17 +27,19 @@ devonly-regression-test-mode
 
     @pytest.mark.external
     def testTXT(self):
-        query = dns.message.make_query('.', 'DNSKEY', want_dnssec=True)
+        query = dns.message.make_query(".", "DNSKEY", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         # As this test uses external servers, be more generous wrt timeouts than the default 2.0s
         res = self.sendUDPQuery(query, timeout=5.0)
 
         self.assertMessageIsAuthenticated(res)
-        self.assertRcodeEqual(res, 0);
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'get tcp-outqueries']
+        self.assertRcodeEqual(res, 0)
+        rec_controlCmd = [
+            os.environ["RECCONTROL"],
+            "--config-dir=%s" % "configs/" + self._confdir,
+            "get tcp-outqueries",
+        ]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
             tcpcount = ret
@@ -45,8 +48,10 @@ devonly-regression-test-mode
             print(e.output)
             raise
 
-        expected = dns.rrset.from_text('dot-test-target.powerdns.org.', 0, dns.rdataclass.IN, 'TXT', 'https://github.com/PowerDNS/pdns/pull/12825')
-        query = dns.message.make_query('dot-test-target.powerdns.org', 'TXT', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "dot-test-target.powerdns.org.", 0, dns.rdataclass.IN, "TXT", "https://github.com/PowerDNS/pdns/pull/12825"
+        )
+        query = dns.message.make_query("dot-test-target.powerdns.org", "TXT", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         # As this test uses external servers, be a more generous wrt timeouts than the default 2.0s
@@ -56,21 +61,25 @@ devonly-regression-test-mode
         self.assertRRsetInAnswer(res, expected)
         self.assertMatchingRRSIGInAnswer(res, expected)
 
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'get dot-outqueries']
+        rec_controlCmd = [
+            os.environ["RECCONTROL"],
+            "--config-dir=%s" % "configs/" + self._confdir,
+            "get dot-outqueries",
+        ]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
-            self.assertNotEqual(ret, b'UNKNOWN\n')
-            self.assertNotEqual(ret, b'0\n')
+            self.assertNotEqual(ret, b"UNKNOWN\n")
+            self.assertNotEqual(ret, b"0\n")
 
         except subprocess.CalledProcessError as e:
             print(e.output)
             raise
 
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'get tcp-outqueries']
+        rec_controlCmd = [
+            os.environ["RECCONTROL"],
+            "--config-dir=%s" % "configs/" + self._confdir,
+            "get tcp-outqueries",
+        ]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
             self.assertEqual(ret, tcpcount)
@@ -79,12 +88,13 @@ devonly-regression-test-mode
             print(e.output)
             raise
 
+
 class DoTTest(RecursorTest):
     """
     This tests DoT to auth server with validation and is dependent on powerdns.com nameservers having DoT enabled.
     """
 
-    _confdir = 'DoT'
+    _confdir = "DoT"
     _config_template = """
 dnssec:
     validation: validate
@@ -107,17 +117,19 @@ recursor:
 
     @pytest.mark.external
     def testTXT(self):
-        query = dns.message.make_query('.', 'DNSKEY', want_dnssec=True)
+        query = dns.message.make_query(".", "DNSKEY", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         # As this test uses external servers, be more generous wrt timeouts than the default 2.0s
         res = self.sendUDPQuery(query, timeout=5.0)
 
         self.assertMessageIsAuthenticated(res)
-        self.assertRcodeEqual(res, 0);
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'get tcp-outqueries']
+        self.assertRcodeEqual(res, 0)
+        rec_controlCmd = [
+            os.environ["RECCONTROL"],
+            "--config-dir=%s" % "configs/" + self._confdir,
+            "get tcp-outqueries",
+        ]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
             tcpcount = ret
@@ -126,8 +138,10 @@ recursor:
             print(e.output)
             raise
 
-        expected = dns.rrset.from_text('dot-test-target.powerdns.org.', 0, dns.rdataclass.IN, 'TXT', 'https://github.com/PowerDNS/pdns/pull/12825')
-        query = dns.message.make_query('dot-test-target.powerdns.org', 'TXT', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "dot-test-target.powerdns.org.", 0, dns.rdataclass.IN, "TXT", "https://github.com/PowerDNS/pdns/pull/12825"
+        )
+        query = dns.message.make_query("dot-test-target.powerdns.org", "TXT", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         # As this test uses external servers, be a more generous wrt timeouts than the default 2.0s
@@ -137,21 +151,25 @@ recursor:
         self.assertRRsetInAnswer(res, expected)
         self.assertMatchingRRSIGInAnswer(res, expected)
 
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'get dot-outqueries']
+        rec_controlCmd = [
+            os.environ["RECCONTROL"],
+            "--config-dir=%s" % "configs/" + self._confdir,
+            "get dot-outqueries",
+        ]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
-            self.assertNotEqual(ret, b'UNKNOWN\n')
-            self.assertNotEqual(ret, b'0\n')
+            self.assertNotEqual(ret, b"UNKNOWN\n")
+            self.assertNotEqual(ret, b"0\n")
 
         except subprocess.CalledProcessError as e:
             print(e.output)
             raise
 
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'get tcp-outqueries']
+        rec_controlCmd = [
+            os.environ["RECCONTROL"],
+            "--config-dir=%s" % "configs/" + self._confdir,
+            "get tcp-outqueries",
+        ]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
             self.assertEqual(ret, tcpcount)
@@ -160,12 +178,13 @@ recursor:
             print(e.output)
             raise
 
+
 class DoTWithGNUTLSTest(RecursorTest):
     """
     This tests DoT to auth server with validation and is dependent on powerdns.com nameservers having DoT enabled.
     """
 
-    _confdir = 'DoTWithGNUTLS'
+    _confdir = "DoTWithGNUTLS"
     _config_template = """
 dnssec:
     validation: validate
@@ -189,17 +208,19 @@ recursor:
 
     @pytest.mark.external
     def testTXT(self):
-        query = dns.message.make_query('.', 'DNSKEY', want_dnssec=True)
+        query = dns.message.make_query(".", "DNSKEY", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         # As this test uses external servers, be more generous wrt timeouts than the default 2.0s
         res = self.sendUDPQuery(query, timeout=5.0)
 
         self.assertMessageIsAuthenticated(res)
-        self.assertRcodeEqual(res, 0);
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'get tcp-outqueries']
+        self.assertRcodeEqual(res, 0)
+        rec_controlCmd = [
+            os.environ["RECCONTROL"],
+            "--config-dir=%s" % "configs/" + self._confdir,
+            "get tcp-outqueries",
+        ]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
             tcpcount = ret
@@ -208,8 +229,10 @@ recursor:
             print(e.output)
             raise
 
-        expected = dns.rrset.from_text('dot-test-target.powerdns.org.', 0, dns.rdataclass.IN, 'TXT', 'https://github.com/PowerDNS/pdns/pull/12825')
-        query = dns.message.make_query('dot-test-target.powerdns.org', 'TXT', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "dot-test-target.powerdns.org.", 0, dns.rdataclass.IN, "TXT", "https://github.com/PowerDNS/pdns/pull/12825"
+        )
+        query = dns.message.make_query("dot-test-target.powerdns.org", "TXT", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         # As this test uses external servers, be a more generous wrt timeouts than the default 2.0s
@@ -219,21 +242,25 @@ recursor:
         self.assertRRsetInAnswer(res, expected)
         self.assertMatchingRRSIGInAnswer(res, expected)
 
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'get dot-outqueries']
+        rec_controlCmd = [
+            os.environ["RECCONTROL"],
+            "--config-dir=%s" % "configs/" + self._confdir,
+            "get dot-outqueries",
+        ]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
-            self.assertNotEqual(ret, b'UNKNOWN\n')
-            self.assertNotEqual(ret, b'0\n')
+            self.assertNotEqual(ret, b"UNKNOWN\n")
+            self.assertNotEqual(ret, b"0\n")
 
         except subprocess.CalledProcessError as e:
             print(e.output)
             raise
 
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'get tcp-outqueries']
+        rec_controlCmd = [
+            os.environ["RECCONTROL"],
+            "--config-dir=%s" % "configs/" + self._confdir,
+            "get tcp-outqueries",
+        ]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
             self.assertEqual(ret, tcpcount)
@@ -242,6 +269,7 @@ recursor:
             print(e.output)
             raise
 
+
 class DoTWithLocalResponderTests(RecursorTest):
     """
     This tests DoT to responder with validation"
@@ -249,9 +277,9 @@ class DoTWithLocalResponderTests(RecursorTest):
 
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
-    _tlsBackendPort = 853 # If binding to this port fails, add an empty !853 file to /etc/authbind/byport with execute permissons for you
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
+    _tlsBackendPort = 853  # If binding to this port fails, add an empty !853 file to /etc/authbind/byport with execute permissons for you
     _queueTimeout = 1
     _toResponderQueue = Queue()
     _fromResponderQueue = Queue()
@@ -263,7 +291,7 @@ class DoTWithLocalResponderTests(RecursorTest):
 
     @staticmethod
     def sniCallback(sslSocket, sni, sslContext):
-        assert(sni == 'tls.tests.powerdns.com')
+        assert sni == "tls.tests.powerdns.com"
         return None
 
     @classmethod
@@ -296,9 +324,9 @@ class DoTWithLocalResponderTests(RecursorTest):
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
-        tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.load_cert_chain("server.chain", "server.key")
         # requires Python 3.7+
-        if hasattr(tlsContext, 'sni_callback'):
+        if hasattr(tlsContext, "sni_callback"):
             tlsContext.sni_callback = cls.sniCallback
 
         if cls._clientCert:
@@ -308,7 +336,23 @@ class DoTWithLocalResponderTests(RecursorTest):
             tlsContext.load_verify_locations(cafile="ca.pem")
 
         print("Launching TLS responder..")
-        cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext, False, '127.0.0.1', False, cls._clientCert])
+        cls._TLSResponder = threading.Thread(
+            name="TLS Responder",
+            target=cls.TCPResponder,
+            args=[
+                cls._tlsBackendPort,
+                cls._toResponderQueue,
+                cls._fromResponderQueue,
+                False,
+                False,
+                None,
+                tlsContext,
+                False,
+                "127.0.0.1",
+                False,
+                cls._clientCert,
+            ],
+        )
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
 
@@ -317,25 +361,26 @@ class DoTWithLocalResponderTests(RecursorTest):
         cls._backgroundThreads[cls._TLSResponder.native_id] = False
         count = 0
         while count < 200 and len(cls._backgroundThreads) != 0:
-            print(f'Waiting for background responder thread to exit {count}...')
+            print(f"Waiting for background responder thread to exit {count}...")
             time.sleep(0.01)
             count = count + 1
 
     def checkOnlyTLSResponderHit(self, numberOfTLSQueries=1):
-        self.assertNotIn('UDP Responder', self._responsesCounter)
-        self.assertNotIn('TCP Responder', self._responsesCounter)
-        self.assertEqual(self._responsesCounter['TLS Responder'], numberOfTLSQueries)
+        self.assertNotIn("UDP Responder", self._responsesCounter)
+        self.assertNotIn("TCP Responder", self._responsesCounter)
+        self.assertEqual(self._responsesCounter["TLS Responder"], numberOfTLSQueries)
+
 
 class DoTOKOpenSSLTest(DoTWithLocalResponderTests):
     """
     This tests DoT to responder with openssl validation using a proper CA store for the locally generated cert
     """
 
-    _confdir = 'DoTOKOpenSSL'
+    _confdir = "DoTOKOpenSSL"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 dnssec:
     validation: off
@@ -369,19 +414,15 @@ webservice:
         """
         Outgoing TLS: UDP query is sent via TLS
         """
-        name = 'udp.outgoing-tls.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.outgoing-tls.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query, True)
-        rrset = dns.rrset.from_text(name,
-                                    15,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 15, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         currentCount = 0
-        if 'TLS Responder' in self._responsesCounter:
-            currentCount = self._responsesCounter['TLS Responder']
+        if "TLS Responder" in self._responsesCounter:
+            currentCount = self._responsesCounter["TLS Responder"]
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
         receivedQuery.id = query.id
         self.assertEqual(query, receivedQuery)
@@ -389,20 +430,19 @@ webservice:
 
         # there was one TCP query
         self.checkOnlyTLSResponderHit(currentCount + 1)
-        self.checkMetrics({
-            'dot-outqueries': 1
-        })
+        self.checkMetrics({"dot-outqueries": 1})
+
 
 class DoTOKWithClientCertPEMTest(DoTWithLocalResponderTests):
     """
     This tests DoT to responder with openssl validation using a proper CA store for the locally generated cert
     """
 
-    _confdir = 'DoTOKWithClientCertPEM'
+    _confdir = "DoTOKWithClientCertPEM"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _clientCert = True
     _config_template = """
 dnssec:
@@ -439,19 +479,15 @@ webservice:
         """
         Outgoing TLS: UDP query is sent via TLS
         """
-        name = 'udp.outgoing-tls.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.outgoing-tls.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query, True)
-        rrset = dns.rrset.from_text(name,
-                                    15,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 15, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         currentCount = 0
-        if 'TLS Responder' in self._responsesCounter:
-            currentCount = self._responsesCounter['TLS Responder']
+        if "TLS Responder" in self._responsesCounter:
+            currentCount = self._responsesCounter["TLS Responder"]
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
         receivedQuery.id = query.id
         self.assertEqual(query, receivedQuery)
@@ -459,20 +495,19 @@ webservice:
 
         # there was one TCP query
         self.checkOnlyTLSResponderHit(currentCount + 1)
-        self.checkMetrics({
-            'dot-outqueries': 1
-        })
+        self.checkMetrics({"dot-outqueries": 1})
+
 
 class DoTOKWithClientCertPKCS12Test(DoTWithLocalResponderTests):
     """
     This tests DoT to responder with openssl validation using a proper CA store for the locally generated cert
     """
 
-    _confdir = 'DoTOKWithClientCertPKCS12'
+    _confdir = "DoTOKWithClientCertPKCS12"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _clientCert = True
     _config_template = """
 dnssec:
@@ -509,19 +544,15 @@ webservice:
         """
         Outgoing TLS: UDP query is sent via TLS
         """
-        name = 'udp.outgoing-tls.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.outgoing-tls.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query, True)
-        rrset = dns.rrset.from_text(name,
-                                    15,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 15, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         currentCount = 0
-        if 'TLS Responder' in self._responsesCounter:
-            currentCount = self._responsesCounter['TLS Responder']
+        if "TLS Responder" in self._responsesCounter:
+            currentCount = self._responsesCounter["TLS Responder"]
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
         receivedQuery.id = query.id
         self.assertEqual(query, receivedQuery)
@@ -529,20 +560,19 @@ webservice:
 
         # there was one TCP query
         self.checkOnlyTLSResponderHit(currentCount + 1)
-        self.checkMetrics({
-            'dot-outqueries': 1
-        })
-        
+        self.checkMetrics({"dot-outqueries": 1})
+
+
 class DoTOKGnuTLSTest(DoTWithLocalResponderTests):
     """
     This tests DoT to responder with gnutls validation using a proper CA store for the locally generated cert
     """
 
-    _confdir = 'DoTOKGnuTLS'
+    _confdir = "DoTOKGnuTLS"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 dnssec:
     validation: off
@@ -577,19 +607,15 @@ webservice:
         """
         Outgoing TLS: UDP query is sent via TLS
         """
-        name = 'udp.outgoing-tls.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.outgoing-tls.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query, True)
-        rrset = dns.rrset.from_text(name,
-                                    15,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 15, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         currentCount = 0
-        if 'TLS Responder' in self._responsesCounter:
-            currentCount = self._responsesCounter['TLS Responder'] 
+        if "TLS Responder" in self._responsesCounter:
+            currentCount = self._responsesCounter["TLS Responder"]
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
         receivedQuery.id = query.id
         self.assertEqual(query, receivedQuery)
@@ -597,20 +623,19 @@ webservice:
 
         # there was one TCP query
         self.checkOnlyTLSResponderHit(currentCount + 1)
-        self.checkMetrics({
-            'dot-outqueries': 1
-        })
+        self.checkMetrics({"dot-outqueries": 1})
+
 
 class DoTNOKOpenSSLTest(DoTWithLocalResponderTests):
     """
     This tests DoT to responder with openssl validation using a missing CA store for the locally generated cert
     """
 
-    _confdir = 'DoTNOKOpenSSL'
+    _confdir = "DoTNOKOpenSSL"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 dnssec:
     validation: off
@@ -643,28 +668,22 @@ webservice:
         """
         Outgoing TLS: UDP query is sent via TLS
         """
-        name = 'udp.outgoing-tls.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.outgoing-tls.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query, True)
-        rrset = dns.rrset.from_text(name,
-                                    15,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 15, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         currentCount = 0
-        if 'TLS Responder' in self._responsesCounter:
-            currentCount = self._responsesCounter['TLS Responder']
+        if "TLS Responder" in self._responsesCounter:
+            currentCount = self._responsesCounter["TLS Responder"]
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
 
         self.assertRcodeEqual(receivedResponse, dns.rcode.SERVFAIL)
 
         # there was no successful DoT query
         self.checkOnlyTLSResponderHit(currentCount)
-        self.checkMetrics({
-            'dot-outqueries': 1
-        })
+        self.checkMetrics({"dot-outqueries": 1})
 
 
 class DoTNOKGnuTLSTest(DoTWithLocalResponderTests):
@@ -672,11 +691,11 @@ class DoTNOKGnuTLSTest(DoTWithLocalResponderTests):
     This tests DoT to responder with gnutls validation using a missing CA store for the locally generated cert
     """
 
-    _confdir = 'DoTNOKGnuTLS'
+    _confdir = "DoTNOKGnuTLS"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 dnssec:
     validation: off
@@ -710,26 +729,19 @@ webservice:
         """
         Outgoing TLS: UDP query is sent via TLS
         """
-        name = 'udp.outgoing-tls.test.powerdns.com.'
-        query = dns.message.make_query(name, 'A', 'IN')
+        name = "udp.outgoing-tls.test.powerdns.com."
+        query = dns.message.make_query(name, "A", "IN")
         expectedResponse = dns.message.make_response(query, True)
-        rrset = dns.rrset.from_text(name,
-                                    15,
-                                    dns.rdataclass.IN,
-                                    dns.rdatatype.A,
-                                    '127.0.0.1')
+        rrset = dns.rrset.from_text(name, 15, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1")
         expectedResponse.answer.append(rrset)
 
         currentCount = 0
-        if 'TLS Responder' in self._responsesCounter:
-            currentCount = self._responsesCounter['TLS Responder']
+        if "TLS Responder" in self._responsesCounter:
+            currentCount = self._responsesCounter["TLS Responder"]
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
 
         self.assertRcodeEqual(receivedResponse, dns.rcode.SERVFAIL)
 
         # there was no succesful DoT query
         self.checkOnlyTLSResponderHit(currentCount)
-        self.checkMetrics({
-            'dot-outqueries': 1
-        })
-
+        self.checkMetrics({"dot-outqueries": 1})
index f5b07b6efe8482cf7c44a65b33d91c7bd4317ed7..3872b2d406cd5e1404e5d1d60b72370f139fa530 100644 (file)
@@ -12,14 +12,15 @@ from twisted.internet.protocol import Protocol
 from twisted.internet.protocol import DatagramProtocol
 from twisted.internet import reactor
 
-emptyECSText = 'No ECS received'
-mismatchedECSText = 'Mismatched ECS'
-nameECS = 'ecs-echo.example.'
-nameECSInvalidScope = 'invalid-scope.ecs-echo.example.'
+emptyECSText = "No ECS received"
+mismatchedECSText = "Mismatched ECS"
+nameECS = "ecs-echo.example."
+nameECSInvalidScope = "invalid-scope.ecs-echo.example."
 ttlECS = 60
 ecsReactorRunning = False
 ecsReactorv6Running = False
 
+
 class ECSTest(RecursorTest):
     _config_template_default = """
 daemon=no
@@ -84,7 +85,7 @@ ecs-add-for=0.0.0.0/0
         global ecsReactorv6Running
         print("Launching responders..")
 
-        address = cls._PREFIX + '.21'
+        address = cls._PREFIX + ".21"
         port = 53
 
         if not ecsReactorRunning:
@@ -93,53 +94,56 @@ ecs-add-for=0.0.0.0/0
             ecsReactorRunning = True
 
         if not ecsReactorv6Running and have_ipv6():
-            reactor.listenUDP(53000, UDPECSResponder(), interface='::1')
-            reactor.listenTCP(53000, TCPECSFactory(), interface='::1')
+            reactor.listenUDP(53000, UDPECSResponder(), interface="::1")
+            reactor.listenTCP(53000, TCPECSFactory(), interface="::1")
             ecsReactorv6Running = True
 
         cls.startReactor()
 
+
 class NoECSTest(ECSTest):
-    _confdir = 'NoECS'
+    _confdir = "NoECS"
 
     _config_template = """edns-subnet-allow-list=
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        query = dns.message.make_query(nameECS, 'TXT')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
 
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
+
 class NoECSHardenedTest(NoECSTest):
-    _confdir = 'NoECSHardened'
+    _confdir = "NoECSHardened"
 
     _config_template = """
 edns-subnet-harden=yes
 edns-subnet-allow-list=
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
+
 
 class NoECSInAnswerTest(ECSTest):
-    _confdir = 'NoECSInAnswer'
+    _confdir = "NoECSInAnswer"
 
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """edns-subnet-allow-list=xecs-echo.example
 forward-zones=xecs-echo.example=%s.21
 webserver=yes
@@ -148,42 +152,37 @@ webserver-address=127.0.0.1
 webserver-password=%s
 webserver-allow-from=127.0.0.1
 api-key=%s
-    """ % (os.environ['PREFIX'], _wsPort, _wsPassword, _apiKey)
+    """ % (os.environ["PREFIX"], _wsPort, _wsPassword, _apiKey)
 
     def test1SendECS(self):
-        expected = dns.rrset.from_text('x'+ nameECS, ttlECS, dns.rdataclass.IN, 'TXT', 'X')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query('x' + nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text("x" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", "X")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query("x" + nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
-        self.checkMetrics({
-            'ecs-missing': 0
-        })
+        self.checkMetrics({"ecs-missing": 0})
 
     def test2NoECS(self):
-        expected = dns.rrset.from_text('x' + nameECS, ttlECS, dns.rdataclass.IN, 'TXT', 'X')
-        query = dns.message.make_query('x' + nameECS, 'TXT')
+        expected = dns.rrset.from_text("x" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", "X")
+        query = dns.message.make_query("x" + nameECS, "TXT")
         self.sendECSQuery(query, expected)
-        self.checkMetrics({
-            'ecs-missing': 0
-        })
+        self.checkMetrics({"ecs-missing": 0})
 
     def test3RequireNoECS(self):
-        expected = dns.rrset.from_text('x' + nameECS, ttlECS, dns.rdataclass.IN, 'TXT', 'X')
+        expected = dns.rrset.from_text("x" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", "X")
 
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query('x' + nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query("x" + nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
-        self.checkMetrics({
-            'ecs-missing': 0
-        })
+        self.checkMetrics({"ecs-missing": 0})
+
 
 class NoECSInAnswerHardenedTest(NoECSInAnswerTest):
-    _confdir = 'NoECSInAnswerHardened'
+    _confdir = "NoECSInAnswerHardened"
 
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 edns-subnet-harden=yes
 edns-subnet-allow-list=xecs-echo.example
@@ -194,192 +193,193 @@ webserver-address=127.0.0.1
 webserver-password=%s
 webserver-allow-from=127.0.0.1
 api-key=%s
-    """ % (os.environ['PREFIX'], _wsPort, _wsPassword, _apiKey)
+    """ % (os.environ["PREFIX"], _wsPort, _wsPassword, _apiKey)
 
     # All test below have ecs-missing count to be 1, as they result in a non ecs scoped answer in the cache
     def test1SendECS(self):
-        expected = dns.rrset.from_text('x'+ nameECS, ttlECS, dns.rdataclass.IN, 'TXT', 'X')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query('x' + nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text("x" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", "X")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query("x" + nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
-        self.checkMetrics({
-            'ecs-missing': 1
-        })
+        self.checkMetrics({"ecs-missing": 1})
 
     def test2NoECS(self):
-        expected = dns.rrset.from_text('x' + nameECS, ttlECS, dns.rdataclass.IN, 'TXT', 'X')
-        query = dns.message.make_query('x' + nameECS, 'TXT')
+        expected = dns.rrset.from_text("x" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", "X")
+        query = dns.message.make_query("x" + nameECS, "TXT")
         self.sendECSQuery(query, expected)
-        self.checkMetrics({
-            'ecs-missing': 1
-        })
+        self.checkMetrics({"ecs-missing": 1})
 
     def test3RequireNoECS(self):
-        expected = dns.rrset.from_text('x' + nameECS, ttlECS, dns.rdataclass.IN, 'TXT', 'X')
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query('x' + nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text("x" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", "X")
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query("x" + nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
-        self.checkMetrics({
-            'ecs-missing': 1
-        })
+        self.checkMetrics({"ecs-missing": 1})
+
 
 class MismatchedECSInAnswerTest(ECSTest):
-    _confdir = 'MismatchedECSInAnswer'
+    _confdir = "MismatchedECSInAnswer"
 
     _config_template = """edns-subnet-allow-list=mecs-echo.example
 forward-zones=mecs-echo.example=%s.21
 dont-throttle-netmasks=0.0.0.0/0
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def test1SendECS(self):
-        expected = dns.rrset.from_text('m'+ nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query('m' + nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text("m" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query("m" + nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def test2NoECS(self):
-        expected = dns.rrset.from_text('m' + nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        query = dns.message.make_query('m' + nameECS, 'TXT')
+        expected = dns.rrset.from_text("m" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        query = dns.message.make_query("m" + nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def test3RequireNoECS(self):
-        expected = dns.rrset.from_text('m' + nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query('m' + nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text("m" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query("m" + nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
+
 class MismatchedECSInAnswerHardenedTest(MismatchedECSInAnswerTest):
-    _confdir = 'MismatchedECSInAnswerHardened'
+    _confdir = "MismatchedECSInAnswerHardened"
 
     _config_template = """
 edns-subnet-harden=yes
 edns-subnet-allow-list=mecs-echo.example
 forward-zones=mecs-echo.example=%s.21
 dont-throttle-netmasks=0.0.0.0/0
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def test1SendECS(self):
-        expected = dns.rrset.from_text('m'+ nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query('m' + nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text("m" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query("m" + nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def test2NoECS(self):
-        expected = dns.rrset.from_text('m' + nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        query = dns.message.make_query('m' + nameECS, 'TXT')
+        expected = dns.rrset.from_text("m" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        query = dns.message.make_query("m" + nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def test3RequireNoECS(self):
-        expected = dns.rrset.from_text('m' + nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query('m' + nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text("m" + nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query("m" + nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
+
 class IncomingNoECSTest(ECSTest):
-    _confdir = 'IncomingNoECS'
+    _confdir = "IncomingNoECS"
 
     _config_template = """edns-subnet-allow-list=
 use-incoming-edns-subnet=yes
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
 
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, scopeZeroResponse=True)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
 
-        query = dns.message.make_query(nameECS, 'TXT')
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
 
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, scopeZeroResponse=True)
 
+
 class IncomingNoECSHardenedTest(IncomingNoECSTest):
-    _confdir = 'IncomingNoECSHardened'
+    _confdir = "IncomingNoECSHardened"
 
     _config_template = """
 edns-subnet-harden=yes
 edns-subnet-allow-list=
 use-incoming-edns-subnet=yes
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
+
 
 class ECSByNameTest(ECSTest):
-    _confdir = 'ECSByName'
+    _confdir = "ECSByName"
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
         # check that a query in a different ECS range is a hit, because we don't use the incoming ECS
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.2", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.checkECSQueryHit(query, expected)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
-        query = dns.message.make_query(nameECS, 'TXT')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
 
         # the request for no ECS is ignored because use-incoming-edns-subnet is not set
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
+
 class ECSByNameLargerTest(ECSTest):
-    _confdir = 'ECSByNameLarger'
+    _confdir = "ECSByNameLarger"
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 ecs-ipv4-bits=32
 forward-zones=ecs-echo.example=%s.21
 ecs-ipv4-cache-bits=32
 ecs-ipv6-cache-bits=128
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.1/32')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.1/32")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
         # check that a query in a different range is a miss
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.2", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.1/32')
-        query = dns.message.make_query(nameECS, 'TXT')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.1/32")
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.1/32')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.1/32")
 
         # the request for no ECS is ignored because use-incoming-edns-subnet is not set
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
+
 class ECSByNameLargerHardenedTest(ECSByNameLargerTest):
-    _confdir = 'ECSByNameLargerHardened'
+    _confdir = "ECSByNameLargerHardened"
 
     _config_template = """
 edns-subnet-harden=yes
@@ -388,47 +388,50 @@ ecs-ipv4-bits=32
 forward-zones=ecs-echo.example=%s.21
 ecs-ipv4-cache-bits=32
 ecs-ipv6-cache-bits=128
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
+
 
 class ECSByNameSmallerTest(ECSTest):
-    _confdir = 'ECSByNameSmaller'
+    _confdir = "ECSByNameSmaller"
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 ecs-ipv4-bits=16
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/16')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/16")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/16')
-        query = dns.message.make_query(nameECS, 'TXT')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/16")
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/16')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/16")
 
         # the request for no ECS is ignored because use-incoming-edns-subnet is not set
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
+
 class ECSByNameSmallerHardenedTest(ECSByNameSmallerTest):
-    _confdir = 'ECSByNameSmallerHardened'
+    _confdir = "ECSByNameSmallerHardened"
 
     _config_template = """
 edns-subnet-harden=yes
 edns-subnet-allow-list=ecs-echo.example.
 ecs-ipv4-bits=16
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
+
 
 class IncomingECSByNameTest(ECSTest):
-    _confdir = 'IncomingECSByName'
+    _confdir = "IncomingECSByName"
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 use-incoming-edns-subnet=yes
@@ -436,39 +439,40 @@ forward-zones=ecs-echo.example=%s.21
 ecs-scope-zero-address=2001:db8::42
 ecs-ipv4-cache-bits=32
 ecs-ipv6-cache-bits=128
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.0.2.0/24')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.0.2.0/24")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
         # check that a query in the same ECS range is a hit
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.2", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.checkECSQueryHit(query, expected)
 
         # check that a query in a different ECS range is a miss
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.1.2.0/24')
-        ecso = clientsubnetoption.ClientSubnetOption('192.1.2.2', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.1.2.0/24")
+        ecso = clientsubnetoption.ClientSubnetOption("192.1.2.2", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
-        query = dns.message.make_query(nameECS, 'TXT')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected, ttlECS)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', "2001:db8::42/128")
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "2001:db8::42/128")
 
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
+
 class IncomingECSByNameHardenedTest(IncomingECSByNameTest):
-    _confdir = 'IncomingECSByNameHardened'
+    _confdir = "IncomingECSByNameHardened"
 
     _config_template = """
 edns-subnet-harden=yes
@@ -478,10 +482,11 @@ forward-zones=ecs-echo.example=%s.21
 ecs-scope-zero-address=2001:db8::42
 ecs-ipv4-cache-bits=32
 ecs-ipv6-cache-bits=128
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
+
 
 class IncomingECSByNameLargerTest(ECSTest):
-    _confdir = 'IncomingECSByNameLarger'
+    _confdir = "IncomingECSByNameLarger"
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 use-incoming-edns-subnet=yes
@@ -490,30 +495,31 @@ forward-zones=ecs-echo.example=%s.21
 ecs-scope-zero-address=192.168.0.1
 ecs-ipv4-cache-bits=32
 ecs-ipv6-cache-bits=128
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.0.2.1/32')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.0.2.1/32")
 
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.1/32')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.1/32")
 
-        query = dns.message.make_query(nameECS, 'TXT')
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected, ttlECS)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.168.0.1/32')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.168.0.1/32")
 
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
+
 class IncomingECSByNameLargerHardenedTest(IncomingECSByNameLargerTest):
-    _confdir = 'IncomingECSByNameLargerHardened'
+    _confdir = "IncomingECSByNameLargerHardened"
 
     _config_template = """
 edns-subnet-harden=yes
@@ -524,10 +530,11 @@ forward-zones=ecs-echo.example=%s.21
 ecs-scope-zero-address=192.168.0.1
 ecs-ipv4-cache-bits=32
 ecs-ipv6-cache-bits=128
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
+
 
 class IncomingECSByNameSmallerTest(ECSTest):
-    _confdir = 'IncomingECSByNameSmaller'
+    _confdir = "IncomingECSByNameSmaller"
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 use-incoming-edns-subnet=yes
@@ -536,28 +543,29 @@ forward-zones=ecs-echo.example=%s.21
 ecs-scope-zero-address=192.168.0.1
 ecs-ipv4-cache-bits=32
 ecs-ipv6-cache-bits=128
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.0.0.0/16')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.0.0.0/16")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/16')
-        query = dns.message.make_query(nameECS, 'TXT')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/16")
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.168.0.1/32')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.168.0.1/32")
 
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
+
 class IncomingECSByNameSmallerHardenedTest(IncomingECSByNameSmallerTest):
-    _confdir = 'IncomingECSByNameSmallerHardened'
+    _confdir = "IncomingECSByNameSmallerHardened"
 
     _config_template = """
 edns-subnet-harden=yes
@@ -568,11 +576,12 @@ forward-zones=ecs-echo.example=%s.21
 ecs-scope-zero-address=192.168.0.1
 ecs-ipv4-cache-bits=32
 ecs-ipv6-cache-bits=128
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
+
 
 @unittest.skipIf(not have_ipv6(), "No IPv6")
 class IncomingECSByNameV6Test(ECSTest):
-    _confdir = 'IncomingECSByNameV6'
+    _confdir = "IncomingECSByNameV6"
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 use-incoming-edns-subnet=yes
@@ -584,54 +593,56 @@ forward-zones=ecs-echo.example=[::1]:53000
     """
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '2001:db8::1/128')
-        ecso = clientsubnetoption.ClientSubnetOption('2001:db8::1', 128)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "2001:db8::1/128")
+        ecso = clientsubnetoption.ClientSubnetOption("2001:db8::1", 128)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
 
-        query = dns.message.make_query(nameECS, 'TXT')
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendUDPQuery(query)
         self.sendECSQuery(query, expected, ttlECS)
 
     def testRequireNoECS(self):
         # we should get ::1/128 because ecs-scope-zero-addr is unset and query-local-address is set to ::1
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', "::1/128")
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "::1/128")
 
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
+
 class ECSNameMismatchTest(ECSTest):
-    _confdir = 'ECSNameMismatch'
+    _confdir = "ECSNameMismatch"
 
     _config_template = """edns-subnet-allow-list=not-the-right-name.example.
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        query = dns.message.make_query(nameECS, 'TXT')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
 
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
+
 @unittest.skipIf(not have_ipv6(), "No IPv6")
 class IncomingECSByNameV6HardenedTest(IncomingECSByNameV6Test):
-    _confdir = 'IncomingECSByNameV6Hardened'
+    _confdir = "IncomingECSByNameV6Hardened"
 
     _config_template = """
 edns-subnet-harden=yes
@@ -644,43 +655,46 @@ query-local-address=::1
 forward-zones=ecs-echo.example=[::1]:53000
     """
 
+
 class ECSByIPTest(ECSTest):
-    _confdir = 'ECSByIP'
+    _confdir = "ECSByIP"
 
     _config_template = """edns-subnet-allow-list=%s.21
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'], os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"], os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
-        query = dns.message.make_query(nameECS, 'TXT')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
 
         # the request for no ECS is ignored because use-incoming-edns-subnet is not set
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
+
 class ECSByIPHardenedTest(ECSByIPTest):
-    _confdir = 'ECSByIPHardened'
+    _confdir = "ECSByIPHardened"
 
     _config_template = """
 edns-subnet-harden=yes
 edns-subnet-allow-list=%s.21
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'], os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"], os.environ["PREFIX"])
+
 
 class IncomingECSByIPTest(ECSTest):
-    _confdir = 'IncomingECSByIP'
+    _confdir = "IncomingECSByIP"
 
     _config_template = """edns-subnet-allow-list=%s.21
 use-incoming-edns-subnet=yes
@@ -688,39 +702,40 @@ forward-zones=ecs-echo.example=%s.21
 ecs-scope-zero-address=::1
 ecs-ipv4-cache-bits=32
 ecs-ipv6-cache-bits=128
-    """ % (os.environ['PREFIX'], os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"], os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.0.2.0/24')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.0.2.0/24")
 
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
-        query = dns.message.make_query(nameECS, 'TXT')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendECSQuery(query, expected)
 
     def testRequireNoECS(self):
         # we will get ::1 because ecs-scope-zero-addr is set to ::1
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '::1/128')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "::1/128")
 
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
     def testSendECSInvalidScope(self):
         # test that the recursor does not cache with a more specific scope than the source it sent
-        expected = dns.rrset.from_text(nameECSInvalidScope, ttlECS, dns.rdataclass.IN, 'TXT', '192.0.2.0/24/25')
+        expected = dns.rrset.from_text(nameECSInvalidScope, ttlECS, dns.rdataclass.IN, "TXT", "192.0.2.0/24/25")
 
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
-        query = dns.message.make_query(nameECSInvalidScope, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 24)
+        query = dns.message.make_query(nameECSInvalidScope, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
 
         self.sendECSQuery(query, expected)
 
+
 class IncomingECSByIPHardenedTest(IncomingECSByIPTest):
-    _confdir = 'IncomingECSByIPHardened'
+    _confdir = "IncomingECSByIPHardened"
 
     _config_template = """
 edns-subnet-harden=yes
@@ -730,66 +745,70 @@ forward-zones=ecs-echo.example=%s.21
 ecs-scope-zero-address=::1
 ecs-ipv4-cache-bits=32
 ecs-ipv6-cache-bits=128
-    """ % (os.environ['PREFIX'], os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"], os.environ["PREFIX"])
+
 
 class ECSIPMismatchTest(ECSTest):
-    _confdir = 'ECSIPMismatch'
+    _confdir = "ECSIPMismatch"
 
     _config_template = """edns-subnet-allow-list=192.0.2.1
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
 
     def testSendECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
     def testNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
-        query = dns.message.make_query(nameECS, 'TXT')
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
+        query = dns.message.make_query(nameECS, "TXT")
         self.sendUDPQuery(query)
         self.sendECSQuery(query, expected)
 
     def testRequireNoECS(self):
-        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', emptyECSText)
+        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", emptyECSText)
 
-        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("0.0.0.0", 0)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
+
 class ECSIPMismatchHardenedTest(ECSIPMismatchTest):
-    _confdir = 'ECSIPMismatchHardened'
+    _confdir = "ECSIPMismatchHardened"
 
     _config_template = """
 edns-subnet-harden=yes
 edns-subnet-allow-list=192.0.2.1
 forward-zones=ecs-echo.example=%s.21
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
+
 
 class ECSWithProxyProtocolRecursorTest(ECSTest):
-    _confdir = 'ECSWithProxyProtocolRecursor'
+    _confdir = "ECSWithProxyProtocolRecursor"
     _config_template = """
     ecs-add-for=2001:db8::1/128
     edns-subnet-allow-list=ecs-echo.example.
     forward-zones=ecs-echo.example=%s.21
     proxy-protocol-from=127.0.0.1/32
     allow-from=2001:db8::1/128
-""" % (os.environ['PREFIX'])
+""" % (os.environ["PREFIX"])
 
     def testProxyProtocolPlusECS(self):
         qname = nameECS
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'TXT', '2001:db8::/56')
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "TXT", "2001:db8::/56")
 
-        query = dns.message.make_query(qname, 'TXT', use_edns=True)
+        query = dns.message.make_query(qname, "TXT", use_edns=True)
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, True, '2001:db8::1', '2001:db8::2', 0, 65535)
+            res = sender(query, True, "2001:db8::1", "2001:db8::2", 0, 65535)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertRRsetInAnswer(res, expected)
 
+
 class ECSWithProxyProtocolRecursorHardenedTest(ECSWithProxyProtocolRecursorTest):
-    _confdir = 'ECSWithProxyProtocolRecursorHardened'
+    _confdir = "ECSWithProxyProtocolRecursorHardened"
     _config_template = """
     edns-subnet-harden=yes
     ecs-add-for=2001:db8::1/128
@@ -797,11 +816,11 @@ class ECSWithProxyProtocolRecursorHardenedTest(ECSWithProxyProtocolRecursorTest)
     forward-zones=ecs-echo.example=%s.21
     proxy-protocol-from=127.0.0.1/32
     allow-from=2001:db8::1/128
-""" % (os.environ['PREFIX'])
+""" % (os.environ["PREFIX"])
 
-class TooLargeToAddZeroScopeTest(RecursorTest):
 
-    _confdir = 'TooLargeToAddZeroScope'
+class TooLargeToAddZeroScopeTest(RecursorTest):
+    _confdir = "TooLargeToAddZeroScope"
     _config_template = """
 use-incoming-edns-subnet=yes
 dnssec=validate
@@ -814,19 +833,18 @@ dnssec=validate
       end
       return false
     end
-    """ % ('A'*447)
+    """ % ("A" * 447)
 
     _roothints = None
 
-
     @classmethod
     def generateRecursorConfig(cls, confdir):
         super(TooLargeToAddZeroScopeTest, cls).generateRecursorConfig(confdir)
 
     def testTooLarge(self):
-        qname = 'toolarge.ecs.'
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
-        query = dns.message.make_query(qname, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        qname = "toolarge.ecs."
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 24)
+        query = dns.message.make_query(qname, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
 
         # should not have an ECS Option since the packet is too large already
         res = self.sendUDPQuery(query, timeout=5.0)
@@ -843,16 +861,14 @@ dnssec=validate
         self.assertEqual(res.options[0].otype, 8)
         self.assertEqual(res.options[0].scope, 0)
 
+
 class UDPECSResponder(DatagramProtocol):
     @staticmethod
     def ipToStr(option):
         if option.family == clientsubnetoption.FAMILY_IPV4:
-            ip = socket.inet_ntop(socket.AF_INET, struct.pack('!L', option.ip))
+            ip = socket.inet_ntop(socket.AF_INET, struct.pack("!L", option.ip))
         elif option.family == clientsubnetoption.FAMILY_IPV6:
-            ip = socket.inet_ntop(socket.AF_INET6,
-                                  struct.pack('!QQ',
-                                              option.ip >> 64,
-                                              option.ip & (2 ** 64 - 1)))
+            ip = socket.inet_ntop(socket.AF_INET6, struct.pack("!QQ", option.ip >> 64, option.ip & (2**64 - 1)))
         return ip
 
     def question(self, datagram, tcp=False):
@@ -862,12 +878,16 @@ class UDPECSResponder(DatagramProtocol):
         response.flags |= dns.flags.AA
         ecso = None
 
-        if (request.question[0].name == dns.name.from_text(nameECS) or request.question[0].name == dns.name.from_text(nameECSInvalidScope)) and request.question[0].rdtype == dns.rdatatype.TXT:
-
+        if (
+            request.question[0].name == dns.name.from_text(nameECS)
+            or request.question[0].name == dns.name.from_text(nameECSInvalidScope)
+        ) and request.question[0].rdtype == dns.rdatatype.TXT:
             text = emptyECSText
             for option in request.options:
-                if option.otype == clientsubnetoption.ASSIGNED_OPTION_CODE and isinstance(option, clientsubnetoption.ClientSubnetOption):
-                    text = self.ipToStr(option) + '/' + str(option.mask)
+                if option.otype == clientsubnetoption.ASSIGNED_OPTION_CODE and isinstance(
+                    option, clientsubnetoption.ClientSubnetOption
+                ):
+                    text = self.ipToStr(option) + "/" + str(option.mask)
 
                     # Send a scope more specific than the received source for nameECSInvalidScope
                     if request.question[0].name == dns.name.from_text(nameECSInvalidScope):
@@ -876,33 +896,37 @@ class UDPECSResponder(DatagramProtocol):
                     else:
                         ecso = clientsubnetoption.ClientSubnetOption(self.ipToStr(option), option.mask, option.mask)
 
-            answer = dns.rrset.from_text(request.question[0].name, ttlECS, dns.rdataclass.IN, 'TXT', text)
+            answer = dns.rrset.from_text(request.question[0].name, ttlECS, dns.rdataclass.IN, "TXT", text)
             response.answer.append(answer)
 
         elif request.question[0].name == dns.name.from_text(nameECS) and request.question[0].rdtype == dns.rdatatype.NS:
-            answer = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'NS', 'ns1.ecs-echo.example.')
+            answer = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "NS", "ns1.ecs-echo.example.")
             response.answer.append(answer)
-            additional = dns.rrset.from_text('ns1.ecs-echo.example.', 15, dns.rdataclass.IN, 'A', os.environ['PREFIX'] + '.21')
+            additional = dns.rrset.from_text(
+                "ns1.ecs-echo.example.", 15, dns.rdataclass.IN, "A", os.environ["PREFIX"] + ".21"
+            )
             response.additional.append(additional)
 
-        elif request.question[0].name == dns.name.from_text('x' + nameECS):
-            answer = dns.rrset.from_text(request.question[0].name, ttlECS, dns.rdataclass.IN, 'TXT', 'X')
+        elif request.question[0].name == dns.name.from_text("x" + nameECS):
+            answer = dns.rrset.from_text(request.question[0].name, ttlECS, dns.rdataclass.IN, "TXT", "X")
             response.answer.append(answer)
-        elif request.question[0].name == dns.name.from_text('m' + nameECS):
+        elif request.question[0].name == dns.name.from_text("m" + nameECS):
             incomingECS = False
             for option in request.options:
-                if option.otype == clientsubnetoption.ASSIGNED_OPTION_CODE and isinstance(option, clientsubnetoption.ClientSubnetOption):
+                if option.otype == clientsubnetoption.ASSIGNED_OPTION_CODE and isinstance(
+                    option, clientsubnetoption.ClientSubnetOption
+                ):
                     incomingECS = True
             # Send mismatched ECS over UDP
             flag = emptyECSText
             if not tcp and incomingECS:
                 ecso = clientsubnetoption.ClientSubnetOption("193.0.2.1", 24, 25)
                 flag = mismatchedECSText
-            answer = dns.rrset.from_text(request.question[0].name, ttlECS, dns.rdataclass.IN, 'TXT', flag)
+            answer = dns.rrset.from_text(request.question[0].name, ttlECS, dns.rdataclass.IN, "TXT", flag)
             response.answer.append(answer)
 
         if ecso:
-            response.use_edns(options = [ecso])
+            response.use_edns(options=[ecso])
 
         return response.to_wire()
 
@@ -910,14 +934,16 @@ class UDPECSResponder(DatagramProtocol):
         response = self.question(datagram)
         self.transport.write(response, address)
 
+
 class TCPECSResponder(Protocol):
     def dataReceived(self, data):
         handler = UDPECSResponder()
         response = handler.question(data[2:], True)
         length = len(response)
-        header = length.to_bytes(2, 'big')
+        header = length.to_bytes(2, "big")
         self.transport.write(header + response)
 
+
 class TCPECSFactory(Factory):
     def buildProtocol(self, addr):
         return TCPECSResponder()
index 79a48c48640cdd511de8839032a4cb76661a4e15..1163abf07009a8deb3a97e15a3f839bdfa9e17b6 100644 (file)
@@ -6,21 +6,22 @@ from recursortests import RecursorTest
 
 ednsBufferReactorRunning = False
 
+
 class EDNSTest(RecursorTest):
     """
     These tests are designed to check if we respond correctly to EDNS queries
     from clients. Note that buffer-size tests go into test_EDNSBufferSize
     """
-    _confdir = 'EDNS'
+
+    _confdir = "EDNS"
 
     def testEDNSUnknownOpt(self):
         """
         Ensure the recursor does not reply with an unknown option when one is
         sent in the query
         """
-        unknownOpt = dns.edns.GenericOption(65005, b'1234567890')
-        query = dns.message.make_query('version.bind.', 'TXT', 'CH', use_edns=0,
-                                       payload=4096, options=[unknownOpt])
+        unknownOpt = dns.edns.GenericOption(65005, b"1234567890")
+        query = dns.message.make_query("version.bind.", "TXT", "CH", use_edns=0, payload=4096, options=[unknownOpt])
         response = self.sendUDPQuery(query)
         self.assertRcodeEqual(response, dns.rcode.NOERROR)
         self.assertEqual(response.options, ())
@@ -32,8 +33,7 @@ class EDNSTest(RecursorTest):
         """
         if sys.version_info >= (3, 11) and sys.version_info <= (3, 11, 3):
             raise unitest.SkipTest("Test skipped, see https://github.com/PowerDNS/pdns/pull/12912")
-        query = dns.message.make_query('version.bind.', 'TXT', 'CH', use_edns=5,
-                                       payload=4096)
+        query = dns.message.make_query("version.bind.", "TXT", "CH", use_edns=5, payload=4096)
         response = self.sendUDPQuery(query)
         self.assertRcodeEqual(response, dns.rcode.BADVERS)
         self.assertEqual(response.answer, [])
index 3f9120608ca161df1890fa80ec822adb1613751e..c5966dddb7641d8b0d0382e3ee4b06a37b1a1905 100644 (file)
@@ -7,6 +7,7 @@ from twisted.internet import reactor
 
 ednsBufferReactorRunning = False
 
+
 class EDNSBufferTest(RecursorTest):
     """
     The tests derived from this one test several truncation related issues.
@@ -37,24 +38,25 @@ class EDNSBufferTest(RecursorTest):
 
     The qname is $testnum.edns-tests.example.
     """
-    _confdir = 'EDNSBuffer'
+
+    _confdir = "EDNSBuffer"
     _udpTruncationThreshold = 1680
     _ednsOutgoingBufsize = 1680
-    _qnameSuffix = '.edns-tests.example.'
+    _qnameSuffix = ".edns-tests.example."
 
     _config_template = """
 qname-minimization=no
 forward-zones=edns-tests.example=%s.22
 udp-truncation-threshold=%d
 edns-outgoing-bufsize=%d
-    """ % (os.environ['PREFIX'], _udpTruncationThreshold, _ednsOutgoingBufsize)
+    """ % (os.environ["PREFIX"], _udpTruncationThreshold, _ednsOutgoingBufsize)
 
     @classmethod
     def startResponders(cls):
         global ednsBufferReactorRunning
         print("Launching responders..")
 
-        address = cls._PREFIX + '.22'
+        address = cls._PREFIX + ".22"
         port = 53
 
         if not ednsBufferReactorRunning:
@@ -65,8 +67,7 @@ edns-outgoing-bufsize=%d
 
     def getMessage(self, testnum, payload=0):
         do_edns = payload > 0
-        return dns.message.make_query(testnum + self._qnameSuffix, 'TXT', 'IN',
-                                      use_edns=do_edns, payload=payload)
+        return dns.message.make_query(testnum + self._qnameSuffix, "TXT", "IN", use_edns=do_edns, payload=payload)
 
     def checkResponseContent(self, rawResponse, value, size, txt_final):
         """
@@ -79,17 +80,16 @@ edns-outgoing-bufsize=%d
         self.assertEqual(len(rawResponse), size)
         self.assertRcodeEqual(response, dns.rcode.NOERROR)
 
-        self.assertMessageHasFlags(response, ['QR', 'RD', 'RA'])
+        self.assertMessageHasFlags(response, ["QR", "RD", "RA"])
 
         for record in response.answer:
             self.assertEqual(record.rdtype, dns.rdatatype.TXT)
             for part in record:
                 for string in part.strings:
-                    self.assertTrue(len(string) == 255 or
-                                    len(string) == txt_final)
+                    self.assertTrue(len(string) == 255 or len(string) == txt_final)
 
     def checkTruncatedResponse(self, message):
-        self.assertMessageHasFlags(message, ['QR', 'RD', 'RA', 'TC'])
+        self.assertMessageHasFlags(message, ["QR", "RD", "RA", "TC"])
 
     def checkEDNS(self, message, bufsize=0):
         """
@@ -107,74 +107,75 @@ class EDNSBuffer16801680Test(EDNSBufferTest):
     """
     Runs test cases 1, 2, 5, 6, 7, 8
     """
-    _confdir = 'EDNSBuffer16801680'
+
+    _confdir = "EDNSBuffer16801680"
 
     def testEdnsBufferTestCase01(self):
-        query = self.getMessage('01', 4096)
+        query = self.getMessage("01", 4096)
         for _ in range(10):
             raw = self.sendUDPQuery(query, decode=False)
-            self.checkResponseContent(raw, 'A',
-                                      self._udpTruncationThreshold, 9)
+            self.checkResponseContent(raw, "A", self._udpTruncationThreshold, 9)
             message = dns.message.from_wire(raw)
             self.checkEDNS(message, 512)
 
     def testEdnsBufferTestCase02(self):
-        query = self.getMessage('02', 1679)
+        query = self.getMessage("02", 1679)
         for _ in range(10):
             message = self.sendUDPQuery(query)
             self.checkTruncatedResponse(message)
             self.checkEDNS(message, 512)
 
     def testEdnsBufferTestCase05(self):
-        query = self.getMessage('05', 1680)
+        query = self.getMessage("05", 1680)
         for _ in range(10):
             raw = self.sendUDPQuery(query, decode=False)
-            self.checkResponseContent(raw, 'E',
-                                      self._udpTruncationThreshold, 9)
+            self.checkResponseContent(raw, "E", self._udpTruncationThreshold, 9)
             message = dns.message.from_wire(raw)
             self.checkEDNS(message, 512)
 
     def testEdnsBufferTestCase06(self):
-        query = self.getMessage('06', 0)
+        query = self.getMessage("06", 0)
         for _ in range(10):
             raw = self.sendUDPQuery(query, decode=False)
-            self.checkResponseContent(raw, 'F', 512, 192)
+            self.checkResponseContent(raw, "F", 512, 192)
             message = dns.message.from_wire(raw)
             self.checkEDNS(message, 0)
 
     def testEdnsBufferTestCase07(self):
-        query = self.getMessage('07', 0)
+        query = self.getMessage("07", 0)
         for _ in range(10):
             message = self.sendUDPQuery(query)
             self.checkTruncatedResponse(message)
             self.checkEDNS(message, 0)
 
     def testEdnsBufferTestCase08(self):
-        query = self.getMessage('08', 511)
+        query = self.getMessage("08", 511)
         for _ in range(10):
             raw = self.sendUDPQuery(query, decode=False)
-            self.checkResponseContent(raw, 'H', 512, 181)
+            self.checkResponseContent(raw, "H", 512, 181)
             message = dns.message.from_wire(raw)
             self.checkEDNS(message, 512)
 
+
 class EDNSBuffer16801681Test(EDNSBufferTest):
     """
     Runs test case 3
     """
-    _confdir = 'EDNSBuffer16801681'
+
+    _confdir = "EDNSBuffer16801681"
     _udpTruncationThreshold = 1680
     _ednsOutgoingBufsize = 1681
-    _qnameSuffix = '.edns-tests.example.'
+    _qnameSuffix = ".edns-tests.example."
 
     _config_template = """
 qname-minimization=no
 forward-zones=edns-tests.example=%s.22
 udp-truncation-threshold=%d
 edns-outgoing-bufsize=%d
-    """ % (os.environ['PREFIX'], _udpTruncationThreshold, _ednsOutgoingBufsize)
+    """ % (os.environ["PREFIX"], _udpTruncationThreshold, _ednsOutgoingBufsize)
 
     def testEdnsBufferTestCase03(self):
-        query = self.getMessage('03', 4096)
+        query = self.getMessage("03", 4096)
         for _ in range(10):
             message = self.sendUDPQuery(query)
             self.checkTruncatedResponse(message)
@@ -185,24 +186,24 @@ class EDNSBuffer16801679Test(EDNSBufferTest):
     """
     Runs test case 4
     """
-    _confdir = 'EDNSBuffer16801679'
+
+    _confdir = "EDNSBuffer16801679"
     _udpTruncationThreshold = 1680
     _ednsOutgoingBufsize = 1679
-    _qnameSuffix = '.edns-tests.example.'
+    _qnameSuffix = ".edns-tests.example."
 
     _config_template = """
 qname-minimization=no
 forward-zones=edns-tests.example=%s.22
 udp-truncation-threshold=%d
 edns-outgoing-bufsize=%d
-    """ % (os.environ['PREFIX'], _udpTruncationThreshold, _ednsOutgoingBufsize)
+    """ % (os.environ["PREFIX"], _udpTruncationThreshold, _ednsOutgoingBufsize)
 
     def testEdnsBufferTestCase04(self):
-        query = self.getMessage('04', 4096)
+        query = self.getMessage("04", 4096)
         for _ in range(10):
             raw = self.sendUDPQuery(query, decode=False)
-            self.checkResponseContent(raw, 'D',
-                                      self._ednsOutgoingBufsize, 8)
+            self.checkResponseContent(raw, "D", self._ednsOutgoingBufsize, 8)
             message = dns.message.from_wire(raw)
             self.checkEDNS(message, 512)
 
@@ -213,7 +214,7 @@ class UDPLargeResponder(DatagramProtocol):
         # The outgoing packet should be EDNS buffersize bytes
         packet_size = request.payload
 
-        testnum = int(str(request.question[0].name).split('.')[0])
+        testnum = int(str(request.question[0].name).split(".")[0])
 
         # Unless we have special tests
         if testnum == 6:
@@ -263,13 +264,11 @@ class UDPLargeResponder(DatagramProtocol):
             # And the TXT size indicator (first byte in the TXT record)
             packet_size -= 1
             txt_size = min(packet_size, 255)
-            answer = dns.rrset.from_text(request.question[0].name,
-                                         0, dns.rdataclass.IN, 'TXT',
-                                         value*txt_size)
+            answer = dns.rrset.from_text(request.question[0].name, 0, dns.rdataclass.IN, "TXT", value * txt_size)
 
             response.answer.append(answer)
             packet_size -= txt_size
 
-        assert(packet_size == 0)
+        assert packet_size == 0
 
         self.transport.write(response.to_wire(max_size=65535), address)
index e58b2374adb412da5fc0dfe1c14745de0ffbc505..570fcfe3463c41b81627f6c36160711d9926a1f1 100644 (file)
@@ -7,9 +7,9 @@ import paddingoption
 
 from recursortests import RecursorTest
 
-class RecursorEDNSPaddingTest(RecursorTest):
 
-    _confdir = 'RecursorEDNSPadding'
+class RecursorEDNSPaddingTest(RecursorTest):
+    _confdir = "RecursorEDNSPadding"
 
     def checkPadding(self, message, numberOfBytes=None):
         self.assertEqual(message.edns, 0)
@@ -51,66 +51,66 @@ class RecursorEDNSPaddingTest(RecursorTest):
         return message
 
     def testQueryWithoutEDNS(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
-        query = dns.message.make_query(name, 'A', want_dnssec=False)
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
+        query = dns.message.make_query(name, "A", want_dnssec=False)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoEDNS(res)
         self.assertRRsetInAnswer(res, expected)
 
-class PaddingDefaultTest(RecursorEDNSPaddingTest):
 
-    _confdir = 'PaddingDefault'
+class PaddingDefaultTest(RecursorEDNSPaddingTest):
+    _confdir = "PaddingDefault"
 
     def testQueryWithPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
     def testQueryWithoutPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
-class PaddingDefaultNotAllowedTest(RecursorEDNSPaddingTest):
 
-    _confdir = 'PaddingDefaultNotAllowed'
+class PaddingDefaultNotAllowedTest(RecursorEDNSPaddingTest):
+    _confdir = "PaddingDefaultNotAllowed"
     _config_template = """edns-padding-from=127.0.0.2
 packetcache-ttl=60
     """
 
     def testQueryWithPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
     def testQueryWithoutPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
-class PaddingAlwaysTest(RecursorEDNSPaddingTest):
 
-    _confdir = 'PaddingAlways'
+class PaddingAlwaysTest(RecursorEDNSPaddingTest):
+    _confdir = "PaddingAlways"
     _config_template = """edns-padding-from=127.0.0.1
 edns-padding-mode=always
 edns-padding-tag=7830
@@ -148,30 +148,30 @@ packetcache-ttl=60
     """
 
     def testQueryWithPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
     def testQueryWithPaddingButDisabledViaLua(self):
-        name = 'host1.secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.2')
+        name = "host1.secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.2")
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
     def testQueryWithPaddingButDisabledViaGettagFFI(self):
-        name = 'host1.sub.secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.11')
+        name = "host1.sub.secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.11")
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         query.flags |= dns.flags.CD
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
@@ -179,17 +179,17 @@ packetcache-ttl=60
         self.assertRRsetInAnswer(res, expected)
 
     def testQueryWithoutPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
-class PaddingNotAllowedAlwaysTest(RecursorEDNSPaddingTest):
 
-    _confdir = 'PaddingNotAllowedAlways'
+class PaddingNotAllowedAlwaysTest(RecursorEDNSPaddingTest):
+    _confdir = "PaddingNotAllowedAlways"
     _config_template = """edns-padding-from=127.0.0.2
 edns-padding-mode=always
 edns-padding-tag=7830
@@ -197,27 +197,27 @@ packetcache-ttl=60
     """
 
     def testQueryWithPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
     def testQueryWithoutPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
-class PaddingWhenPaddedTest(RecursorEDNSPaddingTest):
 
-    _confdir = 'PaddingWhenPadded'
+class PaddingWhenPaddedTest(RecursorEDNSPaddingTest):
+    _confdir = "PaddingWhenPadded"
     _config_template = """edns-padding-from=127.0.0.1
 edns-padding-mode=padded-queries-only
 edns-padding-tag=7830
@@ -226,27 +226,27 @@ packetcache-ttl=60
     """
 
     def testQueryWithPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
     def testQueryWithoutPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
-class PaddingWhenPaddedNotAllowedTest(RecursorEDNSPaddingTest):
 
-    _confdir = 'PaddingWhenPaddedNotAllowed'
+class PaddingWhenPaddedNotAllowedTest(RecursorEDNSPaddingTest):
+    _confdir = "PaddingWhenPaddedNotAllowed"
     _config_template = """edns-padding-from=127.0.0.2
 edns-padding-mode=padded-queries-only
 edns-padding-tag=7830
@@ -255,31 +255,31 @@ packetcache-ttl=60
     """
 
     def testQueryWithPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
     def testQueryWithoutPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkNoPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
-@unittest.skipIf('SKIP_IPV6_TESTS' in os.environ, 'IPv6 tests are disabled')
-class PaddingAllowedAlwaysSameTagTest(RecursorEDNSPaddingTest):
 
+@unittest.skipIf("SKIP_IPV6_TESTS" in os.environ, "IPv6 tests are disabled")
+class PaddingAllowedAlwaysSameTagTest(RecursorEDNSPaddingTest):
     # we use the default tag (0) for padded responses, which will cause
     # the same packet cache entry (with padding ) to be returned to a client
     # not allowed by the edns-padding-from list
-    _confdir = 'PaddingAllowedAlwaysSameTag'
+    _confdir = "PaddingAllowedAlwaysSameTag"
     _config_template = """edns-padding-from=127.0.0.1
 edns-padding-mode=always
 edns-padding-tag=0
@@ -289,34 +289,34 @@ packetcache-ttl=60
 
     @classmethod
     def setUpClass(cls):
-        if 'SKIP_IPV6_TESTS' in os.environ:
-            raise unittest.SkipTest('IPv6 tests are disabled')
+        if "SKIP_IPV6_TESTS" in os.environ:
+            raise unittest.SkipTest("IPv6 tests are disabled")
 
         super(PaddingAllowedAlwaysSameTagTest, cls).setUpClass()
 
     def testQueryWithPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
         po = paddingoption.PaddingOption(64)
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[po])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[po])
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
-        res = self.sendUDPQueryTo(query, '::1')
+        res = self.sendUDPQueryTo(query, "::1")
         self.checkPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
     def testQueryWithoutPadding(self):
-        name = 'secure.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.17')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "secure.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.17")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.checkPadding(res)
         self.assertRRsetInAnswer(res, expected)
 
-        res = self.sendUDPQueryTo(query, '::1')
+        res = self.sendUDPQueryTo(query, "::1")
         self.checkPadding(res)
         self.assertRRsetInAnswer(res, expected)
index 95dad2ce0e49b7a5b1367c73f0bf0b34730f0867..d6e1233a969d33290f351ba87c9942ebbf35a139 100644 (file)
@@ -6,18 +6,19 @@ import pytest
 import shutil
 from recursortests import RecursorTest
 
+
 class ExpiredTest(RecursorTest):
     """This regression test starts the authoritative servers with a clock that is
     set 15 days into the past. Hence, the recursor must reject the signatures
     because they are expired.
     """
-    _confdir = 'Expired'
+
+    _confdir = "Expired"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """dnssec=validate"""
 
-    _auth_env = {'LD_PRELOAD':os.environ.get('LIBFAKETIME'),
-                 'FAKETIME':'-15d'}
+    _auth_env = {"LD_PRELOAD": os.environ.get("LIBFAKETIME"), "FAKETIME": "-15d"}
 
     @classmethod
     def setUpClass(cls):
@@ -26,12 +27,12 @@ class ExpiredTest(RecursorTest):
 
     @classmethod
     def tearDownClass(cls):
-        confdir = os.path.join('configs', 'auths')
+        confdir = os.path.join("configs", "auths")
         print("Specialized auth teardown " + confdir)
         # tear down specialized auths, and then start standard ones
         super().tearDownClass(True)
         print("Starting default auths")
-        #confdir = 'configs/auths'
+        # confdir = 'configs/auths'
         shutil.rmtree(confdir, True)
         os.mkdir(confdir)
         # Be careful here, we don't want the overridden secureZone(), so call RecursorTest explicitly
@@ -39,17 +40,19 @@ class ExpiredTest(RecursorTest):
         RecursorTest.startAllAuth(confdir)
 
     def testA(self):
-        query = dns.message.make_query('host1.secure.example', 'A')
+        query = dns.message.make_query("host1.secure.example", "A")
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
+
 class ExpiredWithEDETest(RecursorTest):
     """This regression test starts the authoritative servers with a clock that is
     set 15 days into the past. Hence, the recursor must reject the signatures
     because they are expired.
     """
-    _confdir = 'ExpiredWithEDE'
+
+    _confdir = "ExpiredWithEDE"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """
@@ -57,8 +60,8 @@ class ExpiredWithEDETest(RecursorTest):
     extended-resolution-errors=yes
     """
 
-    _auth_env = {'LD_PRELOAD':os.environ.get('LIBFAKETIME'),
-                 'FAKETIME':'-15d'}
+    _auth_env = {"LD_PRELOAD": os.environ.get("LIBFAKETIME"), "FAKETIME": "-15d"}
+
     @classmethod
     def setUpClass(cls):
         cls.setUpClassSpecialAuths()
@@ -66,12 +69,12 @@ class ExpiredWithEDETest(RecursorTest):
 
     @classmethod
     def tearDownClass(cls):
-        confdir = os.path.join('configs', 'auths')
+        confdir = os.path.join("configs", "auths")
         print("Specialized auth teardown " + confdir)
         # tear down specialized auths, and then start standard ones
         super().tearDownClass(True)
         print("Starting default auths")
-        #confdir = 'configs/auths'
+        # confdir = 'configs/auths'
         shutil.rmtree(confdir, True)
         os.mkdir(confdir)
         # Be careful here, we don't want the overridden secureZone(), so call RecursorTest explicitly
@@ -79,8 +82,8 @@ class ExpiredWithEDETest(RecursorTest):
         RecursorTest.startAllAuth(confdir)
 
     def testA(self):
-        qname = 'host1.secure.example'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        qname = "host1.secure.example"
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -89,4 +92,4 @@ class ExpiredWithEDETest(RecursorTest):
             self.assertEqual(res.edns, 0)
             self.assertEqual(len(res.options), 1)
             self.assertEqual(res.options[0].otype, 15)
-            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(7, b''))
+            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(7, b""))
index 49f5ad61480e8dd8c9bd524095e9e78ea00d5bf3..40151b3fb0b236160716221fa85db4f54c4813ed 100644 (file)
@@ -5,9 +5,9 @@ import pytest
 
 from recursortests import RecursorTest
 
-class ExtendedErrorsTest(RecursorTest):
 
-    _confdir = 'ExtendedErrors'
+class ExtendedErrorsTest(RecursorTest):
+    _confdir = "ExtendedErrors"
     _config_template = """
 dnssec=validate
 extended-resolution-errors=yes
@@ -51,25 +51,27 @@ extended-resolution-errors=yes
         ffi.C.pdns_ffi_param_set_extended_error_extra(obj, #extra, extra)
       end
     end
-    """ % ('A'*427)
+    """ % ("A" * 427)
 
     _roothints = None
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 *.rpz.extended.zone.rpz. 60 IN CNAME .
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
         super(ExtendedErrorsTest, cls).generateRecursorConfig(confdir)
 
     @pytest.mark.external
     def testNotIncepted(self):
-        qname = 'signotincepted.bad-dnssec.wb.sidnlabs.nl.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        qname = "signotincepted.bad-dnssec.wb.sidnlabs.nl."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -78,12 +80,12 @@ extended-resolution-errors=yes
             self.assertEqual(res.edns, 0)
             self.assertEqual(len(res.options), 1)
             self.assertEqual(res.options[0].otype, 15)
-            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(8, b''))
+            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(8, b""))
 
     @pytest.mark.external
     def testExpired(self):
-        qname = 'sigexpired.bad-dnssec.wb.sidnlabs.nl.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        qname = "sigexpired.bad-dnssec.wb.sidnlabs.nl."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -92,12 +94,12 @@ extended-resolution-errors=yes
             self.assertEqual(res.edns, 0)
             self.assertEqual(len(res.options), 1)
             self.assertEqual(res.options[0].otype, 15)
-            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(7, b''))
+            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(7, b""))
 
     @pytest.mark.external
     def testAllExpired(self):
-        qname = 'servfail.nl.'
-        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        qname = "servfail.nl."
+        query = dns.message.make_query(qname, "AAAA", want_dnssec=True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -106,12 +108,12 @@ extended-resolution-errors=yes
             self.assertEqual(res.edns, 0)
             self.assertEqual(len(res.options), 1)
             self.assertEqual(res.options[0].otype, 15)
-            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(6, b''))
+            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(6, b""))
 
     @pytest.mark.external
     def testBogus(self):
-        qname = 'bogussig.ok.bad-dnssec.wb.sidnlabs.nl.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        qname = "bogussig.ok.bad-dnssec.wb.sidnlabs.nl."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -120,12 +122,12 @@ extended-resolution-errors=yes
             self.assertEqual(res.edns, 0)
             self.assertEqual(len(res.options), 1)
             self.assertEqual(res.options[0].otype, 15)
-            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(6, b''))
+            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(6, b""))
 
     @pytest.mark.external
     def testMissingRRSIG(self):
-        qname = 'brokendnssec.net.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        qname = "brokendnssec.net."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -134,11 +136,11 @@ extended-resolution-errors=yes
             self.assertEqual(res.edns, 0)
             self.assertEqual(len(res.options), 1)
             self.assertEqual(res.options[0].otype, 15)
-            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(10, b''))
+            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(10, b""))
 
     def testFromLua(self):
-        qname = 'fromlua.extended.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        qname = "fromlua.extended."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -147,11 +149,11 @@ extended-resolution-errors=yes
             self.assertEqual(res.edns, 0)
             self.assertEqual(len(res.options), 1)
             self.assertEqual(res.options[0].otype, 15)
-            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(10, b'Extra text from Lua!'))
+            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(10, b"Extra text from Lua!"))
 
     def testFromLuaFFI(self):
-        qname = 'fromluaffi.extended.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        qname = "fromluaffi.extended."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -160,11 +162,11 @@ extended-resolution-errors=yes
             self.assertEqual(res.edns, 0)
             self.assertEqual(len(res.options), 1)
             self.assertEqual(res.options[0].otype, 15)
-            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(10, b'Extra text from Lua FFI!'))
+            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(10, b"Extra text from Lua FFI!"))
 
     def testRPZ(self):
-        qname = 'sub.rpz.extended.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        qname = "sub.rpz.extended."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -173,11 +175,11 @@ extended-resolution-errors=yes
             self.assertEqual(res.edns, 0)
             self.assertEqual(len(res.options), 1)
             self.assertEqual(res.options[0].otype, 15)
-            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(15, b'Blocked by RPZ!'))
+            self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(15, b"Blocked by RPZ!"))
 
     def testTooLarge(self):
-        qname = 'toolarge.extended.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True, payload=512)
+        qname = "toolarge.extended."
+        query = dns.message.make_query(qname, "A", want_dnssec=True, payload=512)
 
         # should not have the Extended Option since the packet is too large already
         res = self.sendUDPQuery(query, timeout=5.0)
@@ -192,11 +194,11 @@ extended-resolution-errors=yes
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(10, b'Extra text from Lua!'))
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(10, b"Extra text from Lua!"))
 
-class NoExtendedErrorsTest(RecursorTest):
 
-    _confdir = 'NoExtendedErrors'
+class NoExtendedErrorsTest(RecursorTest):
+    _confdir = "NoExtendedErrors"
     _config_template = """
 dnssec=validate
 extended-resolution-errors=no
@@ -205,8 +207,8 @@ extended-resolution-errors=no
 
     @pytest.mark.external
     def testNotIncepted(self):
-        qname = 'signotincepted.bad-dnssec.wb.sidnlabs.nl.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        qname = "signotincepted.bad-dnssec.wb.sidnlabs.nl."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
index 0d5ca4ef92ff7f39ef931d70f2a4eb7728cdc5ce..b3cb46cdbc19587d38eeed60d71ab4ba0a9f6924 100644 (file)
@@ -8,13 +8,13 @@ import yaml
 
 from recursortests import RecursorTest
 
-class FWCatzServer(object):
 
+class FWCatzServer(object):
     def __init__(self, port):
         self._currentSerial = 0
         self._targetSerial = 1
         self._serverPort = port
-        listener = threading.Thread(name='FWCatz Listener', target=self._listener, args=[])
+        listener = threading.Thread(name="FWCatz Listener", target=self._listener, args=[])
         listener.daemon = True
         listener.start()
 
@@ -26,7 +26,9 @@ class FWCatzServer(object):
             return False
 
         if newSerial != self._currentSerial + 1:
-            raise AssertionError("Asking the FWCatz server to serve serial %d, already serving %d" % (newSerial, self._currentSerial))
+            raise AssertionError(
+                "Asking the FWCatz server to serve serial %d, already serving %d" % (newSerial, self._currentSerial)
+            )
         self._targetSerial = newSerial
         return True
 
@@ -37,127 +39,364 @@ class FWCatzServer(object):
 
         if message.question[0].rdtype == dns.rdatatype.AXFR:
             if self._currentSerial != 0:
-                print('Received an AXFR query but IXFR expected because the current serial is %d' % (self._currentSerial))
+                print(
+                    "Received an AXFR query but IXFR expected because the current serial is %d" % (self._currentSerial)
+                )
                 return (None, self._currentSerial)
 
             newSerial = self._targetSerial
             records = [
-                dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                dns.rrset.from_text('version.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.TXT, '2'),
-                dns.rrset.from_text('a.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'a.'),
-                dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial)
-                ]
+                dns.rrset.from_text(
+                    "forward.catz.",
+                    60,
+                    dns.rdataclass.IN,
+                    dns.rdatatype.SOA,
+                    "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                ),
+                dns.rrset.from_text("version.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.TXT, "2"),
+                dns.rrset.from_text("a.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "a."),
+                dns.rrset.from_text(
+                    "forward.catz.",
+                    60,
+                    dns.rdataclass.IN,
+                    dns.rdatatype.SOA,
+                    "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                ),
+            ]
 
         elif message.question[0].rdtype == dns.rdatatype.IXFR:
             oldSerial = message.authority[0][0].serial
 
             # special case for the 9th update, which might get skipped
             if oldSerial != self._currentSerial and self._currentSerial != 9:
-                print('Received an IXFR query with an unexpected serial %d, expected %d' % (oldSerial, self._currentSerial))
+                print(
+                    "Received an IXFR query with an unexpected serial %d, expected %d"
+                    % (oldSerial, self._currentSerial)
+                )
                 return (None, self._currentSerial)
 
             newSerial = self._targetSerial
             if newSerial == 2:
                 records = [
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % oldSerial),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
                     # no deletion
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('b.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'b.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("b.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "b."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 3:
                 records = [
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('a.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'a.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text("a.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "a."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
                     # no addition
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 4:
                 records = [
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('b.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'b.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('c.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'c.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text("b.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "b."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("c.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "c."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 5:
                 # this one is a bit special, we are answering with a full AXFR
                 records = [
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('version.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.TXT, '2'),
-                    dns.rrset.from_text('d.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'd.'),
-                    dns.rrset.from_text('e.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'e.'),
-                    dns.rrset.from_text('f.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'f.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("version.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.TXT, "2"),
+                    dns.rrset.from_text("d.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "d."),
+                    dns.rrset.from_text("e.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "e."),
+                    dns.rrset.from_text("f.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "f."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 6:
                 # back to IXFR
                 records = [
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('d.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'd.'),
-                    dns.rrset.from_text('e.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'e.'),
-                    dns.rrset.from_text('f.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'f.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('e.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'ee.'),
-                    dns.rrset.from_text('group.e.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.TXT, 'GROUP'),
-                    dns.rrset.from_text('f.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'ff.'),
-                    dns.rrset.from_text('g.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'gg.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text("d.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "d."),
+                    dns.rrset.from_text("e.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "e."),
+                    dns.rrset.from_text("f.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "f."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("e.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "ee."),
+                    dns.rrset.from_text(
+                        "group.e.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.TXT, "GROUP"
+                    ),
+                    dns.rrset.from_text("f.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "ff."),
+                    dns.rrset.from_text("g.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "gg."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 7:
                 records = [
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('e.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'ee.'),
-                    dns.rrset.from_text('group.e.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.TXT, 'GROUP'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('e.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'e.'),
-                    dns.rrset.from_text('f.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'f.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text("e.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "ee."),
+                    dns.rrset.from_text(
+                        "group.e.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.TXT, "GROUP"
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("e.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "e."),
+                    dns.rrset.from_text("f.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "f."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 8:
                 # this one is a bit special too, we are answering with a full AXFR and the new zone is empty
                 records = [
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('version.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.TXT, '2'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("version.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.TXT, "2"),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 9:
                 # IXFR inserting a duplicate, we should not crash and skip it
                 records = [
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('version.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.TXT, '2'),
-                    dns.rrset.from_text('dup1.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'dup.'),
-                    dns.rrset.from_text('dup2.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'dup.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("version.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.TXT, "2"),
+                    dns.rrset.from_text("dup1.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "dup."),
+                    dns.rrset.from_text("dup2.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "dup."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 10:
                 # full AXFR to make sure we are removing the duplicate, adding a record, to check that the update was correctly applied
                 records = [
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('version.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.TXT, '2'),
-                    dns.rrset.from_text('f.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'f.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("version.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.TXT, "2"),
+                    dns.rrset.from_text("f.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "f."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 11:
                 # IXFR with two deltas, the first one adding a 'g' and the second one removing 'f'
                 records = [
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % (newSerial + 1)),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('g.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'g.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('f.zones.forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.PTR, 'f.'),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % (newSerial + 1)),
-                    dns.rrset.from_text('forward.catz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1' % (newSerial + 1)),
-                    ]
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % (newSerial + 1),
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("g.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "g."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("f.zones.forward.catz.", 60, dns.rdataclass.IN, dns.rdatatype.PTR, "f."),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % (newSerial + 1),
+                    ),
+                    dns.rrset.from_text(
+                        "forward.catz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.forward.catz. hostmaster.forward.catz. %d 3600 3600 3600 1" % (newSerial + 1),
+                    ),
+                ]
                 # this one has two updates in one
                 newSerial = newSerial + 1
                 self._targetSerial = self._targetSerial + 1
@@ -178,14 +417,14 @@ class FWCatzServer(object):
 
             message = dns.message.from_wire(data)
             if len(message.question) != 1:
-                print('Invalid FWCatz query, qdcount is %d' % (len(message.question)))
+                print("Invalid FWCatz query, qdcount is %d" % (len(message.question)))
                 break
             if not message.question[0].rdtype in [dns.rdatatype.AXFR, dns.rdatatype.IXFR]:
-                print('Invalid FWCatz query, qtype is %d' % (message.question.rdtype))
+                print("Invalid FWCatz query, qtype is %d" % (message.question.rdtype))
                 break
             (serial, answer) = self._getAnswer(message)
             if not answer:
-                print('Unable to get a response for %s %d' % (message.question[0].name, message.question[0].rdtype))
+                print("Unable to get a response for %s %d" % (message.question[0].name, message.question[0].rdtype))
                 break
 
             wire = answer.to_wire()
@@ -214,30 +453,30 @@ class FWCatzServer(object):
         while True:
             try:
                 (conn, _) = sock.accept()
-                thread = threading.Thread(name='FWCatz Connection Handler',
-                                      target=self._connectionHandler,
-                                      args=[conn])
+                thread = threading.Thread(name="FWCatz Connection Handler", target=self._connectionHandler, args=[conn])
                 thread.daemon = True
                 thread.start()
 
             except socket.error as e:
-                print('Error in FWCatz socket: %s' % str(e))
+                print("Error in FWCatz socket: %s" % str(e))
                 sock.close()
 
+
 fwCatzServerPort = 4252
 fwCatzServer = FWCatzServer(fwCatzServerPort)
 
+
 class FWCatzXFRRecursorTest(RecursorTest):
     """
     This test makes sure that we correctly update FW cat zones via AXFR then IXFR
     """
 
     global fwCatzServerPort
-    _confdir = 'FWCatzXFRRecursor'
+    _confdir = "FWCatzXFRRecursor"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 logging:
   loglevel: 7
@@ -276,12 +515,12 @@ recursor:
         super(FWCatzXFRRecursorTest, cls).generateRecursorYamlConfig(confdir, False)
 
     def sendNotify(self):
-        notify = dns.message.make_query('forward.catz', 'SOA', want_dnssec=False)
-        notify.set_opcode(4) # notify
+        notify = dns.message.make_query("forward.catz", "SOA", want_dnssec=False)
+        notify.set_opcode(4)  # notify
         res = self.sendUDPQuery(notify)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(res.opcode(), 4)
-        self.assertEqual(res.question[0].to_text(), 'forward.catz. IN SOA')
+        self.assertEqual(res.question[0].to_text(), "forward.catz. IN SOA")
 
     def checkForwards(self, expected):
         attempts = 0
@@ -289,8 +528,8 @@ recursor:
         ex = None
         while attempts < tries:
             try:
-                with open('configs/' + self._confdir + '/catzone.forward.catz.') as file:
-                    reality = yaml.safe_load(file);
+                with open("configs/" + self._confdir + "/catzone.forward.catz.") as file:
+                    reality = yaml.safe_load(file)
                     if expected == reality:
                         return
             except Exception as e:
@@ -299,7 +538,7 @@ recursor:
             time.sleep(0.01)
         if ex is not None:
             raise ex
-        raise AssertionError('expected content not found')
+        raise AssertionError("expected content not found")
 
     def waitUntilCorrectSerialIsLoaded(self, serial, timeout=5):
         global fwCatzServer
@@ -318,66 +557,74 @@ recursor:
             attempts = attempts + 1
             time.sleep(1)
 
-        raise AssertionError("Waited %d seconds for the serial to be updated to %d but the serial is still %d" % (timeout, serial, currentSerial))
+        raise AssertionError(
+            "Waited %d seconds for the serial to be updated to %d but the serial is still %d"
+            % (timeout, serial, currentSerial)
+        )
 
     def testFWCatz(self):
         # Fresh catz does not need a notify
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
         # first zone
         self.waitUntilCorrectSerialIsLoaded(1)
-        self.checkForwards({'forward_zones': [
-            {'zone': 'a.', 'forwarders': ['1.2.3.4']}
-        ]})
+        self.checkForwards({"forward_zones": [{"zone": "a.", "forwarders": ["1.2.3.4"]}]})
 
         # second zone
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(2)
-        self.checkForwards({'forward_zones': [
-            {'zone': 'a.', 'forwarders': ['1.2.3.4']},
-            {'zone': 'b.', 'forwarders': ['1.2.3.4']}
-        ]})
+        self.checkForwards(
+            {"forward_zones": [{"zone": "a.", "forwarders": ["1.2.3.4"]}, {"zone": "b.", "forwarders": ["1.2.3.4"]}]}
+        )
 
         # third zone
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(3)
-        self.checkForwards({'forward_zones': [
-            {'zone': 'b.', 'forwarders': ['1.2.3.4']}
-        ]})
+        self.checkForwards({"forward_zones": [{"zone": "b.", "forwarders": ["1.2.3.4"]}]})
 
         # fourth zone
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(4)
-        self.checkForwards({'forward_zones': [
-            {'zone': 'c.', 'forwarders': ['1.2.3.4']}
-        ]})
+        self.checkForwards({"forward_zones": [{"zone": "c.", "forwarders": ["1.2.3.4"]}]})
 
         # fifth zone, we should get a full AXFR this time
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(5)
-        self.checkForwards({'forward_zones': [
-            {'zone': 'd.', 'forwarders': ['1.2.3.4']},
-            {'zone': 'e.', 'forwarders': ['1.2.3.4']},
-            {'zone': 'f.', 'forwarders': ['1.2.3.4']}
-        ]})
+        self.checkForwards(
+            {
+                "forward_zones": [
+                    {"zone": "d.", "forwarders": ["1.2.3.4"]},
+                    {"zone": "e.", "forwarders": ["1.2.3.4"]},
+                    {"zone": "f.", "forwarders": ["1.2.3.4"]},
+                ]
+            }
+        )
 
         # sixth zone
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(6)
-        self.checkForwards({'forward_zones': [
-            {'zone': 'ee.', 'forwarders': ['4.5.6.7'], 'notify_allowed': True, 'recurse': True},
-            {'zone': 'ff.', 'forwarders': ['1.2.3.4']},
-            {'zone': 'gg.', 'forwarders': ['1.2.3.4']}
-        ]})
+        self.checkForwards(
+            {
+                "forward_zones": [
+                    {"zone": "ee.", "forwarders": ["4.5.6.7"], "notify_allowed": True, "recurse": True},
+                    {"zone": "ff.", "forwarders": ["1.2.3.4"]},
+                    {"zone": "gg.", "forwarders": ["1.2.3.4"]},
+                ]
+            }
+        )
 
         # seventh zone
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(7)
-        self.checkForwards({'forward_zones': [
-            {'zone': 'e.', 'forwarders': ['1.2.3.4']},
-            {'zone': 'ff.', 'forwarders': ['1.2.3.4']},
-            {'zone': 'f.', 'forwarders': ['1.2.3.4']},
-            {'zone': 'gg.', 'forwarders': ['1.2.3.4']}
-        ]})
+        self.checkForwards(
+            {
+                "forward_zones": [
+                    {"zone": "e.", "forwarders": ["1.2.3.4"]},
+                    {"zone": "ff.", "forwarders": ["1.2.3.4"]},
+                    {"zone": "f.", "forwarders": ["1.2.3.4"]},
+                    {"zone": "gg.", "forwarders": ["1.2.3.4"]},
+                ]
+            }
+        )
 
         # eighth zone, all entries should be gone
         self.sendNotify()
@@ -398,8 +645,4 @@ recursor:
         time.sleep(3)
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(12)
-        self.checkForwards({'forward_zones': [
-            {'zone': 'g.', 'forwarders': ['1.2.3.4']}
-        ]})
-
-
+        self.checkForwards({"forward_zones": [{"zone": "g.", "forwarders": ["1.2.3.4"]}]})
index 92dec29f96a3e85cc8aea274fbbb7e7a8a76a9ca..ab46f9e9872acbe81599a1af0d14f1d7531ce228 100644 (file)
@@ -6,33 +6,30 @@ from recursortests import RecursorTest
 
 
 class FlagsTest(RecursorTest):
-    _confdir = 'Flags'
+    _confdir = "Flags"
     _auth_zones = RecursorTest._default_auth_zones
     _config_template = """dnssec=%s"""
-    _config_params = ['_dnssec_setting']
+    _config_params = ["_dnssec_setting"]
     _dnssec_setting = None
     _recursors = {}
 
-    _dnssec_setting_ports = {'off': 5300,
-                             'process-no-validate': 5301,
-                             'process': 5302,
-                             'validate': 5303}
+    _dnssec_setting_ports = {"off": 5300, "process-no-validate": 5301, "process": 5302, "validate": 5303}
 
     @classmethod
     def setUp(cls):
         for setting in cls._dnssec_setting_ports:
-            confdir = os.path.join('configs', cls._confdir, setting)
+            confdir = os.path.join("configs", cls._confdir, setting)
             cls.wipeRecursorCache(confdir)
 
     @classmethod
     def setUpClass(cls):
         cls.setUpSockets()
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         cls.createConfigDir(confdir)
 
         # Moved to fixture
-        #cls.generateAllAuthConfig(confdir)
-        #cls.startAllAuth(confdir)
+        # cls.generateAllAuthConfig(confdir)
+        # cls.startAllAuth(confdir)
 
         for dnssec_setting, port in cls._dnssec_setting_ports.items():
             cls._dnssec_setting = dnssec_setting
@@ -47,8 +44,7 @@ class FlagsTest(RecursorTest):
         cls._sock = {}
         for dnssec_setting, port in cls._dnssec_setting_ports.items():
             print("Setting up UDP socket..")
-            cls._sock[dnssec_setting] = socket.socket(socket.AF_INET,
-                                                      socket.SOCK_DGRAM)
+            cls._sock[dnssec_setting] = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
             cls._sock[dnssec_setting].settimeout(2.0)
             cls._sock[dnssec_setting].connect(("127.0.0.1", port))
 
@@ -73,280 +69,311 @@ class FlagsTest(RecursorTest):
 
     @classmethod
     def tearDownClass(cls):
-        #cls.tearDownAuth() moved to fixture
+        # cls.tearDownAuth() moved to fixture
         for subdir, recursor in cls._recursors.items():
             cls._recursor = recursor
             cls.tearDownRecursor(subdir)
 
-    def getQueryForSecure(self, flags='', ednsflags=''):
-        return self.createQuery('ns1.example.', 'A', flags, ednsflags)
+    def getQueryForSecure(self, flags="", ednsflags=""):
+        return self.createQuery("ns1.example.", "A", flags, ednsflags)
 
     ##
     #   -AD -CD -DO
     ##
     def testOff_Secure_None(self):
         msg = self.getQueryForSecure()
-        res = self.sendUDPQuery(msg, 'off')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        res = self.sendUDPQuery(msg, "off")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcessNoValidate_Secure_None(self):
         msg = self.getQueryForSecure()
-        res = self.sendUDPQuery(msg, 'process-no-validate')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        res = self.sendUDPQuery(msg, "process-no-validate")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcess_Secure_None(self):
         msg = self.getQueryForSecure()
-        res = self.sendUDPQuery(msg, 'process')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        res = self.sendUDPQuery(msg, "process")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testValidate_Secure_None(self):
         msg = self.getQueryForSecure()
-        res = self.sendUDPQuery(msg, 'validate')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        res = self.sendUDPQuery(msg, "validate")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     ##
     # +AD -CD -DO
     ##
     def testOff_Secure_AD(self):
-        msg = self.getQueryForSecure('AD')
-        res = self.sendUDPQuery(msg, 'off')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        msg = self.getQueryForSecure("AD")
+        res = self.sendUDPQuery(msg, "off")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
 
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcessNoValidate_Secure_AD(self):
-        msg = self.getQueryForSecure('AD')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        msg = self.getQueryForSecure("AD")
+        res = self.sendUDPQuery(msg, "process-no-validate")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcess_Secure_AD(self):
-        msg = self.getQueryForSecure('AD')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForSecure("AD")
+        res = self.sendUDPQuery(msg, "process")
         self.assertMessageIsAuthenticated(res)
-        self.assertMessageHasFlags(res, ['AD', 'QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["AD", "QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testValidate_Secure_AD(self):
-        msg = self.getQueryForSecure('AD')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForSecure("AD")
+        res = self.sendUDPQuery(msg, "validate")
 
         self.assertMessageIsAuthenticated(res)
-        self.assertMessageHasFlags(res, ['AD', 'RD', 'RA', 'QR'])
+        self.assertMessageHasFlags(res, ["AD", "RD", "RA", "QR"])
         self.assertNoRRSIGsInAnswer(res)
 
     ##
     # +AD -CD +DO
     ##
     def testOff_Secure_ADDO(self):
-        msg = self.getQueryForSecure('AD', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForSecure("AD", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcessNoValidate_Secure_ADDO(self):
-        msg = self.getQueryForSecure('AD', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForSecure("AD", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testProcess_Secure_ADDO(self):
-        msg = self.getQueryForSecure('AD', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForSecure("AD", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "process")
 
         self.assertMessageIsAuthenticated(res)
-        self.assertMessageHasFlags(res, ['AD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["AD", "QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testValidate_Secure_ADDO(self):
-        msg = self.getQueryForSecure('AD', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForSecure("AD", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "validate")
 
         self.assertMessageIsAuthenticated(res)
-        self.assertMessageHasFlags(res, ['AD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["AD", "QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     ##
     # +AD +CD +DO
     ##
     def testOff_Secure_ADDOCD(self):
-        msg = self.getQueryForSecure('AD CD', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForSecure("AD CD", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
 
     def testProcessNoValidate_Secure_ADDOCD(self):
-        msg = self.getQueryForSecure('AD CD', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForSecure("AD CD", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['CD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["CD", "QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testProcess_Secure_ADDOCD(self):
-        msg = self.getQueryForSecure('AD CD', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForSecure("AD CD", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "process")
 
         self.assertMessageIsAuthenticated(res)
-        self.assertMessageHasFlags(res, ['AD', 'CD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["AD", "CD", "QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testValidate_Secure_ADDOCD(self):
-        msg = self.getQueryForSecure('AD CD', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForSecure("AD CD", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "validate")
 
         self.assertMessageIsAuthenticated(res)
-        self.assertMessageHasFlags(res, ['AD', 'QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["AD", "QR", "RA", "RD", "CD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     ##
     # -AD -CD +DO
     ##
     def testOff_Secure_DO(self):
-        msg = self.getQueryForSecure('', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForSecure("", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcessNoValidate_Secure_DO(self):
-        msg = self.getQueryForSecure('', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForSecure("", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testProcess_Secure_DO(self):
-        msg = self.getQueryForSecure('', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForSecure("", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['AD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["AD", "QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testValidate_Secure_DO(self):
-        msg = self.getQueryForSecure('', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForSecure("", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['AD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["AD", "QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     ##
     # -AD +CD +DO
     ##
     def testOff_Secure_DOCD(self):
-        msg = self.getQueryForSecure('CD', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForSecure("CD", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcessNoValidate_Secure_DOCD(self):
-        msg = self.getQueryForSecure('CD', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForSecure("CD", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testProcess_Secure_DOCD(self):
-        msg = self.getQueryForSecure('CD', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForSecure("CD", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['AD', 'QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["AD", "QR", "RA", "RD", "CD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testValidate_Secure_DOCD(self):
-        msg = self.getQueryForSecure('CD', 'DO')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForSecure("CD", "DO")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['AD', 'QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["AD", "QR", "RA", "RD", "CD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     ##
     # -AD +CD -DO
     ##
     def testOff_Secure_CD(self):
-        msg = self.getQueryForSecure('CD')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForSecure("CD")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRRsetInAnswer(res, expected)
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcessNoValidate_Secure_CD(self):
-        msg = self.getQueryForSecure('CD')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForSecure("CD")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"])
         self.assertRRsetInAnswer(res, expected)
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcess_Secure_CD(self):
-        msg = self.getQueryForSecure('CD')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForSecure("CD")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"])
         self.assertRRsetInAnswer(res, expected)
         self.assertNoRRSIGsInAnswer(res)
 
     def testValidate_Secure_CD(self):
-        msg = self.getQueryForSecure('CD')
-        expected = dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForSecure("CD")
+        expected = dns.rrset.from_text(
+            "ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX)
+        )
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"])
         self.assertRRsetInAnswer(res, expected)
         self.assertNoRRSIGsInAnswer(res)
 
-
     ### Bogus
-    def getQueryForBogus(self, flags='', ednsflags=''):
-        return self.createQuery('ted.bogus.example.', 'A', flags, ednsflags)
+    def getQueryForBogus(self, flags="", ednsflags=""):
+        return self.createQuery("ted.bogus.example.", "A", flags, ednsflags)
 
     ##
     #   -AD -CD -DO
     ##
     def testOff_Bogus_None(self):
         msg = self.getQueryForBogus()
-        res = self.sendUDPQuery(msg, 'off')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        res = self.sendUDPQuery(msg, "off")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcessNoValidate_Bogus_None(self):
         msg = self.getQueryForBogus()
-        res = self.sendUDPQuery(msg, 'process-no-validate')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        res = self.sendUDPQuery(msg, "process-no-validate")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcess_Bogus_None(self):
         msg = self.getQueryForBogus()
-        res = self.sendUDPQuery(msg, 'process')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        res = self.sendUDPQuery(msg, "process")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testValidate_Bogus_None(self):
         msg = self.getQueryForBogus()
-        res = self.sendUDPQuery(msg, 'validate')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        res = self.sendUDPQuery(msg, "validate")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
 
@@ -354,29 +381,29 @@ class FlagsTest(RecursorTest):
     # +AD -CD -DO
     ##
     def testOff_Bogus_AD(self):
-        msg = self.getQueryForBogus('AD')
-        res = self.sendUDPQuery(msg, 'off')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        msg = self.getQueryForBogus("AD")
+        res = self.sendUDPQuery(msg, "off")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcessNoValidate_Bogus_AD(self):
-        msg = self.getQueryForBogus('AD')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        msg = self.getQueryForBogus("AD")
+        res = self.sendUDPQuery(msg, "process-no-validate")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcess_Bogus_AD(self):
-        msg = self.getQueryForBogus('AD')
-        res = self.sendUDPQuery(msg, 'process')
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        msg = self.getQueryForBogus("AD")
+        res = self.sendUDPQuery(msg, "process")
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
 
     def testValidate_Bogus_AD(self):
-        msg = self.getQueryForBogus('AD')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForBogus("AD")
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['RD', 'RA', 'QR'])
+        self.assertMessageHasFlags(res, ["RD", "RA", "QR"])
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
 
@@ -384,257 +411,257 @@ class FlagsTest(RecursorTest):
     # +AD -CD +DO
     ##
     def testOff_Bogus_ADDO(self):
-        msg = self.getQueryForBogus('AD', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForBogus("AD", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcessNoValidate_Bogus_ADDO(self):
-        msg = self.getQueryForBogus('AD', 'DO')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForBogus("AD", "DO")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcess_Bogus_ADDO(self):
-        msg = self.getQueryForBogus('AD', 'DO')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForBogus("AD", "DO")
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
 
     def testValidate_Bogus_ADDO(self):
-        msg = self.getQueryForBogus('AD', 'DO')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForBogus("AD", "DO")
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
+
     ##
     # +AD +CD +DO
     ##
     def testOff_Bogus_ADDOCD(self):
-        msg = self.getQueryForBogus('AD CD', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForBogus("AD CD", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcessNoValidate_Bogus_ADDOCD(self):
-        msg = self.getQueryForBogus('AD CD', 'DO')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForBogus("AD CD", "DO")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['CD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["CD", "QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testProcess_Bogus_ADDOCD(self):
-        msg = self.getQueryForBogus('AD CD', 'DO')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForBogus("AD CD", "DO")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "process")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['CD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["CD", "QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testValidate_Bogus_ADDOCD(self):
-        msg = self.getQueryForBogus('AD CD', 'DO')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForBogus("AD CD", "DO")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "validate")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     ##
     # -AD -CD +DO
     ##
     def testOff_Bogus_DO(self):
-        msg = self.getQueryForBogus('', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForBogus("", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcessNoValidate_Bogus_DO(self):
-        msg = self.getQueryForBogus('', 'DO')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForBogus("", "DO")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testProcess_Bogus_DO(self):
-        msg = self.getQueryForBogus('', 'DO')
-        dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForBogus("", "DO")
+        dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertAnswerEmpty(res)
 
     def testValidate_Bogus_DO(self):
-        msg = self.getQueryForBogus('', 'DO')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForBogus("", "DO")
+        res = self.sendUDPQuery(msg, "validate")
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertAnswerEmpty(res)
 
     ##
     # -AD +CD +DO
     ##
     def testOff_Bogus_DOCD(self):
-        msg = self.getQueryForBogus('CD', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForBogus("CD", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcessNoValidate_Bogus_DOCD(self):
-        msg = self.getQueryForBogus('CD', 'DO')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForBogus("CD", "DO")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testProcess_Bogus_DOCD(self):
-        msg = self.getQueryForBogus('CD', 'DO')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForBogus("CD", "DO")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "process")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testValidate_Bogus_DOCD(self):
-        msg = self.getQueryForBogus('CD', 'DO')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForBogus("CD", "DO")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "validate")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"], ["DO"])
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     ##
     # -AD +CD -DO
     ##
     def testOff_Bogus_CD(self):
-        msg = self.getQueryForBogus('CD')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForBogus("CD")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "off")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertRRsetInAnswer(res, expected)
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcessNoValidate_Bogus_CD(self):
-        msg = self.getQueryForBogus('CD')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForBogus("CD")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"])
         self.assertRRsetInAnswer(res, expected)
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcess_Bogus_CD(self):
-        msg = self.getQueryForBogus('CD')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForBogus("CD")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "process")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"])
         self.assertRRsetInAnswer(res, expected)
         self.assertNoRRSIGsInAnswer(res)
 
     def testValidate_Bogus_CD(self):
-        msg = self.getQueryForBogus('CD')
-        expected = dns.rrset.from_text('ted.bogus.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForBogus("CD")
+        expected = dns.rrset.from_text("ted.bogus.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1")
+        res = self.sendUDPQuery(msg, "validate")
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"])
         self.assertRRsetInAnswer(res, expected)
         self.assertNoRRSIGsInAnswer(res)
 
-
     ## Insecure
-    def getQueryForInsecure(self, flags='', ednsflags=''):
-        return self.createQuery('node1.insecure.example.', 'A', flags, ednsflags)
+    def getQueryForInsecure(self, flags="", ednsflags=""):
+        return self.createQuery("node1.insecure.example.", "A", flags, ednsflags)
 
     ##
     #   -AD -CD -DO
     ##
     def testOff_Insecure_None(self):
         msg = self.getQueryForInsecure()
-        res = self.sendUDPQuery(msg, 'off')
+        res = self.sendUDPQuery(msg, "off")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcessNoValidate_Insecure_None(self):
         msg = self.getQueryForInsecure()
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        res = self.sendUDPQuery(msg, "process-no-validate")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testProcess_Insecure_None(self):
         msg = self.getQueryForInsecure()
-        res = self.sendUDPQuery(msg, 'process')
+        res = self.sendUDPQuery(msg, "process")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     def testValidate_Insecure_None(self):
         msg = self.getQueryForInsecure()
-        res = self.sendUDPQuery(msg, 'validate')
+        res = self.sendUDPQuery(msg, "validate")
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
 
     ##
     # +AD -CD -DO
     ##
     def testOff_Insecure_AD(self):
-        msg = self.getQueryForInsecure('AD')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForInsecure("AD")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcessNoValidate_Insecure_AD(self):
-        msg = self.getQueryForInsecure('AD')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForInsecure("AD")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcess_Insecure_AD(self):
-        msg = self.getQueryForInsecure('AD')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForInsecure("AD")
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testValidate_Insecure_AD(self):
-        msg = self.getQueryForInsecure('AD')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForInsecure("AD")
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['RD', 'RA', 'QR'])
+        self.assertMessageHasFlags(res, ["RD", "RA", "QR"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
@@ -642,34 +669,34 @@ class FlagsTest(RecursorTest):
     # +AD -CD +DO
     ##
     def testOff_Insecure_ADDO(self):
-        msg = self.getQueryForInsecure('AD', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForInsecure("AD", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcessNoValidate_Insecure_ADDO(self):
-        msg = self.getQueryForInsecure('AD', 'DO')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForInsecure("AD", "DO")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcess_Insecure_ADDO(self):
-        msg = self.getQueryForInsecure('AD', 'DO')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForInsecure("AD", "DO")
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testValidate_Insecure_ADDO(self):
-        msg = self.getQueryForInsecure('AD', 'DO')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForInsecure("AD", "DO")
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
@@ -677,35 +704,35 @@ class FlagsTest(RecursorTest):
     # +AD +CD +DO
     ##
     def testOff_Insecure_ADDOCD(self):
-        msg = self.getQueryForInsecure('AD CD', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForInsecure("AD CD", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcessNoValidate_Insecure_ADDOCD(self):
-        msg = self.getQueryForInsecure('AD CD', 'DO')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForInsecure("AD CD", "DO")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['CD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["CD", "QR", "RA", "RD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcess_Insecure_ADDOCD(self):
-        msg = self.getQueryForInsecure('AD CD', 'DO')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForInsecure("AD CD", "DO")
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['CD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["CD", "QR", "RA", "RD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testValidate_Insecure_ADDOCD(self):
-        msg = self.getQueryForInsecure('AD CD', 'DO')
-        dns.rrset.from_text('ns1.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForInsecure("AD CD", "DO")
+        dns.rrset.from_text("ns1.example.", 0, dns.rdataclass.IN, "A", "{prefix}.10".format(prefix=self._PREFIX))
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
@@ -713,34 +740,34 @@ class FlagsTest(RecursorTest):
     # -AD -CD +DO
     ##
     def testOff_Insecure_DO(self):
-        msg = self.getQueryForInsecure('', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForInsecure("", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcessNoValidate_Insecure_DO(self):
-        msg = self.getQueryForInsecure('', 'DO')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForInsecure("", "DO")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcess_Insecure_DO(self):
-        msg = self.getQueryForInsecure('', 'DO')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForInsecure("", "DO")
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testValidate_Insecure_DO(self):
-        msg = self.getQueryForInsecure('', 'DO')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForInsecure("", "DO")
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
@@ -748,34 +775,34 @@ class FlagsTest(RecursorTest):
     # -AD +CD +DO
     ##
     def testOff_Insecure_DOCD(self):
-        msg = self.getQueryForInsecure('CD', 'DO')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForInsecure("CD", "DO")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcessNoValidate_Insecure_DOCD(self):
-        msg = self.getQueryForInsecure('CD', 'DO')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForInsecure("CD", "DO")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcess_Insecure_DOCD(self):
-        msg = self.getQueryForInsecure('CD', 'DO')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForInsecure("CD", "DO")
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testValidate_Insecure_DOCD(self):
-        msg = self.getQueryForInsecure('CD', 'DO')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForInsecure("CD", "DO")
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"], ["DO"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
@@ -783,33 +810,33 @@ class FlagsTest(RecursorTest):
     # -AD +CD -DO
     ##
     def testOff_Insecure_CD(self):
-        msg = self.getQueryForInsecure('CD')
-        res = self.sendUDPQuery(msg, 'off')
+        msg = self.getQueryForInsecure("CD")
+        res = self.sendUDPQuery(msg, "off")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcessNoValidate_Insecure_CD(self):
-        msg = self.getQueryForInsecure('CD')
-        res = self.sendUDPQuery(msg, 'process-no-validate')
+        msg = self.getQueryForInsecure("CD")
+        res = self.sendUDPQuery(msg, "process-no-validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testProcess_Insecure_CD(self):
-        msg = self.getQueryForInsecure('CD')
-        res = self.sendUDPQuery(msg, 'process')
+        msg = self.getQueryForInsecure("CD")
+        res = self.sendUDPQuery(msg, "process")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testValidate_Insecure_CD(self):
-        msg = self.getQueryForInsecure('CD')
-        res = self.sendUDPQuery(msg, 'validate')
+        msg = self.getQueryForInsecure("CD")
+        res = self.sendUDPQuery(msg, "validate")
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"])
         self.assertNoRRSIGsInAnswer(res)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
index a2fc8671ac110d8d248908e416a5cbd027f111bd..fb70f1083b9f06f39c4f3c8f09742ca5e82e495c 100644 (file)
@@ -4,12 +4,13 @@ import os
 import subprocess
 from recursortests import RecursorTest
 
+
 class SimpleForwardOverDoTTest(RecursorTest):
     """
     This is forwarding to DoT servers in a very basic way and is dependent on the forwards working for DoT
     """
 
-    _confdir = 'SimpleForwardOverDoT'
+    _confdir = "SimpleForwardOverDoT"
     _config_template = """
 dnssec:
     validation: validate
@@ -28,18 +29,18 @@ outgoing:
         super(SimpleForwardOverDoTTest, cls).generateRecursorYamlConfig(confdir, False)
 
     def reloadConfig(self, config):
-      confdir = os.path.join('configs', SimpleForwardOverDoTTest._confdir)
-      SimpleForwardOverDoTTest._config_template = config
-      SimpleForwardOverDoTTest.generateRecursorYamlConfig(confdir, False)
-      SimpleForwardOverDoTTest.recControl(confdir, 'reload-yaml')
+        confdir = os.path.join("configs", SimpleForwardOverDoTTest._confdir)
+        SimpleForwardOverDoTTest._config_template = config
+        SimpleForwardOverDoTTest.generateRecursorYamlConfig(confdir, False)
+        SimpleForwardOverDoTTest.recControl(confdir, "reload-yaml")
 
     @pytest.mark.external
     def testBasic(self):
-        confdir = 'configs/' + self._confdir
+        confdir = "configs/" + self._confdir
         self.reloadConfig(self._config_template)
-        self.recControl(confdir, 'reload-zones')
-        expected = dns.rrset.from_text('dns.google.', 0, dns.rdataclass.IN, 'A', '8.8.8.8', '8.8.4.4')
-        query = dns.message.make_query('dns.google', 'A', want_dnssec=True)
+        self.recControl(confdir, "reload-zones")
+        expected = dns.rrset.from_text("dns.google.", 0, dns.rdataclass.IN, "A", "8.8.8.8", "8.8.4.4")
+        query = dns.message.make_query("dns.google", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
@@ -48,12 +49,12 @@ outgoing:
         self.assertRRsetInAnswer(res, expected)
         self.assertMatchingRRSIGInAnswer(res, expected)
 
-        ret = self.recControl(confdir, 'get', 'dot-outqueries')
-        self.assertNotEqual(ret, 'UNKNOWN\n')
-        self.assertNotEqual(ret, '0\n')
+        ret = self.recControl(confdir, "get", "dot-outqueries")
+        self.assertNotEqual(ret, "UNKNOWN\n")
+        self.assertNotEqual(ret, "0\n")
 
-        ret = self.recControl(confdir, 'get', 'tcp-outqueries')
-        self.assertEqual(ret, '0\n')
+        ret = self.recControl(confdir, "get", "tcp-outqueries")
+        self.assertEqual(ret, "0\n")
 
     _config_template_test2 = """
 dnssec:
@@ -80,11 +81,11 @@ recursor:
 
     @pytest.mark.external
     def testWithVerify(self):
-        confdir = 'configs/' + self._confdir
+        confdir = "configs/" + self._confdir
         self.reloadConfig(self._config_template_test2)
-        self.recControl(confdir, 'reload-zones')
-        expected = dns.rrset.from_text('dns.google.', 0, dns.rdataclass.IN, 'A', '8.8.8.8', '8.8.4.4')
-        query = dns.message.make_query('dns.google', 'A', want_dnssec=True)
+        self.recControl(confdir, "reload-zones")
+        expected = dns.rrset.from_text("dns.google.", 0, dns.rdataclass.IN, "A", "8.8.8.8", "8.8.4.4")
+        query = dns.message.make_query("dns.google", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
@@ -93,12 +94,12 @@ recursor:
         self.assertRRsetInAnswer(res, expected)
         self.assertMatchingRRSIGInAnswer(res, expected)
 
-        ret = self.recControl(confdir, 'get', 'dot-outqueries')
-        self.assertNotEqual(ret, 'UNKNOWN\n')
-        self.assertNotEqual(ret, '0\n')
+        ret = self.recControl(confdir, "get", "dot-outqueries")
+        self.assertNotEqual(ret, "UNKNOWN\n")
+        self.assertNotEqual(ret, "0\n")
 
-        ret = self.recControl(confdir, 'get', 'tcp-outqueries')
-        self.assertEqual(ret, '0\n')
+        ret = self.recControl(confdir, "get", "tcp-outqueries")
+        self.assertEqual(ret, "0\n")
 
     _config_template_test3 = """
 dnssec:
@@ -126,11 +127,11 @@ recursor:
 
     @pytest.mark.external
     def testCertFailed(self):
-        confdir = 'configs/' + self._confdir
+        confdir = "configs/" + self._confdir
         self.reloadConfig(self._config_template_test3)
-        self.recControl(confdir, 'reload-zones')
-        expected = dns.rrset.from_text('dns.google.', 0, dns.rdataclass.IN, 'A', '8.8.8.8', '8.8.4.4')
-        query = dns.message.make_query('dns.google', 'A', want_dnssec=True)
+        self.recControl(confdir, "reload-zones")
+        expected = dns.rrset.from_text("dns.google.", 0, dns.rdataclass.IN, "A", "8.8.8.8", "8.8.4.4")
+        query = dns.message.make_query("dns.google", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
index 36b582ce1cb75513cfde5344a26ecde0f4d84b02..799af4215d2fa2cac48bf89bd4d70b4464053d0c 100644 (file)
@@ -4,24 +4,25 @@ from recursortests import RecursorTest
 from twisted.internet.protocol import DatagramProtocol
 from twisted.internet import reactor
 
+
 class InteropTest(RecursorTest):
-    _confdir = 'Interop'
+    _confdir = "Interop"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """dnssec=validate
 packetcache-ttl=0 # explicitly disable packetcache
 forward-zones=undelegated.secure.example=%s.12
 forward-zones+=undelegated.insecure.example=%s.12
-    """ % (os.environ['PREFIX'], os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"], os.environ["PREFIX"])
 
     def testFORMERR(self):
         """
         #3841, when we encounter a server that does not understands OPT records
         (or something else), we don't retry without EDNS in dnssec=validate mode
         """
-        expected = dns.rrset.from_text('host1.insecure-formerr.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        expected = dns.rrset.from_text("host1.insecure-formerr.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
 
-        query = dns.message.make_query('cname-to-formerr.secure.example.', 'A')
+        query = dns.message.make_query("cname-to-formerr.secure.example.", "A")
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -31,14 +32,14 @@ forward-zones+=undelegated.insecure.example=%s.12
         """
         #4158, When chasing down for DS/DNSKEY and we find a CNAME, skip a level
         """
-        expected = dns.rrset.from_text('node1.insecure.sub2.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.18')
+        expected = dns.rrset.from_text("node1.insecure.sub2.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.18")
 
-        query = dns.message.make_query('node1.insecure.sub2.secure.example.', 'A')
+        query = dns.message.make_query("node1.insecure.sub2.secure.example.", "A")
         query.flags |= dns.flags.AD
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], [])
         self.assertRRsetInAnswer(res, expected)
 
     def testUndelegatedForwardedZoneExisting(self):
@@ -46,7 +47,7 @@ forward-zones+=undelegated.insecure.example=%s.12
         #4369. Ensure we SERVFAIL when forwarding to undelegated zones for a name that exists
         """
 
-        query = dns.message.make_query('node1.undelegated.secure.example.', 'A')
+        query = dns.message.make_query("node1.undelegated.secure.example.", "A")
         query.flags |= dns.flags.AD
 
         # twice, so we hit the record cache
@@ -54,14 +55,14 @@ forward-zones+=undelegated.insecure.example=%s.12
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], [])
 
     def testUndelegatedForwardedZoneNXDOMAIN(self):
         """
         #4369. Ensure we SERVFAIL when forwarding to undelegated zones for a name that does not exist
         """
 
-        query = dns.message.make_query('node2.undelegated.secure.example.', 'A')
+        query = dns.message.make_query("node2.undelegated.secure.example.", "A")
         query.flags |= dns.flags.AD
 
         # twice, so we hit the negative record cache
@@ -69,15 +70,15 @@ forward-zones+=undelegated.insecure.example=%s.12
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], [])
 
     def testUndelegatedForwardedInsecureZoneExisting(self):
         """
         #4369. Ensure we answer when forwarding to an undelegated zone in an insecure zone for a name that exists
         """
 
-        expected = dns.rrset.from_text('node1.undelegated.insecure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.22')
-        query = dns.message.make_query('node1.undelegated.insecure.example.', 'A')
+        expected = dns.rrset.from_text("node1.undelegated.insecure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.22")
+        query = dns.message.make_query("node1.undelegated.insecure.example.", "A")
         query.flags |= dns.flags.AD
 
         # twice, so we hit the record cache
@@ -85,7 +86,7 @@ forward-zones+=undelegated.insecure.example=%s.12
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], [])
         self.assertRRsetInAnswer(res, expected)
 
     def testUndelegatedForwardedInsecureZoneNXDOMAIN(self):
@@ -93,7 +94,7 @@ forward-zones+=undelegated.insecure.example=%s.12
         #4369. Ensure we answer when forwarding to an undelegated zone in an insecure zone for a name that does not exist
         """
 
-        query = dns.message.make_query('node2.undelegated.insecure.example.', 'A')
+        query = dns.message.make_query("node2.undelegated.insecure.example.", "A")
         query.flags |= dns.flags.AD
 
         # twice, so we hit the negative record cache
@@ -101,46 +102,51 @@ forward-zones+=undelegated.insecure.example=%s.12
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], [])
 
     def testBothSecureCNAMEAtApex(self):
         """
         #4466: a CNAME at the apex of a secure domain to another secure domain made us use the wrong DNSKEY to validate
         """
-        query = dns.message.make_query('cname-secure.example.', 'A')
+        query = dns.message.make_query("cname-secure.example.", "A")
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
-        expectedCNAME = dns.rrset.from_text('cname-secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'secure.example.')
-        expectedA = dns.rrset.from_text('secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.17')
+        expectedCNAME = dns.rrset.from_text("cname-secure.example.", 0, dns.rdataclass.IN, "CNAME", "secure.example.")
+        expectedA = dns.rrset.from_text("secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.17")
 
         self.assertRRsetInAnswer(res, expectedA)
         self.assertRRsetInAnswer(res, expectedCNAME)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'AD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA", "AD"], [])
 
     def testNonApexDNSKEY(self):
         """
         a DNSKEY not at the apex of a zone should not be treated as a DNSKEY in validation
         """
-        query = dns.message.make_query('non-apex-dnskey.secure.example.', 'DNSKEY')
+        query = dns.message.make_query("non-apex-dnskey.secure.example.", "DNSKEY")
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
         print(res)
-        expectedDNSKEY = dns.rrset.from_text('non-apex-dnskey.secure.example.', 0, dns.rdataclass.IN, 'DNSKEY', '257 3 13 CT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==')
+        expectedDNSKEY = dns.rrset.from_text(
+            "non-apex-dnskey.secure.example.",
+            0,
+            dns.rdataclass.IN,
+            "DNSKEY",
+            "257 3 13 CT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==",
+        )
 
         self.assertRRsetInAnswer(res, expectedDNSKEY)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'AD'], [])
-
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA", "AD"], [])
 
     @classmethod
     def startResponders(cls):
         global interopReactorRunning
         print("Launching responders..")
 
-        address = cls._PREFIX + '.2'
+        address = cls._PREFIX + ".2"
         port = 53
 
         if not interopReactorRunning:
@@ -149,24 +155,26 @@ forward-zones+=undelegated.insecure.example=%s.12
 
         cls.startReactor()
 
+
 interopReactorRunning = False
 
+
 class InteropProcessTest(RecursorTest):
-    _confdir = 'InteropProcess'
+    _confdir = "InteropProcess"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """dnssec=process
 packetcache-ttl=0 # explicitly disable packetcache
 forward-zones=undelegated.secure.example=%s.12
 forward-zones+=undelegated.insecure.example=%s.12
-    """ % (os.environ['PREFIX'], os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"], os.environ["PREFIX"])
 
     @classmethod
     def startResponders(cls):
         global interopReactorRunning
         print("Launching responders..")
 
-        address = cls._PREFIX + '.2'
+        address = cls._PREFIX + ".2"
         port = 53
 
         if not interopReactorRunning:
@@ -180,28 +188,40 @@ forward-zones+=undelegated.insecure.example=%s.12
         """
 
         # send the query with +CD so the record ends up cached with Indeterminate validation state
-        query = dns.message.make_query('non-apex-dnskey2.secure.example.', 'DNSKEY')
+        query = dns.message.make_query("non-apex-dnskey2.secure.example.", "DNSKEY")
         query.flags |= dns.flags.CD
 
         res = self.sendUDPQuery(query)
         print(res)
-        expectedDNSKEY = dns.rrset.from_text('non-apex-dnskey2.secure.example.', 0, dns.rdataclass.IN, 'DNSKEY', '256 3 13 CT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==')
+        expectedDNSKEY = dns.rrset.from_text(
+            "non-apex-dnskey2.secure.example.",
+            0,
+            dns.rdataclass.IN,
+            "DNSKEY",
+            "256 3 13 CT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==",
+        )
 
         self.assertRRsetInAnswer(res, expectedDNSKEY)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'CD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA", "CD"], [])
 
         # now ask again with +AD so it has to be validated from cache
-        query = dns.message.make_query('non-apex-dnskey2.secure.example.', 'DNSKEY')
+        query = dns.message.make_query("non-apex-dnskey2.secure.example.", "DNSKEY")
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
         print(res)
-        expectedDNSKEY = dns.rrset.from_text('non-apex-dnskey2.secure.example.', 0, dns.rdataclass.IN, 'DNSKEY', '256 3 13 CT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==')
+        expectedDNSKEY = dns.rrset.from_text(
+            "non-apex-dnskey2.secure.example.",
+            0,
+            dns.rdataclass.IN,
+            "DNSKEY",
+            "256 3 13 CT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==",
+        )
 
         self.assertRRsetInAnswer(res, expectedDNSKEY)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'AD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA", "AD"], [])
 
     def testNonApexDNSKEYANYQuery(self):
         """
@@ -211,28 +231,41 @@ forward-zones+=undelegated.insecure.example=%s.12
         """
 
         # send the query with +CD so the record ends up cached with Indeterminate validation state
-        query = dns.message.make_query('non-apex-dnskey3.secure.example.', 'DNSKEY')
+        query = dns.message.make_query("non-apex-dnskey3.secure.example.", "DNSKEY")
         query.flags |= dns.flags.CD
 
         res = self.sendUDPQuery(query)
         print(res)
-        expectedDNSKEY = dns.rrset.from_text('non-apex-dnskey3.secure.example.', 0, dns.rdataclass.IN, 'DNSKEY', '256 3 13 DT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==')
+        expectedDNSKEY = dns.rrset.from_text(
+            "non-apex-dnskey3.secure.example.",
+            0,
+            dns.rdataclass.IN,
+            "DNSKEY",
+            "256 3 13 DT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==",
+        )
 
         self.assertRRsetInAnswer(res, expectedDNSKEY)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'CD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA", "CD"], [])
 
         # now ask again with +AD so it has to be validated from cache
-        query = dns.message.make_query('non-apex-dnskey3.secure.example.', 'ANY')
+        query = dns.message.make_query("non-apex-dnskey3.secure.example.", "ANY")
         query.flags |= dns.flags.AD
 
         res = self.sendTCPQuery(query)
         print(res)
-        expectedDNSKEY = dns.rrset.from_text('non-apex-dnskey3.secure.example.', 0, dns.rdataclass.IN, 'DNSKEY', '256 3 13 DT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==')
+        expectedDNSKEY = dns.rrset.from_text(
+            "non-apex-dnskey3.secure.example.",
+            0,
+            dns.rdataclass.IN,
+            "DNSKEY",
+            "256 3 13 DT6AJ4MEOtNDgj0+xLtTLGHf1WbLsKWZI8ONHOt/6q7hTjeWSnY/SGig1dIKZrHg+pJFUSPaxeShv48SYVRKEg==",
+        )
 
         self.assertRRsetInAnswer(res, expectedDNSKEY)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'AD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RD", "RA", "AD"], [])
+
 
 class UDPResponder(DatagramProtocol):
     def datagramReceived(self, datagram, address):
@@ -247,13 +280,23 @@ class UDPResponder(DatagramProtocol):
 
             response.additional = []
         else:
-            if request.question[0].name == dns.name.from_text('host1.insecure-formerr.example.') and request.question[0].rdtype == dns.rdatatype.A:
-                answer = dns.rrset.from_text('host1.insecure-formerr.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+            if (
+                request.question[0].name == dns.name.from_text("host1.insecure-formerr.example.")
+                and request.question[0].rdtype == dns.rdatatype.A
+            ):
+                answer = dns.rrset.from_text("host1.insecure-formerr.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
                 response.answer.append(answer)
-            elif request.question[0].name == dns.name.from_text('insecure-formerr.example.') and request.question[0].rdtype == dns.rdatatype.NS:
-                answer = dns.rrset.from_text('insecure-formerr.example.', 15, dns.rdataclass.IN, 'NS', 'ns1.insecure-formerr.example.')
+            elif (
+                request.question[0].name == dns.name.from_text("insecure-formerr.example.")
+                and request.question[0].rdtype == dns.rdatatype.NS
+            ):
+                answer = dns.rrset.from_text(
+                    "insecure-formerr.example.", 15, dns.rdataclass.IN, "NS", "ns1.insecure-formerr.example."
+                )
                 response.answer.append(answer)
-                additional = dns.rrset.from_text('ns1.insecure-formerr.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.2')
+                additional = dns.rrset.from_text(
+                    "ns1.insecure-formerr.example.", 15, dns.rdataclass.IN, "A", "127.0.0.2"
+                )
                 response.additional.append(additional)
 
         self.transport.write(response.to_wire(), address)
index 26a3307fa368e612f3d16b5d7864a8e1d04c09fe..a128ad24d674a11276f4e935e6c13f9ce48032df 100644 (file)
@@ -5,23 +5,29 @@ import struct
 
 from recursortests import RecursorTest
 
+
 class KeepOpenTCPTest(RecursorTest):
-    _confdir = 'KeepOpenTCP'
+    _confdir = "KeepOpenTCP"
     _auth_zones = RecursorTest._default_auth_zones
 
-    _config_template = """dnssec=validate
+    _config_template = (
+        """dnssec=validate
 packetcache-ttl=10
 packetcache-servfail-ttl=10
-auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
+auth-zones=authzone.example=configs/%s/authzone.zone"""
+        % _confdir
+    )
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'authzone.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN authzone.example.
+        authzonepath = os.path.join(confdir, "authzone.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN authzone.example.
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(KeepOpenTCPTest, cls).generateRecursorConfig(confdir)
 
     def sendTCPQueryKeepOpen(cls, sock, query, timeout=2.0):
@@ -48,8 +54,10 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
     def testNoTrailingData(self):
         count = 10
         sock = [None] * count
-        expected = dns.rrset.from_text('ns.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.9'.format(prefix=self._PREFIX))
-        query = dns.message.make_query('ns.secure.example', 'A', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "ns.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.9".format(prefix=self._PREFIX)
+        )
+        query = dns.message.make_query("ns.secure.example", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
         for i in range(count):
             sock[i] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -81,4 +89,3 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
                 print("ok")
         for i in range(count):
             sock[i].close()
-
index c17c6d20197c5100772f386f9ee29482b70b2616..13ae94ac4623c7a4036a9012050c62a21897dd2d 100644 (file)
@@ -5,11 +5,13 @@ import time
 
 from recursortests import RecursorTest
 
+
 class LockedCacheTest(RecursorTest):
     """
     Test that a locked cached entry is *not* updated by the same additional encountered in a second query
     """
-    _confdir = 'LockedCache'
+
+    _confdir = "LockedCache"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """
@@ -18,29 +20,29 @@ class LockedCacheTest(RecursorTest):
     """
 
     def getCacheTTL(self):
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'dump-cache',
-                          '-']
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % "configs/" + self._confdir, "dump-cache", "-"]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT, text=True)
             for i in ret.splitlines():
-                pieces = i.split(' ')
+                pieces = i.split(" ")
                 print(pieces)
-                if pieces[0] == 'mx1.secure.example.' and pieces[4] == 'A':
+                if pieces[0] == "mx1.secure.example." and pieces[4] == "A":
                     return pieces[2]
-            raise AssertionError("Cache Line not found");
-
+            raise AssertionError("Cache Line not found")
         except subprocess.CalledProcessError as e:
             print(e.output)
             raise
 
     def testMX(self):
-        expected1 = dns.rrset.from_text('secure.example.', 0, dns.rdataclass.IN, 'MX', '10 mx1.secure.example.', '20 mx2.secure.example.')
-        expected2 = dns.rrset.from_text('sub.secure.example.', 0, dns.rdataclass.IN, 'MX', '10 mx1.secure.example.', '20 mx2.secure.example.')
-        query1 = dns.message.make_query('secure.example', 'MX', want_dnssec=True)
+        expected1 = dns.rrset.from_text(
+            "secure.example.", 0, dns.rdataclass.IN, "MX", "10 mx1.secure.example.", "20 mx2.secure.example."
+        )
+        expected2 = dns.rrset.from_text(
+            "sub.secure.example.", 0, dns.rdataclass.IN, "MX", "10 mx1.secure.example.", "20 mx2.secure.example."
+        )
+        query1 = dns.message.make_query("secure.example", "MX", want_dnssec=True)
         query1.flags |= dns.flags.AD
-        query2 = dns.message.make_query('sub.secure.example', 'MX', want_dnssec=True)
+        query2 = dns.message.make_query("sub.secure.example", "MX", want_dnssec=True)
         query2.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query1)
@@ -56,11 +58,13 @@ class LockedCacheTest(RecursorTest):
         ttl2 = self.getCacheTTL()
         self.assertGreater(ttl1, ttl2)
 
+
 class NotLockedCacheTest(RecursorTest):
     """
     Test that a not locked cached entry *is* updated by the same additional encountered in a second query
     """
-    _confdir = 'NotLockedCache'
+
+    _confdir = "NotLockedCache"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """
@@ -68,16 +72,13 @@ class NotLockedCacheTest(RecursorTest):
     """
 
     def getCacheTTL(self):
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'dump-cache',
-                          '-']
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % "configs/" + self._confdir, "dump-cache", "-"]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT, text=True)
             for i in ret.splitlines():
-                pieces = i.split(' ')
+                pieces = i.split(" ")
                 print(pieces)
-                if pieces[0] == 'mx1.secure.example.' and pieces[4] == 'A':
+                if pieces[0] == "mx1.secure.example." and pieces[4] == "A":
                     return int(pieces[2])
             return -1
 
@@ -86,11 +87,15 @@ class NotLockedCacheTest(RecursorTest):
             raise
 
     def testMX(self):
-        expected1 = dns.rrset.from_text('secure.example.', 0, dns.rdataclass.IN, 'MX', '10 mx1.secure.example.', '20 mx2.secure.example.')
-        expected2 = dns.rrset.from_text('sub.secure.example.', 0, dns.rdataclass.IN, 'MX', '10 mx1.secure.example.', '20 mx2.secure.example.')
-        query1 = dns.message.make_query('secure.example', 'MX', want_dnssec=True)
+        expected1 = dns.rrset.from_text(
+            "secure.example.", 0, dns.rdataclass.IN, "MX", "10 mx1.secure.example.", "20 mx2.secure.example."
+        )
+        expected2 = dns.rrset.from_text(
+            "sub.secure.example.", 0, dns.rdataclass.IN, "MX", "10 mx1.secure.example.", "20 mx2.secure.example."
+        )
+        query1 = dns.message.make_query("secure.example", "MX", want_dnssec=True)
         query1.flags |= dns.flags.AD
-        query2 = dns.message.make_query('sub.secure.example', 'MX', want_dnssec=True)
+        query2 = dns.message.make_query("sub.secure.example", "MX", want_dnssec=True)
         query2.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query1)
index adfd8b44bea6b73fd9d432e4ca37638080b4e3ae..78ed03f362474d0b3d1dd842a0b83e5c55b2a94c 100644 (file)
@@ -8,8 +8,9 @@ from twisted.internet import reactor
 
 from recursortests import RecursorTest
 
+
 class GettagRecursorTest(RecursorTest):
-    _confdir = 'GettagRecursor'
+    _confdir = "GettagRecursor"
     _config_template = """
     log-common-errors=yes
     gettag-needs-edns-options=yes
@@ -115,86 +116,109 @@ class GettagRecursorTest(RecursorTest):
     """
 
     def testA(self):
-        name = 'gettag.lua.'
+        name = "gettag.lua."
         expected = [
-            dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.1'),
-            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, 'TXT', [ name, 'gettag-qtype-1'])
-            ]
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.1"),
+            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, "TXT", [name, "gettag-qtype-1"]),
+        ]
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertResponseMatches(query, expected, res)
 
     def testTCPA(self):
-        name = 'gettag-tcpa.lua.'
+        name = "gettag-tcpa.lua."
         expected = [
-            dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.1'),
-            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, 'TXT', [ name, 'gettag-qtype-1', 'gettag-tcp'])
-            ]
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.1"),
+            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, "TXT", [name, "gettag-qtype-1", "gettag-tcp"]),
+        ]
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendTCPQuery(query)
         self.assertResponseMatches(query, expected, res)
 
     def testAAAA(self):
-        name = 'gettag-aaaa.lua.'
+        name = "gettag-aaaa.lua."
         expected = [
-            dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'AAAA', '2001:db8::1'),
-            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, 'TXT', [ name, 'gettag-qtype-28'])
-            ]
-        query = dns.message.make_query(name, 'AAAA', want_dnssec=True)
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "AAAA", "2001:db8::1"),
+            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, "TXT", [name, "gettag-qtype-28"]),
+        ]
+        query = dns.message.make_query(name, "AAAA", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertResponseMatches(query, expected, res)
 
     def testTcpAAAA(self):
-        name = 'gettag-tcpaaaa.lua.'
+        name = "gettag-tcpaaaa.lua."
         expected = [
-            dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'AAAA', '2001:db8::1'),
-            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, 'TXT', [ name, 'gettag-qtype-28', 'gettag-tcp'])
-            ]
-        query = dns.message.make_query(name, 'AAAA', want_dnssec=True)
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "AAAA", "2001:db8::1"),
+            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, "TXT", [name, "gettag-qtype-28", "gettag-tcp"]),
+        ]
+        query = dns.message.make_query(name, "AAAA", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendTCPQuery(query)
         self.assertResponseMatches(query, expected, res)
 
     def testSubnet(self):
-        name = 'gettag-subnet.lua.'
-        subnet = '192.0.2.255'
+        name = "gettag-subnet.lua."
+        subnet = "192.0.2.255"
         subnetMask = 32
         ecso = clientsubnetoption.ClientSubnetOption(subnet, subnetMask)
         expected = [
-            dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.1'),
-            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, 'TXT', [name, 'gettag-qtype-1', 'edns-subnet-' + subnet + '/' + str(subnetMask),
-                                                                         'ednsoption-8-count-1', 'ednsoption-8-total-len-8']),
-            ]
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[ecso])
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.1"),
+            dns.rrset.from_text_list(
+                name,
+                0,
+                dns.rdataclass.IN,
+                "TXT",
+                [
+                    name,
+                    "gettag-qtype-1",
+                    "edns-subnet-" + subnet + "/" + str(subnetMask),
+                    "ednsoption-8-count-1",
+                    "ednsoption-8-total-len-8",
+                ],
+            ),
+        ]
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[ecso])
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertResponseMatches(query, expected, res)
 
     def testEDNSOptions(self):
-        name = 'gettag-ednsoptions.lua.'
-        subnet = '192.0.2.255'
+        name = "gettag-ednsoptions.lua."
+        subnet = "192.0.2.255"
         subnetMask = 32
         ecso = clientsubnetoption.ClientSubnetOption(subnet, subnetMask)
-        eco1 = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        eco2 = cookiesoption.CookiesOption(b'deadc0de', b'deadc0de')
+        eco1 = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        eco2 = cookiesoption.CookiesOption(b"deadc0de", b"deadc0de")
 
         expected = [
-            dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.1'),
-            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, 'TXT', [name, 'gettag-qtype-1', 'edns-subnet-' + subnet + '/' + str(subnetMask),
-                                                                         'ednsoption-10-count-2', 'ednsoption-10-total-len-32',
-                                                                         'ednsoption-8-count-1', 'ednsoption-8-total-len-8'
-                                                                        ]),
-            ]
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[eco1,ecso,eco2])
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.1"),
+            dns.rrset.from_text_list(
+                name,
+                0,
+                dns.rdataclass.IN,
+                "TXT",
+                [
+                    name,
+                    "gettag-qtype-1",
+                    "edns-subnet-" + subnet + "/" + str(subnetMask),
+                    "ednsoption-10-count-2",
+                    "ednsoption-10-total-len-32",
+                    "ednsoption-8-count-1",
+                    "ednsoption-8-total-len-8",
+                ],
+            ),
+        ]
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[eco1, ecso, eco2])
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertResponseMatches(query, expected, res)
 
+
 class GettagRecursorDistributesQueriesTest(GettagRecursorTest):
-    _confdir = 'GettagRecursorDistributesQueries'
+    _confdir = "GettagRecursorDistributesQueries"
     _config_template = """
     log-common-errors=yes
     gettag-needs-edns-options=yes
@@ -202,42 +226,56 @@ class GettagRecursorDistributesQueriesTest(GettagRecursorTest):
     threads=2
     """
 
+
 hooksReactorRunning = False
 
-class UDPHooksResponder(DatagramProtocol):
 
+class UDPHooksResponder(DatagramProtocol):
     def datagramReceived(self, datagram, address):
         request = dns.message.from_wire(datagram)
 
         response = dns.message.make_response(request)
         response.flags |= dns.flags.AA
 
-        if request.question[0].name == dns.name.from_text('nxdomain.luahooks.example.'):
-            soa = dns.rrset.from_text('luahooks.example.', 86400, dns.rdataclass.IN, 'SOA', 'ns.luahooks.example. hostmaster.luahooks.example. 1 3600 3600 3600 1')
+        if request.question[0].name == dns.name.from_text("nxdomain.luahooks.example."):
+            soa = dns.rrset.from_text(
+                "luahooks.example.",
+                86400,
+                dns.rdataclass.IN,
+                "SOA",
+                "ns.luahooks.example. hostmaster.luahooks.example. 1 3600 3600 3600 1",
+            )
             response.authority.append(soa)
             response.set_rcode(dns.rcode.NXDOMAIN)
 
-        elif request.question[0].name == dns.name.from_text('nodata.luahooks.example.'):
-            soa = dns.rrset.from_text('luahooks.example.', 86400, dns.rdataclass.IN, 'SOA', 'ns.luahooks.example. hostmaster.luahooks.example. 1 3600 3600 3600 1')
+        elif request.question[0].name == dns.name.from_text("nodata.luahooks.example."):
+            soa = dns.rrset.from_text(
+                "luahooks.example.",
+                86400,
+                dns.rdataclass.IN,
+                "SOA",
+                "ns.luahooks.example. hostmaster.luahooks.example. 1 3600 3600 3600 1",
+            )
             response.authority.append(soa)
 
-        elif request.question[0].name == dns.name.from_text('postresolve.luahooks.example.'):
-            answer = dns.rrset.from_text('postresolve.luahooks.example.', 3600, dns.rdataclass.IN, 'A', '192.0.2.1')
+        elif request.question[0].name == dns.name.from_text("postresolve.luahooks.example."):
+            answer = dns.rrset.from_text("postresolve.luahooks.example.", 3600, dns.rdataclass.IN, "A", "192.0.2.1")
             response.answer.append(answer)
 
-        elif request.question[0].name == dns.name.from_text('preresolve.luahooks.example.'):
-            answer = dns.rrset.from_text('preresolve.luahooks.example.', 3600, dns.rdataclass.IN, 'A', '192.0.2.2')
+        elif request.question[0].name == dns.name.from_text("preresolve.luahooks.example."):
+            answer = dns.rrset.from_text("preresolve.luahooks.example.", 3600, dns.rdataclass.IN, "A", "192.0.2.2")
             response.answer.append(answer)
 
         self.transport.write(response.to_wire(), address)
 
+
 class LuaHooksRecursorTest(RecursorTest):
-    _confdir = 'LuaHooksRecursor'
+    _confdir = "LuaHooksRecursor"
     _config_template = """
 forward-zones=luahooks.example=%s.23
 log-common-errors=yes
 quiet=no
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
     _lua_dns_script_file = """
 
     allowedips = newNMG()
@@ -322,14 +360,14 @@ quiet=no
       return false
     end
 
-    """ % (os.environ['PREFIX'], os.environ['PREFIX'], os.environ['PREFIX'], os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"], os.environ["PREFIX"], os.environ["PREFIX"], os.environ["PREFIX"])
 
     @classmethod
     def startResponders(cls):
         global hooksReactorRunning
         print("Launching responders..")
 
-        address = cls._PREFIX + '.23'
+        address = cls._PREFIX + ".23"
         port = 53
 
         if not hooksReactorRunning:
@@ -339,8 +377,8 @@ quiet=no
         cls.startReactor()
 
     def testNoData(self):
-        expected = dns.rrset.from_text('nodata.luahooks.example.', 3600, dns.rdataclass.IN, 'AAAA', '2001:DB8::1')
-        query = dns.message.make_query('nodata.luahooks.example.', 'AAAA', 'IN')
+        expected = dns.rrset.from_text("nodata.luahooks.example.", 3600, dns.rdataclass.IN, "AAAA", "2001:DB8::1")
+        query = dns.message.make_query("nodata.luahooks.example.", "AAAA", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -349,8 +387,8 @@ quiet=no
             self.assertRRsetInAnswer(res, expected)
 
     def testVanillaNXD(self):
-        #expected = dns.rrset.from_text('nxdomain.luahooks.example.', 3600, dns.rdataclass.IN, 'A', '192.0.2.1')
-        query = dns.message.make_query('nxdomain.luahooks.example.', 'AAAA', 'IN')
+        # expected = dns.rrset.from_text('nxdomain.luahooks.example.', 3600, dns.rdataclass.IN, 'A', '192.0.2.1')
+        query = dns.message.make_query("nxdomain.luahooks.example.", "AAAA", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -358,8 +396,8 @@ quiet=no
             self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
 
     def testHookedNXD(self):
-        expected = dns.rrset.from_text('nxdomain.luahooks.example.', 3600, dns.rdataclass.IN, 'A', '192.0.2.1')
-        query = dns.message.make_query('nxdomain.luahooks.example.', 'A', 'IN')
+        expected = dns.rrset.from_text("nxdomain.luahooks.example.", 3600, dns.rdataclass.IN, "A", "192.0.2.1")
+        query = dns.message.make_query("nxdomain.luahooks.example.", "A", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -368,8 +406,8 @@ quiet=no
             self.assertRRsetInAnswer(res, expected)
 
     def testPostResolve(self):
-        expected = dns.rrset.from_text('postresolve.luahooks.example.', 1, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query('postresolve.luahooks.example.', 'A', 'IN')
+        expected = dns.rrset.from_text("postresolve.luahooks.example.", 1, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query("postresolve.luahooks.example.", "A", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -379,8 +417,8 @@ quiet=no
             self.assertEqual(res.answer[0].ttl, 1)
 
     def testPreResolve(self):
-        expected = dns.rrset.from_text('preresolve.luahooks.example.', 1, dns.rdataclass.IN, 'A', '192.0.2.2')
-        query = dns.message.make_query('preresolve.luahooks.example.', 'A', 'IN')
+        expected = dns.rrset.from_text("preresolve.luahooks.example.", 1, dns.rdataclass.IN, "A", "192.0.2.2")
+        query = dns.message.make_query("preresolve.luahooks.example.", "A", "IN")
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -388,7 +426,7 @@ quiet=no
             self.assertRRsetInAnswer(res, expected)
 
     def testIPFilterHeader(self):
-        query = dns.message.make_query('ipfilter.luahooks.example.', 'A', 'IN')
+        query = dns.message.make_query("ipfilter.luahooks.example.", "A", "IN")
         query.flags |= dns.flags.AD
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -397,7 +435,7 @@ quiet=no
             self.assertEqual(res, None)
 
     def testPreOutInterceptedQuery(self):
-        query = dns.message.make_query('preout.luahooks.example.', 'A', 'IN')
+        query = dns.message.make_query("preout.luahooks.example.", "A", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -405,7 +443,7 @@ quiet=no
             self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
     def testPreOutNotInterceptedQuery(self):
-        query = dns.message.make_query('preout.luahooks.example.', 'AAAA', 'IN')
+        query = dns.message.make_query("preout.luahooks.example.", "AAAA", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -413,27 +451,29 @@ quiet=no
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testPreOutInterceptedToTCPQuery(self):
-        query = dns.message.make_query('preout.luahooks.example.', 'TXT', 'IN')
+        query = dns.message.make_query("preout.luahooks.example.", "TXT", "IN")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
-            self.assertRcodeEqual(res, dns.rcode.SERVFAIL) # crude, responder does not do TCP
+            self.assertRcodeEqual(res, dns.rcode.SERVFAIL)  # crude, responder does not do TCP
+
 
 class LuaHooksRecursorDistributesTest(LuaHooksRecursorTest):
-    _confdir = 'LuaHooksRecursorDistributes'
+    _confdir = "LuaHooksRecursorDistributes"
     _config_template = """
 forward-zones=luahooks.example=%s.23
 log-common-errors=yes
 pdns-distributes-queries=yes
 threads=2
 quiet=no
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
+
 
 class LuaDNS64Test(RecursorTest):
     """Tests the dq.followupAction("getFakeAAAARecords")"""
 
-    _confdir = 'LuaDNS64'
+    _confdir = "LuaDNS64"
     _auth_zones = RecursorTest._default_auth_zones
     _config_template = """
     """
@@ -458,10 +498,8 @@ class LuaDNS64Test(RecursorTest):
     """
 
     def testAtoAAAA(self):
-        expected = [
-            dns.rrset.from_text('ns.secure.example.', 15, dns.rdataclass.IN, 'AAAA', '2001:db8:64::7f00:9')
-        ]
-        query = dns.message.make_query('ns.secure.example', 'AAAA')
+        expected = [dns.rrset.from_text("ns.secure.example.", 15, dns.rdataclass.IN, "AAAA", "2001:db8:64::7f00:9")]
+        query = dns.message.make_query("ns.secure.example", "AAAA")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -474,10 +512,12 @@ class LuaDNS64Test(RecursorTest):
 
     def testAtoCNAMEtoAAAA(self):
         expected = [
-            dns.rrset.from_text('cname-to-insecure.secure.example.', 3600, dns.rdataclass.IN, 'CNAME', 'node1.insecure.example.'),
-            dns.rrset.from_text('node1.insecure.example.', 3600, dns.rdataclass.IN, 'AAAA', '2001:db8:64::c000:206')
+            dns.rrset.from_text(
+                "cname-to-insecure.secure.example.", 3600, dns.rdataclass.IN, "CNAME", "node1.insecure.example."
+            ),
+            dns.rrset.from_text("node1.insecure.example.", 3600, dns.rdataclass.IN, "AAAA", "2001:db8:64::c000:206"),
         ]
-        query = dns.message.make_query('cname-to-insecure.secure.example.', 'AAAA')
+        query = dns.message.make_query("cname-to-insecure.secure.example.", "AAAA")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -488,14 +528,15 @@ class LuaDNS64Test(RecursorTest):
             self.assertEqual(len(res.authority), 0)
             self.assertResponseMatches(query, expected, res)
 
+
 class GettagFFIDNS64Test(RecursorTest):
     """Tests the interaction between gettag_ffi, RPZ and DNS64:
-       - gettag_ffi will intercept the query and return a NODATA
-       - the RPZ zone will match the name, but the only type is A
-       - DNS64 should kick in, generating an AAAA
+    - gettag_ffi will intercept the query and return a NODATA
+    - the RPZ zone will match the name, but the only type is A
+    - DNS64 should kick in, generating an AAAA
     """
 
-    _confdir = 'GettagFFIDNS64'
+    _confdir = "GettagFFIDNS64"
     _config_template = """
     dns64-prefix=64:ff9b::/96
     """
@@ -521,19 +562,19 @@ class GettagFFIDNS64Test(RecursorTest):
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 dns64.test.powerdns.com.zone.rpz. 60 IN A 192.0.2.42
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(GettagFFIDNS64Test, cls).generateRecursorConfig(confdir)
 
     def testAtoAAAA(self):
-        expected = [
-            dns.rrset.from_text('dns64.test.powerdns.com.', 15, dns.rdataclass.IN, 'AAAA', '64:ff9b::c000:22a')
-        ]
-        query = dns.message.make_query('dns64.test.powerdns.com.', 'AAAA')
+        expected = [dns.rrset.from_text("dns64.test.powerdns.com.", 15, dns.rdataclass.IN, "AAAA", "64:ff9b::c000:22a")]
+        query = dns.message.make_query("dns64.test.powerdns.com.", "AAAA")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -544,10 +585,11 @@ dns64.test.powerdns.com.zone.rpz. 60 IN A 192.0.2.42
             self.assertEqual(len(res.authority), 0)
             self.assertResponseMatches(query, expected, res)
 
+
 class PDNSRandomTest(RecursorTest):
     """Tests if pdnsrandom works"""
 
-    _confdir = 'PDNSRandom'
+    _confdir = "PDNSRandom"
     _config_template = """
     """
     _lua_dns_script_file = """
@@ -560,7 +602,7 @@ class PDNSRandomTest(RecursorTest):
     """
 
     def testRandom(self):
-        query = dns.message.make_query('whatever.example.', 'TXT')
+        query = dns.message.make_query("whatever.example.", "TXT")
 
         ans = set()
 
@@ -575,7 +617,7 @@ class PDNSRandomTest(RecursorTest):
 class PDNSFeaturesTest(RecursorTest):
     """Tests if pdns_features works"""
 
-    _confdir = 'PDNSFeatures'
+    _confdir = "PDNSFeatures"
     _config_template = """
     """
     _lua_dns_script_file = """
@@ -595,15 +637,16 @@ class PDNSFeaturesTest(RecursorTest):
     """
 
     def testFeatures(self):
-        query = dns.message.make_query('whatever.example.', 'TXT')
+        query = dns.message.make_query("whatever.example.", "TXT")
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
+
 class PDNSGeneratingAnswerFromGettagTest(RecursorTest):
     """Tests that we can generate answers from gettag"""
 
-    _confdir = 'PDNSGeneratingAnswerFromGettag'
+    _confdir = "PDNSGeneratingAnswerFromGettag"
     _config_template = """
     """
     _lua_dns_script_file = """
@@ -642,12 +685,12 @@ class PDNSGeneratingAnswerFromGettagTest(RecursorTest):
 
     def testGettag(self):
         expectedAnswerRecords = [
-            dns.rrset.from_text('gettag-answers.powerdns.com.', 60, dns.rdataclass.IN, 'A', '192.0.2.1'),
+            dns.rrset.from_text("gettag-answers.powerdns.com.", 60, dns.rdataclass.IN, "A", "192.0.2.1"),
         ]
         expectedAdditionalRecords = [
-            dns.rrset.from_text('not-powerdns.com.', 60, dns.rdataclass.IN, 'A', '192.0.2.2'),
+            dns.rrset.from_text("not-powerdns.com.", 60, dns.rdataclass.IN, "A", "192.0.2.2"),
         ]
-        query = dns.message.make_query('gettag-answers.powerdns.com.', 'A')
+        query = dns.message.make_query("gettag-answers.powerdns.com.", "A")
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -657,10 +700,11 @@ class PDNSGeneratingAnswerFromGettagTest(RecursorTest):
         self.assertEqual(res.answer, expectedAnswerRecords)
         self.assertEqual(res.additional, expectedAdditionalRecords)
 
+
 class PDNSValidationStatesTest(RecursorTest):
     """Tests that we have access to the validation states from Lua"""
 
-    _confdir = 'PDNSValidationStates'
+    _confdir = "PDNSValidationStates"
     _config_template = """
 dnssec=validate
 """
@@ -716,17 +760,17 @@ dnssec=validate
     """
 
     def testValidationBogus(self):
-        query = dns.message.make_query('brokendnssec.net.', 'A')
+        query = dns.message.make_query("brokendnssec.net.", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.assertEqual(len(res.answer), 0)
         self.assertEqual(len(res.authority), 0)
 
+
 class PolicyEventFilterOnFollowUpTest(RecursorTest):
-    """Tests the interaction between RPZ and followup queries (dns64, followCNAME)
-    """
+    """Tests the interaction between RPZ and followup queries (dns64, followCNAME)"""
 
-    _confdir = 'PolicyEventFilterOnFollowUp'
+    _confdir = "PolicyEventFilterOnFollowUp"
     _auth_zones = RecursorTest._default_auth_zones
     _config_template = """
     """
@@ -750,20 +794,24 @@ class PolicyEventFilterOnFollowUpTest(RecursorTest):
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 secure.example.zone.rpz. 60 IN A 192.0.2.42
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(PolicyEventFilterOnFollowUpTest, cls).generateRecursorConfig(confdir)
 
     def testA(self):
         expected = [
-            dns.rrset.from_text('policyeventfilter-followup.test.powerdns.com.', 15, dns.rdataclass.IN, 'CNAME', 'secure.example.'),
-            dns.rrset.from_text('secure.example.', 15, dns.rdataclass.IN, 'A', '192.0.2.17')
+            dns.rrset.from_text(
+                "policyeventfilter-followup.test.powerdns.com.", 15, dns.rdataclass.IN, "CNAME", "secure.example."
+            ),
+            dns.rrset.from_text("secure.example.", 15, dns.rdataclass.IN, "A", "192.0.2.17"),
         ]
-        query = dns.message.make_query('policyeventfilter-followup.test.powerdns.com.', 'A')
+        query = dns.message.make_query("policyeventfilter-followup.test.powerdns.com.", "A")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -774,11 +822,11 @@ secure.example.zone.rpz. 60 IN A 192.0.2.42
             self.assertEqual(len(res.authority), 0)
             self.assertResponseMatches(query, expected, res)
 
+
 class PolicyEventFilterOnFollowUpWithNativeDNS64Test(RecursorTest):
-    """Tests the interaction between followup queries and native dns64
-    """
+    """Tests the interaction between followup queries and native dns64"""
 
-    _confdir = 'PolicyEventFilterOnFollowUpWithNativeDNS64'
+    _confdir = "PolicyEventFilterOnFollowUpWithNativeDNS64"
     _auth_zones = RecursorTest._default_auth_zones
     _config_template = """
     dns64-prefix=1234::/96
@@ -797,11 +845,11 @@ class PolicyEventFilterOnFollowUpWithNativeDNS64Test(RecursorTest):
 
     def testAAAA(self):
         expected = [
-            dns.rrset.from_text('mx1.secure.example.', 15, dns.rdataclass.IN, 'CNAME', 'cname.secure.example.'),
-            dns.rrset.from_text('cname.secure.example.', 15, dns.rdataclass.IN, 'CNAME', ' host1.secure.example.'),
-            dns.rrset.from_text('host1.secure.example.', 15, dns.rdataclass.IN, 'AAAA', '1234::c000:202')
+            dns.rrset.from_text("mx1.secure.example.", 15, dns.rdataclass.IN, "CNAME", "cname.secure.example."),
+            dns.rrset.from_text("cname.secure.example.", 15, dns.rdataclass.IN, "CNAME", " host1.secure.example."),
+            dns.rrset.from_text("host1.secure.example.", 15, dns.rdataclass.IN, "AAAA", "1234::c000:202"),
         ]
-        query = dns.message.make_query('mx1.secure.example', 'AAAA')
+        query = dns.message.make_query("mx1.secure.example", "AAAA")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -812,10 +860,11 @@ class PolicyEventFilterOnFollowUpWithNativeDNS64Test(RecursorTest):
             self.assertEqual(len(res.authority), 0)
             self.assertResponseMatches(query, expected, res)
 
+
 class LuaPostResolveFFITest(RecursorTest):
     """Tests postresolve_ffi interface"""
 
-    _confdir = 'LuaPostResolveFFI'
+    _confdir = "LuaPostResolveFFI"
     _auth_zones = RecursorTest._default_auth_zones
     _config_template = """
     """
@@ -974,51 +1023,50 @@ end
     """
 
     def testNOACTION(self):
-        """ postresolve_ffi: test that we can do a NOACTION for a name and type combo"""
-        query = dns.message.make_query('example', 'SOA')
+        """postresolve_ffi: test that we can do a NOACTION for a name and type combo"""
+        query = dns.message.make_query("example", "SOA")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(len(res.answer), 1)
 
     def testDROP(self):
-        """ postresolve_ffi: test that we can do a DROP for a name and type combo"""
-        query = dns.message.make_query('example', 'TXT')
+        """postresolve_ffi: test that we can do a DROP for a name and type combo"""
+        query = dns.message.make_query("example", "TXT")
         res = self.sendUDPQuery(query)
         self.assertEqual(res, None)
 
     def testNXDOMAIN(self):
-        """ postresolve_ffi: test that we can return a NXDOMAIN for a name and type combo"""
-        query = dns.message.make_query('ns1.example', 'A')
+        """postresolve_ffi: test that we can return a NXDOMAIN for a name and type combo"""
+        query = dns.message.make_query("ns1.example", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertEqual(len(res.answer), 0)
 
     def testNODATA(self):
-        """ postresolve_ffi: test that we can return a NODATA for a name and type combo"""
-        query = dns.message.make_query('ns1.example', 'AAAA')
+        """postresolve_ffi: test that we can return a NODATA for a name and type combo"""
+        query = dns.message.make_query("ns1.example", "AAAA")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(len(res.answer), 0)
 
     def testTRUNCATE(self):
-        """ postresolve_ffi: test that we can return a truncated for a name and type combo"""
-        query = dns.message.make_query('ns2.example', 'A')
+        """postresolve_ffi: test that we can return a truncated for a name and type combo"""
+        query = dns.message.make_query("ns2.example", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(len(res.answer), 0)
-        self.assertMessageHasFlags(res, ['QR', 'TC', 'RD', 'RA'])
-
+        self.assertMessageHasFlags(res, ["QR", "TC", "RD", "RA"])
 
     def testModifyA(self):
         """postresolve_ffi: test that we can modify A answers"""
         expectedAnswerRecords = [
-            dns.rrset.from_text('postresolve_ffi.example.', 60, dns.rdataclass.IN, 'A', '0.1.2.3', '1.2.3.5'),
+            dns.rrset.from_text("postresolve_ffi.example.", 60, dns.rdataclass.IN, "A", "0.1.2.3", "1.2.3.5"),
         ]
         expectedAdditionalRecords = [
-            dns.rrset.from_text('add.postresolve_ffi.example.', 60, dns.rdataclass.IN, 'A', '4.5.6.7'),
+            dns.rrset.from_text("add.postresolve_ffi.example.", 60, dns.rdataclass.IN, "A", "4.5.6.7"),
         ]
 
-        query = dns.message.make_query('postresolve_ffi.example', 'A')
+        query = dns.message.make_query("postresolve_ffi.example", "A")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(len(res.answer), 1)
@@ -1030,9 +1078,11 @@ end
     def testModifyAAAA(self):
         """postresolve_ffi: test that we can modify AAAA answers"""
         expectedAnswerRecords = [
-            dns.rrset.from_text('postresolve_ffi.example.', 60, dns.rdataclass.IN, 'AAAA', '1:203:405:607:809:a0b:c0d:e0f', '::2'),
+            dns.rrset.from_text(
+                "postresolve_ffi.example.", 60, dns.rdataclass.IN, "AAAA", "1:203:405:607:809:a0b:c0d:e0f", "::2"
+            ),
         ]
-        query = dns.message.make_query('postresolve_ffi.example', 'AAAA')
+        query = dns.message.make_query("postresolve_ffi.example", "AAAA")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(len(res.answer), 1)
index e3e9850acba28c9b669f51f944647f07c6624a56..358bc5abab350528e956d6c2433b1edc19cfd0e0 100644 (file)
@@ -12,8 +12,9 @@ from recursortests import RecursorTest
 
 malformedReactorRunning = False
 
+
 class MalformedTest(RecursorTest):
-    _confdir = 'Malformed'
+    _confdir = "Malformed"
     _config_template = """
 recursor:
   forward_zones:
@@ -27,7 +28,7 @@ logging:
     common_errors: true
 outgoing:
     dont_throttle_netmasks: ['127.0.0.27']
-""" % (os.environ['PREFIX'])
+""" % (os.environ["PREFIX"])
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
@@ -39,7 +40,7 @@ outgoing:
 
         cls.startResponders()
 
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         cls.createConfigDir(confdir)
 
         cls.generateRecursorConfig(confdir)
@@ -52,7 +53,7 @@ outgoing:
         global malformedReactorRunning
         print("Launching responders..")
 
-        address1 = cls._PREFIX + '.27'
+        address1 = cls._PREFIX + ".27"
         port = 53
 
         if not malformedReactorRunning:
@@ -63,15 +64,12 @@ outgoing:
         cls.startReactor()
 
     def getCache(self, name):
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'dump-cache',
-                          '-']
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % "configs/" + self._confdir, "dump-cache", "-"]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT, text=True)
             for i in ret.splitlines():
-                pieces = i.split(' ')
-                #print(pieces)
+                pieces = i.split(" ")
+                # print(pieces)
                 if pieces[0] == name:
                     return pieces
             return []
@@ -82,8 +80,8 @@ outgoing:
 
     def testOKAnswer(self):
         # Case: rec gets a proper answer
-        query = dns.message.make_query('proper.malformed.example.', 'A')
-        expected = dns.rrset.from_text('proper.malformed.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        query = dns.message.make_query("proper.malformed.example.", "A")
+        expected = dns.rrset.from_text("proper.malformed.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -92,7 +90,7 @@ outgoing:
 
     def testQR0Answer(self):
         # Case: rec gets a QR=0 answer
-        query = dns.message.make_query('qr0.malformed.example.', 'A')
+        query = dns.message.make_query("qr0.malformed.example.", "A")
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -100,7 +98,7 @@ outgoing:
 
     def testQR0PoisonAnswer(self):
         # Case: rec gets a QR=0 answer
-        query = dns.message.make_query('qr0poison.malformed.example.', 'A')
+        query = dns.message.make_query("qr0poison.malformed.example.", "A")
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -110,14 +108,14 @@ outgoing:
 
     def testHeaderOnlyAnswer(self):
         # Case: rec gets a header-only answer
-        query = dns.message.make_query('headeronly.malformed.example.', 'A')
+        query = dns.message.make_query("headeronly.malformed.example.", "A")
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
             self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
-class UDPResponder(DatagramProtocol):
 
+class UDPResponder(DatagramProtocol):
     def question(self, datagram, tcp=False):
         request = dns.message.from_wire(datagram)
 
@@ -127,24 +125,24 @@ class UDPResponder(DatagramProtocol):
         question = request.question[0]
 
         # Case: send proper answer back
-        if question.name == dns.name.from_text('proper.malformed.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('proper.malformed.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        if question.name == dns.name.from_text("proper.malformed.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("proper.malformed.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             response.answer.append(answer)
 
         # Case: send qr=0 answer back
-        elif question.name == dns.name.from_text('qr0.malformed.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('qr0.malformed.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        elif question.name == dns.name.from_text("qr0.malformed.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("qr0.malformed.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             response.answer.append(answer)
             response.flags &= ~dns.flags.QR
 
         # Case: send qr=0 poison answer back
-        elif question.name == dns.name.from_text('qr0poison.malformed.example.') and question.rdtype == dns.rdatatype.A:
-            answer = dns.rrset.from_text('www.poision.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
+        elif question.name == dns.name.from_text("qr0poison.malformed.example.") and question.rdtype == dns.rdatatype.A:
+            answer = dns.rrset.from_text("www.poision.example.", 15, dns.rdataclass.IN, "A", "127.0.0.1")
             response.answer.append(answer)
             response.flags &= ~dns.flags.QR
 
         # Case: send header only back
-        elif dns.name.from_text('headeronly.malformed.example.') and question.rdtype == dns.rdatatype.A:
+        elif dns.name.from_text("headeronly.malformed.example.") and question.rdtype == dns.rdatatype.A:
             response.question = []
             response.use_edns(False)
         else:
@@ -155,14 +153,16 @@ class UDPResponder(DatagramProtocol):
         response = self.question(datagram)
         self.transport.write(response, address)
 
+
 class TCPResponder(Protocol):
     def dataReceived(self, data):
         handler = UDPResponder()
         response = handler.question(data[2:], True)
         length = len(response)
-        header = length.to_bytes(2, 'big')
+        header = length.to_bytes(2, "big")
         self.transport.write(header + response)
 
+
 class TCPFactory(Factory):
     def buildProtocol(self, addr):
         return TCPResponder()
index 6a09dc956449a4966a3100f8d5cae92b1c3cf07d..31d39abe1901089a36c47df53daa4bac9c000834 100644 (file)
@@ -1,8 +1,9 @@
 import dns
 from recursortests import RecursorTest
 
+
 class NTATest(RecursorTest):
-    _confdir = 'NTA'
+    _confdir = "NTA"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """dnssec=validate"""
@@ -14,32 +15,32 @@ addTA('secure.optout.example', '64215 13 1 b88284d7a8d8605c398e8942262f97b9a5a31
         """Ensure a direct query to a bogus name with an NTA is Insecure"""
 
         msg = dns.message.make_query("ted.bogus.example.", dns.rdatatype.A)
-        msg.flags = dns.flags.from_text('AD RD')
-        msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text('DO'))
+        msg.flags = dns.flags.from_text("AD RD")
+        msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text("DO"))
 
         res = self.sendUDPQuery(msg)
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testCNAMENTA(self):
         """Ensure a CNAME from a secure zone to a bogus one with an NTA is Insecure"""
         msg = dns.message.make_query("cname-to-bogus.secure.example.", dns.rdatatype.A)
-        msg.flags = dns.flags.from_text('AD RD')
-        msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text('DO'))
+        msg.flags = dns.flags.from_text("AD RD")
+        msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text("DO"))
 
         res = self.sendUDPQuery(msg)
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
     def testSecureWithNTAandDS(self):
         """#4391: when there is a TA *and* NTA configured for a name, the result must be insecure"""
         msg = dns.message.make_query("node1.secure.optout.example.", dns.rdatatype.A)
-        msg.flags = dns.flags.from_text('AD RD')
-        msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text('DO'))
+        msg.flags = dns.flags.from_text("AD RD")
+        msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text("DO"))
 
         res = self.sendUDPQuery(msg)
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
index b7975e7711b2bf1d4b09cb0f3ae4d1db5d993a7a..b4493137d3df0eda8a80eea66c00b5dbb0052a23 100644 (file)
@@ -5,12 +5,13 @@ import subprocess
 import time
 from recursortests import RecursorTest
 
+
 class NamedForwardTest(RecursorTest):
     """
     This is forwarding test using a name as target
     """
 
-    _confdir = 'NamedForward'
+    _confdir = "NamedForward"
     _config_template = """
 dnssec=validate
 forward-zones-recurse=.=dns.quad9.net;dns.google;one.one.one.one
@@ -18,8 +19,8 @@ system-resolver-ttl=10
     """
 
     def testA(self):
-        expected = dns.rrset.from_text('dns.google.', 0, dns.rdataclass.IN, 'A', '8.8.8.8', '8.8.4.4')
-        query = dns.message.make_query('dns.google', 'A', want_dnssec=True)
+        expected = dns.rrset.from_text("dns.google.", 0, dns.rdataclass.IN, "A", "8.8.8.8", "8.8.4.4")
+        query = dns.message.make_query("dns.google", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
@@ -28,13 +29,14 @@ system-resolver-ttl=10
         self.assertRRsetInAnswer(res, expected)
         self.assertMatchingRRSIGInAnswer(res, expected)
 
-@unittest.skipUnless('ENABLE_SUDO_TESTS' in os.environ, "sudo is not available")
+
+@unittest.skipUnless("ENABLE_SUDO_TESTS" in os.environ, "sudo is not available")
 class NamedForwardWithChangeTest(RecursorTest):
     """
     This is forwarding test using a name as target and a changing resolve
     """
 
-    _confdir = 'NamedForwardWithChange'
+    _confdir = "NamedForwardWithChange"
     _config_template = """
 dnssec=off
 forward-zones-recurse=.=namedforwardtest
@@ -44,25 +46,25 @@ system-resolver-ttl=1
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        subprocess.run(['sudo', 'sed', '-i', '-e', '/namedforwardtest/d', '/etc/hosts'])
-        subprocess.run(['sudo', 'sh', '-c', 'echo ' + cls._PREFIX + '.10 namedforwardtest >> /etc/hosts'])
+        subprocess.run(["sudo", "sed", "-i", "-e", "/namedforwardtest/d", "/etc/hosts"])
+        subprocess.run(["sudo", "sh", "-c", "echo " + cls._PREFIX + ".10 namedforwardtest >> /etc/hosts"])
         super(NamedForwardWithChangeTest, cls).generateRecursorConfig(confdir)
 
     def testExampleNSQuery(self):
-        query = dns.message.make_query('example', 'NS', want_dnssec=False)
+        query = dns.message.make_query("example", "NS", want_dnssec=False)
 
-        expectedNS = dns.rrset.from_text('example.', 0, 'IN', 'NS', 'ns1.example.', 'ns2.example.')
+        expectedNS = dns.rrset.from_text("example.", 0, "IN", "NS", "ns1.example.", "ns2.example.")
 
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expectedNS)
 
-        subprocess.run(['sudo', 'sed', '-i', '-e', '/namedforwardtest/d', '/etc/hosts'])
-        subprocess.run(['sudo', 'sh', '-c', 'echo ' + self._PREFIX + '.12 namedforwardtest >> /etc/hosts'])
+        subprocess.run(["sudo", "sed", "-i", "-e", "/namedforwardtest/d", "/etc/hosts"])
+        subprocess.run(["sudo", "sh", "-c", "echo " + self._PREFIX + ".12 namedforwardtest >> /etc/hosts"])
 
         # the change should get picked up by the system resolver update thread and the reload flushes the caches
         time.sleep(2)
         res = self.sendUDPQuery(query)
-        subprocess.run(['sudo', 'sed', '-i', '-e', '/namedforwardtest/d', '/etc/hosts'])
+        subprocess.run(["sudo", "sed", "-i", "-e", "/namedforwardtest/d", "/etc/hosts"])
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
index 9cefed81bfe691c642ceaa07f03bf298de8432ac..9305434f870d6f2d5fdb644ba3d0581078193830 100644 (file)
@@ -3,7 +3,7 @@ from recursortests import RecursorTest
 
 
 class NoDSTest(RecursorTest):
-    _confdir = 'NoDS'
+    _confdir = "NoDS"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """dnssec=validate"""
@@ -13,10 +13,10 @@ class NoDSTest(RecursorTest):
         """#4430 When the root DS is removed, the result must be Insecure"""
 
         msg = dns.message.make_query("ted.bogus.example.", dns.rdatatype.A)
-        msg.flags = dns.flags.from_text('AD RD')
-        msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text('DO'))
+        msg.flags = dns.flags.from_text("AD RD")
+        msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text("DO"))
 
         res = self.sendUDPQuery(msg)
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
index b5561ba25cad1e4220f09c1b7ab614f6626f7e76..dea62e113b09b2c2cfe6e3df6e7c5ff817742293 100644 (file)
@@ -1,8 +1,9 @@
 import dns
 from recursortests import RecursorTest
 
+
 class NoDSYAMLTest(RecursorTest):
-    _confdir = 'NoDSYAML'
+    _confdir = "NoDSYAML"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """
@@ -10,6 +11,7 @@ dnssec:
   validation: validate
   trustanchors: [{name: .}]
 """
+
     @classmethod
     def generateRecursorConfig(cls, confdir):
         super(NoDSYAMLTest, cls).generateRecursorYamlConfig(confdir, False)
@@ -18,10 +20,10 @@ dnssec:
         """#4430 When the root DS is removed, the result must be Insecure"""
 
         msg = dns.message.make_query("ted.bogus.example.", dns.rdatatype.A)
-        msg.flags = dns.flags.from_text('AD RD')
-        msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text('DO'))
+        msg.flags = dns.flags.from_text("AD RD")
+        msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text("DO"))
 
         res = self.sendUDPQuery(msg)
 
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], ["DO"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
index 4a57b4c3cbd21020f92e706c8f52eb3c67cce316..7afc754c192b5e2515f39c53c54197bf3f2d95d7 100644 (file)
@@ -10,12 +10,12 @@ class NotYetValidTest(RecursorTest):
     set 15 days into the future. Hence, the recursor must reject the signatures
     because they are not yet valid.
     """
-    _confdir = 'NotYetValid'
+
+    _confdir = "NotYetValid"
 
     _config_template = """dnssec=validate"""
 
-    _auth_env = {'LD_PRELOAD':os.environ.get('LIBFAKETIME'),
-                 'FAKETIME':'+15d'}
+    _auth_env = {"LD_PRELOAD": os.environ.get("LIBFAKETIME"), "FAKETIME": "+15d"}
 
     @classmethod
     def setUpClass(cls):
@@ -24,12 +24,12 @@ class NotYetValidTest(RecursorTest):
 
     @classmethod
     def tearDownClass(cls):
-        confdir = os.path.join('configs', 'auths')
+        confdir = os.path.join("configs", "auths")
         print("Specialized auth teardown " + confdir)
         # tear down specialized auths, and then start standard ones
         super().tearDownClass(True)
         print("Starting default auths")
-        #confdir = 'configs/auths'
+        # confdir = 'configs/auths'
         shutil.rmtree(confdir, True)
         os.mkdir(confdir)
         # Be careful here, we don't want the overridden secureZone(), so call RecursorTest explicitly
@@ -37,7 +37,7 @@ class NotYetValidTest(RecursorTest):
         RecursorTest.startAllAuth(confdir)
 
     def testA(self):
-        query = dns.message.make_query('host1.secure.example', 'A')
+        query = dns.message.make_query("host1.secure.example", "A")
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
index ed1e4188afc1cfda49997471c149a22d37e6248f..8fd99ca81478ba983748ce3a1ab5c6bad4ceaa84 100644 (file)
@@ -4,13 +4,13 @@ import requests
 
 from recursortests import RecursorTest
 
-class NotifyTest(RecursorTest):
 
-    _confdir = 'Notify'
+class NotifyTest(RecursorTest):
+    _confdir = "Notify"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 packetcache:
     disable: true
@@ -34,9 +34,10 @@ webservice:
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 b 3600 IN A 192.0.2.42
@@ -44,12 +45,13 @@ c 3600 IN A 192.0.2.42
 d 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
 f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an authzone
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(NotifyTest, cls).generateRecursorYamlConfig(confdir)
 
     def checkRecordCacheMetrics(self, expectedHits, expectedMisses):
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/statistics"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -58,12 +60,12 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
         foundHits = False
         foundMisses = True
         for entry in content:
-            if entry['name'] == 'cache-hits':
+            if entry["name"] == "cache-hits":
                 foundHits = True
-                self.assertEqual(int(entry['value']), expectedHits)
-            elif entry['name'] == 'cache-misses':
+                self.assertEqual(int(entry["value"]), expectedHits)
+            elif entry["name"] == "cache-misses":
                 foundMisses = True
-                self.assertEqual(int(entry['value']), expectedMisses)
+                self.assertEqual(int(entry["value"]), expectedMisses)
 
         self.assertTrue(foundHits)
         self.assertTrue(foundMisses)
@@ -71,9 +73,9 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
     def testNotify(self):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
         # first query
-        qname = 'a.example.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
+        qname = "a.example."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.42")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -95,15 +97,15 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
         self.assertRRsetInAnswer(res, expected)
         self.checkRecordCacheMetrics(3, 1)
 
-        notify = dns.message.make_query('example', 'SOA', want_dnssec=False)
-        notify.set_opcode(4) # notify
+        notify = dns.message.make_query("example", "SOA", want_dnssec=False)
+        notify.set_opcode(4)  # notify
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(notify)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertEqual(res.opcode(), 4)
             print(res)
-            self.assertEqual(res.question[0].to_text(), 'example. IN SOA')
+            self.assertEqual(res.question[0].to_text(), "example. IN SOA")
 
         self.checkRecordCacheMetrics(3, 1)
 
@@ -115,13 +117,13 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
 
         self.checkRecordCacheMetrics(4, 2)
 
-class NotifyNameNotAllowedTest(RecursorTest):
 
-    _confdir = 'NotifyNameNotAllowed'
+class NotifyNameNotAllowedTest(RecursorTest):
+    _confdir = "NotifyNameNotAllowed"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 packetcache:
     disable: true
@@ -145,9 +147,10 @@ webservice:
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 b 3600 IN A 192.0.2.42
@@ -155,12 +158,13 @@ c 3600 IN A 192.0.2.42
 d 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
 f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an authzone
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(NotifyNameNotAllowedTest, cls).generateRecursorYamlConfig(confdir)
 
     def checkRecordCacheMetrics(self, expectedHits, expectedMisses):
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/statistics"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -169,12 +173,12 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
         foundHits = False
         foundMisses = True
         for entry in content:
-            if entry['name'] == 'cache-hits':
+            if entry["name"] == "cache-hits":
                 foundHits = True
-                self.assertEqual(int(entry['value']), expectedHits)
-            elif entry['name'] == 'cache-misses':
+                self.assertEqual(int(entry["value"]), expectedHits)
+            elif entry["name"] == "cache-misses":
                 foundMisses = True
-                self.assertEqual(int(entry['value']), expectedMisses)
+                self.assertEqual(int(entry["value"]), expectedMisses)
 
         self.assertTrue(foundHits)
         self.assertTrue(foundMisses)
@@ -182,9 +186,9 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
     def testNotify(self):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
         # first query
-        qname = 'a.example.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
+        qname = "a.example."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.42")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -206,12 +210,12 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
         self.assertRRsetInAnswer(res, expected)
         self.checkRecordCacheMetrics(3, 1)
 
-        notify = dns.message.make_query('example', 'SOA', want_dnssec=False)
-        notify.set_opcode(4) # notify
+        notify = dns.message.make_query("example", "SOA", want_dnssec=False)
+        notify.set_opcode(4)  # notify
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(notify)
-            self.assertEqual(res, None);
+            self.assertEqual(res, None)
 
         self.checkRecordCacheMetrics(3, 1)
 
@@ -223,13 +227,13 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
 
         self.checkRecordCacheMetrics(5, 1)
 
-class NotifyNetNotAllowedTest(RecursorTest):
 
-    _confdir = 'NotifyNetNotAllowed'
+class NotifyNetNotAllowedTest(RecursorTest):
+    _confdir = "NotifyNetNotAllowed"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 packetcache:
     disable: true
@@ -253,9 +257,10 @@ webservice:
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 b 3600 IN A 192.0.2.42
@@ -263,12 +268,13 @@ c 3600 IN A 192.0.2.42
 d 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
 f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an authzone
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(NotifyNetNotAllowedTest, cls).generateRecursorYamlConfig(confdir)
 
     def checkRecordCacheMetrics(self, expectedHits, expectedMisses):
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/statistics"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -277,12 +283,12 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
         foundHits = False
         foundMisses = True
         for entry in content:
-            if entry['name'] == 'cache-hits':
+            if entry["name"] == "cache-hits":
                 foundHits = True
-                self.assertEqual(int(entry['value']), expectedHits)
-            elif entry['name'] == 'cache-misses':
+                self.assertEqual(int(entry["value"]), expectedHits)
+            elif entry["name"] == "cache-misses":
                 foundMisses = True
-                self.assertEqual(int(entry['value']), expectedMisses)
+                self.assertEqual(int(entry["value"]), expectedMisses)
 
         self.assertTrue(foundHits)
         self.assertTrue(foundMisses)
@@ -290,9 +296,9 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
     def testNotify(self):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
         # first query
-        qname = 'a.example.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
+        qname = "a.example."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.42")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -314,12 +320,12 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
         self.assertRRsetInAnswer(res, expected)
         self.checkRecordCacheMetrics(3, 1)
 
-        notify = dns.message.make_query('example', 'SOA', want_dnssec=False)
-        notify.set_opcode(4) # notify
+        notify = dns.message.make_query("example", "SOA", want_dnssec=False)
+        notify.set_opcode(4)  # notify
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(notify)
-            self.assertEqual(res, None);
+            self.assertEqual(res, None)
 
         self.checkRecordCacheMetrics(3, 1)
 
index e83bda1a322337dcb1a8d5033e5f91ebd5f809f9..0029d44cb4e02fe4c5b04b025780af271b4358bf 100644 (file)
@@ -2,8 +2,9 @@ import dns
 import time
 from recursortests import RecursorTest
 
+
 class OOOTCPTest(RecursorTest):
-    _confdir = 'OOOTCP'
+    _confdir = "OOOTCP"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """dnssec=validate
@@ -16,9 +17,9 @@ class OOOTCPTest(RecursorTest):
     def testOOOVeryBasic(self):
         expected = {}
         queries = []
-        for zone in ['5.delay1.example.', '0.delay2.example.']:
-            expected[zone] = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, 'TXT', 'a')
-            query = dns.message.make_query(zone, 'TXT', want_dnssec=True)
+        for zone in ["5.delay1.example.", "0.delay2.example."]:
+            expected[zone] = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, "TXT", "a")
+            query = dns.message.make_query(zone, "TXT", want_dnssec=True)
             query.flags |= dns.flags.AD
             queries.append(query)
 
@@ -27,10 +28,10 @@ class OOOTCPTest(RecursorTest):
         self.assertEqual(len(ress), len(expected))
 
         i = 0
-        for exp in [expected['0.delay2.example.'], expected['5.delay1.example.']]:
-            print('ress0')
+        for exp in [expected["0.delay2.example."], expected["5.delay1.example."]]:
+            print("ress0")
             print(ress[i].answer[0].to_text())
-            print('exp')
+            print("exp")
             print(exp.to_text())
             self.assertMessageIsAuthenticated(ress[i])
             self.assertRRsetInAnswer(ress[i], exp)
@@ -39,15 +40,15 @@ class OOOTCPTest(RecursorTest):
 
     def testOOOTimeout(self):
         queries = []
-        for zone in ['25.delay1.example.', '1.delay2.example.']:
-            query = dns.message.make_query(zone, 'TXT', want_dnssec=True)
+        for zone in ["25.delay1.example.", "1.delay2.example."]:
+            query = dns.message.make_query(zone, "TXT", want_dnssec=True)
             query.flags |= dns.flags.AD
             queries.append(query)
 
         ress = self.sendTCPQueries(queries)
 
         self.assertEqual(len(ress), 2)
-        exp = dns.rrset.from_text('1.delay2.example.', 0, dns.rdataclass.IN, 'TXT', 'a')
+        exp = dns.rrset.from_text("1.delay2.example.", 0, dns.rdataclass.IN, "TXT", "a")
         self.assertRRsetInAnswer(ress[0], exp)
         self.assertMatchingRRSIGInAnswer(ress[0], exp)
         self.assertRcodeEqual(ress[1], dns.rcode.SERVFAIL)
@@ -55,4 +56,3 @@ class OOOTCPTest(RecursorTest):
         # Let the auth timeout happen to not disturb other tests
         # this can happen if the auth is single-threaded
         time.sleep(1)
-
index f1dcc0139cbb61deefede1e00c88defa06bcf791..06b2dfd55189da7db28f76d10ab67720fd46f905 100644 (file)
@@ -7,13 +7,13 @@ import subprocess
 
 from recursortests import RecursorTest
 
-class PacketCacheTest(RecursorTest):
 
-    _confdir = 'PacketCache'
+class PacketCacheTest(RecursorTest):
+    _confdir = "PacketCache"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
     packetcache-ttl=10
     packetcache-negative-ttl=8
@@ -28,9 +28,10 @@ class PacketCacheTest(RecursorTest):
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 b 3600 IN A 192.0.2.42
@@ -38,13 +39,14 @@ c 3600 IN A 192.0.2.42
 d 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
 f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an authzone
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(PacketCacheTest, cls).generateRecursorConfig(confdir)
 
     def checkPacketCacheMetrics(self, expectedHits, expectedMisses):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/statistics"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -53,12 +55,12 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
         foundHits = False
         foundMisses = True
         for entry in content:
-            if entry['name'] == 'packetcache-hits':
+            if entry["name"] == "packetcache-hits":
                 foundHits = True
-                self.assertEqual(int(entry['value']), expectedHits)
-            elif entry['name'] == 'packetcache-misses':
+                self.assertEqual(int(entry["value"]), expectedHits)
+            elif entry["name"] == "packetcache-misses":
                 foundMisses = True
-                self.assertEqual(int(entry['value']), expectedMisses)
+                self.assertEqual(int(entry["value"]), expectedMisses)
 
         self.assertTrue(foundHits)
         self.assertTrue(foundMisses)
@@ -66,9 +68,9 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
     def testPacketCache(self):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
         # first query, no cookie
-        qname = 'a.example.'
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
+        qname = "a.example."
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.42")
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -90,41 +92,41 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
         self.assertRRsetInAnswer(res, expected)
         self.checkPacketCacheMetrics(2, 2)
 
-        eco1 = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
-        eco2 = cookiesoption.CookiesOption(b'deadc0de', b'deadc0de')
-        ecso1 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        ecso2 = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32)
+        eco1 = cookiesoption.CookiesOption(b"deadbeef", b"deadbeef")
+        eco2 = cookiesoption.CookiesOption(b"deadc0de", b"deadc0de")
+        ecso1 = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        ecso2 = clientsubnetoption.ClientSubnetOption("192.0.2.2", 32)
 
         # we add a cookie, should not match anymore
-        query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1])
+        query = dns.message.make_query(qname, "A", want_dnssec=True, options=[eco1])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
         self.checkPacketCacheMetrics(2, 3)
 
         # same cookie, should match
-        query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1])
+        query = dns.message.make_query(qname, "A", want_dnssec=True, options=[eco1])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
         self.checkPacketCacheMetrics(3, 3)
 
         # different cookie, should still match
-        query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco2])
+        query = dns.message.make_query(qname, "A", want_dnssec=True, options=[eco2])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
         self.checkPacketCacheMetrics(4, 3)
 
         # first cookie but with an ECS option, should not match
-        query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1, ecso1])
+        query = dns.message.make_query(qname, "A", want_dnssec=True, options=[eco1, ecso1])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
         self.checkPacketCacheMetrics(4, 4)
 
         # different cookie but same ECS option, should match
-        query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco2, ecso1])
+        query = dns.message.make_query(qname, "A", want_dnssec=True, options=[eco2, ecso1])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
@@ -132,42 +134,43 @@ f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an a
 
         # first cookie but different ECS option, should still match (we ignore EDNS Client Subnet
         # in the recursor's packet cache, but ECS-specific responses are not cached
-        query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1, ecso2])
+        query = dns.message.make_query(qname, "A", want_dnssec=True, options=[eco1, ecso2])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
         self.checkPacketCacheMetrics(6, 4)
 
         # NXDomain should get negative packetcache TTL (8)
-        query = dns.message.make_query('nxdomain.example.', 'A', want_dnssec=True)
+        query = dns.message.make_query("nxdomain.example.", "A", want_dnssec=True)
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.checkPacketCacheMetrics(6, 5)
 
         # NoData should get negative packetcache TTL (8)
-        query = dns.message.make_query('a.example.', 'AAAA', want_dnssec=True)
+        query = dns.message.make_query("a.example.", "AAAA", want_dnssec=True)
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.checkPacketCacheMetrics(6, 6)
 
         # ServFail should get ServFail TTL (5)
-        query = dns.message.make_query('f.example.', 'A', want_dnssec=True)
+        query = dns.message.make_query("f.example.", "A", want_dnssec=True)
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
         self.checkPacketCacheMetrics(6, 7)
 
         # We peek into the cache to check TTLs and allow TTLs to be one lower than inserted since the clock might have ticked
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'dump-cache', '-']
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % "configs/" + self._confdir, "dump-cache", "-"]
         try:
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
             self.assertTrue((b"a.example. 10 A  ; tag 0 udp\n" in ret) or (b"a.example. 9 A  ; tag 0 udp\n" in ret))
-            self.assertTrue((b"nxdomain.example. 8 A  ; tag 0 udp\n" in ret) or (b"nxdomain.example. 7 A  ; tag 0 udp\n" in ret))
-            self.assertTrue((b"a.example. 8 AAAA  ; tag 0 udp\n" in ret) or (b"a.example. 7 AAAA  ; tag 0 udp\n" in ret))
+            self.assertTrue(
+                (b"nxdomain.example. 8 A  ; tag 0 udp\n" in ret) or (b"nxdomain.example. 7 A  ; tag 0 udp\n" in ret)
+            )
+            self.assertTrue(
+                (b"a.example. 8 AAAA  ; tag 0 udp\n" in ret) or (b"a.example. 7 AAAA  ; tag 0 udp\n" in ret)
+            )
             self.assertTrue((b"f.example. 5 A  ; tag 0 udp\n" in ret) or (b"f.example. 4 A  ; tag 0 udp\n" in ret))
 
         except subprocess.CalledProcessError as e:
             print(e.output)
             raise
-
index c2947f06487759f6673ca4ff5076e2478700c584..a1c2be575fd145248054d001f978c57244e1565b 100644 (file)
@@ -3,47 +3,55 @@ import subprocess
 import pytest
 from recursortests import RecursorTest
 
+
 class RecPrometheusTest(RecursorTest):
     def checkPrometheusContentBasic(self, content):
         for line in content.splitlines():
-            if line.startswith('# HELP'):
-                tokens = line.split(' ')
+            if line.startswith("# HELP"):
+                tokens = line.split(" ")
                 self.assertGreaterEqual(len(tokens), 4)
-            elif line.startswith('# TYPE'):
-                tokens = line.split(' ')
+            elif line.startswith("# TYPE"):
+                tokens = line.split(" ")
                 self.assertEqual(len(tokens), 4)
-                self.assertIn(tokens[3], ['counter', 'gauge', 'histogram'])
-            elif not line.startswith('#'):
-                tokens = line.split(' ')
+                self.assertIn(tokens[3], ["counter", "gauge", "histogram"])
+            elif not line.startswith("#"):
+                tokens = line.split(" ")
                 self.assertEqual(len(tokens), 2)
-                if not line.startswith('pdns_recursor_'):
-                    raise AssertionError('Expecting prometheus metric to be prefixed by \'pdns_recursor_\', got: "%s"' % (line))
+                if not line.startswith("pdns_recursor_"):
+                    raise AssertionError(
+                        "Expecting prometheus metric to be prefixed by 'pdns_recursor_', got: \"%s\"" % (line)
+                    )
 
     def checkPrometheusContentPromtool(self, content):
         output = None
         try:
-            testcmd = ['promtool', 'check', 'metrics']
-            process = subprocess.Popen(testcmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
+            testcmd = ["promtool", "check", "metrics"]
+            process = subprocess.Popen(
+                testcmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True
+            )
             output = process.communicate(input=content)
         except subprocess.CalledProcessError as exc:
-            raise AssertionError('%s failed (%d): %s' % (testcmd, process.returncode, process.output))
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, process.output))
 
         # promtool may return 3 because of the "_total" suffix warnings
         if not process.returncode in [0, 3]:
-          raise AssertionError('%s failed (%d): %s' % (testcmd, process.returncode, output))
+            raise AssertionError("%s failed (%d): %s" % (testcmd, process.returncode, output))
 
         for line in output[0].splitlines():
-            if line.endswith(b"should have \"_total\" suffix"):
+            if line.endswith(b'should have "_total" suffix'):
                 continue
-            raise AssertionError('%s returned an unexpected output. Faulty line is "%s", complete content is "%s"' % (testcmd, line, output))
+            raise AssertionError(
+                '%s returned an unexpected output. Faulty line is "%s", complete content is "%s"'
+                % (testcmd, line, output)
+            )
+
 
 class BasicPrometheusTest(RecPrometheusTest):
-    _confdir = 'BasicPrometheus'
+    _confdir = "BasicPrometheus"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
 
     _lua_dns_script_file = """
     getMetric('metric_just_a_name')
@@ -62,19 +70,20 @@ api-key=%s
 
     def testPrometheus(self):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
-        url = 'http://user:' + self._wsPassword + '@127.0.0.1:' + str(self._wsPort) + '/metrics'
+        url = "http://user:" + self._wsPassword + "@127.0.0.1:" + str(self._wsPort) + "/metrics"
         r = requests.get(url, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.checkPrometheusContentBasic(r.text)
         self.checkPrometheusContentPromtool(r.content)
 
+
 class HttpsPrometheusTest(RecPrometheusTest):
-    _confdir = 'HttpsPrometheus'
+    _confdir = "HttpsPrometheus"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
 
     _config_template = """
 webservice:
@@ -95,20 +104,21 @@ webservice:
 
     def testPrometheus(self):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
-        url = 'https://user:' + self._wsPassword + '@127.0.0.1:' + str(self._wsPort) + '/metrics'
-        r = requests.get(url, timeout=self._wsTimeout, verify='ca.pem')
+        url = "https://user:" + self._wsPassword + "@127.0.0.1:" + str(self._wsPort) + "/metrics"
+        r = requests.get(url, timeout=self._wsTimeout, verify="ca.pem")
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.checkPrometheusContentBasic(r.text)
         self.checkPrometheusContentPromtool(r.content)
 
-@pytest.mark.skipif('pkcs12' not in RecursorTest.recFeatures(), reason='pkcs12 feature not available')
+
+@pytest.mark.skipif("pkcs12" not in RecursorTest.recFeatures(), reason="pkcs12 feature not available")
 class HttpsPKCS12PrometheusTest(RecPrometheusTest):
-    _confdir = 'HttpsPKCS12Prometheus'
+    _confdir = "HttpsPKCS12Prometheus"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
 
     _config_template = """
 webservice:
@@ -129,8 +139,8 @@ webservice:
 
     def testPrometheus(self):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
-        url = 'https://user:' + self._wsPassword + '@127.0.0.1:' + str(self._wsPort) + '/metrics'
-        r = requests.get(url, timeout=self._wsTimeout, verify='ca.pem')
+        url = "https://user:" + self._wsPassword + "@127.0.0.1:" + str(self._wsPort) + "/metrics"
+        r = requests.get(url, timeout=self._wsTimeout, verify="ca.pem")
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.checkPrometheusContentBasic(r.text)
index f727a37a80e19be0f4f274888800318c525bb2ee..ee995c368776ea9d0d2b7ccedb1733069985ca3e 100644 (file)
@@ -16,6 +16,7 @@ except ImportError:
 
 from recursortests import RecursorTest
 
+
 def ProtobufConnectionHandler(queue, conn):
     data = None
     while True:
@@ -31,6 +32,7 @@ def ProtobufConnectionHandler(queue, conn):
 
     conn.close()
 
+
 def ProtobufListener(queue, port):
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
@@ -46,60 +48,61 @@ def ProtobufListener(queue, port):
         while True:
             try:
                 (conn, _) = sock.accept()
-                thread = threading.Thread(name='Connection Handler',
-                                        target=ProtobufConnectionHandler,
-                                        args=[queue, conn])
+                thread = threading.Thread(
+                    name="Connection Handler", target=ProtobufConnectionHandler, args=[queue, conn]
+                )
                 thread.daemon = True
                 thread.start()
 
             except socket.error as e:
-                print('Error in protobuf socket: %s' % str(e))
+                print("Error in protobuf socket: %s" % str(e))
 
     finally:
         sock.close()
 
 
 class ProtobufServerParams:
-  def __init__(self, port):
-    self.queue = Queue()
-    self.port = port
+    def __init__(self, port):
+        self.queue = Queue()
+        self.port = port
+
 
 protobufServersParameters = [ProtobufServerParams(4243), ProtobufServerParams(4244)]
 protobufListeners = []
 for param in protobufServersParameters:
-  listener = threading.Thread(name='Protobuf Listener', target=ProtobufListener, args=[param.queue, param.port])
-  listener.daemon = True
-  listener.start()
-  protobufListeners.append(listener)
+    listener = threading.Thread(name="Protobuf Listener", target=ProtobufListener, args=[param.queue, param.port])
+    listener.daemon = True
+    listener.start()
+    protobufListeners.append(listener)
 
-class TestRecursorProtobuf(RecursorTest):
 
+class TestRecursorProtobuf(RecursorTest):
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"})
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
 
     def getFirstProtobufMessage(self, retries=10, waitTime=0.1):
         msg = None
-        #print("in getFirstProtobufMessage")
+        # print("in getFirstProtobufMessage")
         for param in protobufServersParameters:
-          failed = 0
-
-          while param.queue.empty():
-            if failed >= retries:
-              break
-            failed = failed + 1
-            #print(str(failed) + '...')
-            time.sleep(waitTime)
-
-          #print(str(failed) + ' ' + str(param.queue.empty()))
-          self.assertFalse(param.queue.empty())
-          data = param.queue.get(False)
-          self.assertTrue(data)
-          oldmsg = msg
-          msg = dnsmessage_pb2.PBDNSMessage()
-          msg.ParseFromString(data)
-          if oldmsg is not None:
-            self.assertEqual(msg, oldmsg)
+            failed = 0
+
+            while param.queue.empty():
+                if failed >= retries:
+                    break
+                failed = failed + 1
+                # print(str(failed) + '...')
+                time.sleep(waitTime)
+
+            # print(str(failed) + ' ' + str(param.queue.empty()))
+            self.assertFalse(param.queue.empty())
+            data = param.queue.get(False)
+            self.assertTrue(data)
+            oldmsg = msg
+            msg = dnsmessage_pb2.PBDNSMessage()
+            msg.ParseFromString(data)
+            if oldmsg is not None:
+                self.assertEqual(msg, oldmsg)
         return msg
 
     def emptyProtoBufQueue(self):
@@ -109,23 +112,25 @@ class TestRecursorProtobuf(RecursorTest):
 
     def checkNoRemainingMessage(self):
         for param in protobufServersParameters:
-          self.assertTrue(param.queue.empty())
+            self.assertTrue(param.queue.empty())
 
-    def checkProtobufBase(self, msg, protocol, query, initiator, normalQueryResponse=True, expectedECS=None, receivedSize=None):
+    def checkProtobufBase(
+        self, msg, protocol, query, initiator, normalQueryResponse=True, expectedECS=None, receivedSize=None
+    ):
         self.assertTrue(msg)
-        self.assertTrue(msg.HasField('timeSec'))
-        self.assertTrue(msg.HasField('socketFamily'))
+        self.assertTrue(msg.HasField("timeSec"))
+        self.assertTrue(msg.HasField("socketFamily"))
         self.assertEqual(msg.socketFamily, dnsmessage_pb2.PBDNSMessage.INET)
-        self.assertTrue(msg.HasField('from'))
-        fromvalue = getattr(msg, 'from')
+        self.assertTrue(msg.HasField("from"))
+        fromvalue = getattr(msg, "from")
         self.assertEqual(socket.inet_ntop(socket.AF_INET, fromvalue), initiator)
-        self.assertTrue(msg.HasField('socketProtocol'))
+        self.assertTrue(msg.HasField("socketProtocol"))
         self.assertEqual(msg.socketProtocol, protocol)
-        self.assertTrue(msg.HasField('messageId'))
-        self.assertTrue(msg.HasField('serverIdentity'))
-        self.assertTrue(msg.HasField('id'))
+        self.assertTrue(msg.HasField("messageId"))
+        self.assertTrue(msg.HasField("serverIdentity"))
+        self.assertTrue(msg.HasField("id"))
         self.assertEqual(msg.id, query.id)
-        self.assertTrue(msg.HasField('inBytes'))
+        self.assertTrue(msg.HasField("inBytes"))
         if normalQueryResponse:
             # compare inBytes with length of query/response
             # Note that for responses, the size we received might differ
@@ -136,86 +141,94 @@ class TestRecursorProtobuf(RecursorTest):
             else:
                 self.assertEqual(msg.inBytes, len(query.to_wire()))
         if expectedECS is not None:
-            self.assertTrue(msg.HasField('originalRequestorSubnet'))
+            self.assertTrue(msg.HasField("originalRequestorSubnet"))
             # v4 only for now
             self.assertEqual(len(msg.originalRequestorSubnet), 4)
-            self.assertEqual(socket.inet_ntop(socket.AF_INET, msg.originalRequestorSubnet), '127.0.0.1')
+            self.assertEqual(socket.inet_ntop(socket.AF_INET, msg.originalRequestorSubnet), "127.0.0.1")
 
     def checkOutgoingProtobufBase(self, msg, protocol, query, initiator, length=None, expectedECS=None):
         self.assertTrue(msg)
-        self.assertTrue(msg.HasField('timeSec'))
-        self.assertTrue(msg.HasField('socketFamily'))
+        self.assertTrue(msg.HasField("timeSec"))
+        self.assertTrue(msg.HasField("socketFamily"))
         self.assertEqual(msg.socketFamily, dnsmessage_pb2.PBDNSMessage.INET)
-        self.assertTrue(msg.HasField('socketProtocol'))
+        self.assertTrue(msg.HasField("socketProtocol"))
         self.assertEqual(msg.socketProtocol, protocol)
-        self.assertTrue(msg.HasField('messageId'))
-        self.assertTrue(msg.HasField('serverIdentity'))
-        self.assertTrue(msg.HasField('id'))
+        self.assertTrue(msg.HasField("messageId"))
+        self.assertTrue(msg.HasField("serverIdentity"))
+        self.assertTrue(msg.HasField("id"))
         self.assertNotEqual(msg.id, query.id)
-        self.assertTrue(msg.HasField('inBytes'))
+        self.assertTrue(msg.HasField("inBytes"))
         if length is not None:
-          self.assertEqual(msg.inBytes, length)
+            self.assertEqual(msg.inBytes, length)
         else:
-          # compare inBytes with length of query/response
-          self.assertEqual(msg.inBytes, len(query.to_wire()))
+            # compare inBytes with length of query/response
+            self.assertEqual(msg.inBytes, len(query.to_wire()))
         if expectedECS is not None:
-            self.assertTrue(msg.HasField('originalRequestorSubnet'))
+            self.assertTrue(msg.HasField("originalRequestorSubnet"))
             # v4 only for now
             self.assertEqual(len(msg.originalRequestorSubnet), 4)
             self.assertEqual(socket.inet_ntop(socket.AF_INET, msg.originalRequestorSubnet), expectedECS)
 
-    def checkProtobufQuery(self, msg, protocol, query, qclass, qtype, qname, initiator='127.0.0.1', to='127.0.0.1'):
+    def checkProtobufQuery(self, msg, protocol, query, qclass, qtype, qname, initiator="127.0.0.1", to="127.0.0.1"):
         self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSQueryType)
         self.checkProtobufBase(msg, protocol, query, initiator)
         # dnsdist doesn't fill the responder field for responses
         # because it doesn't keep the information around.
-        self.assertTrue(msg.HasField('to'))
+        self.assertTrue(msg.HasField("to"))
         self.assertEqual(socket.inet_ntop(socket.AF_INET, msg.to), to)
-        self.assertTrue(msg.HasField('workerId'))
-        self.assertTrue(msg.HasField('question'))
-        self.assertTrue(msg.question.HasField('qClass'))
+        self.assertTrue(msg.HasField("workerId"))
+        self.assertTrue(msg.HasField("question"))
+        self.assertTrue(msg.question.HasField("qClass"))
         self.assertEqual(msg.question.qClass, qclass)
-        self.assertTrue(msg.question.HasField('qType'))
+        self.assertTrue(msg.question.HasField("qType"))
         self.assertEqual(msg.question.qType, qtype)
-        self.assertTrue(msg.question.HasField('qName'))
+        self.assertTrue(msg.question.HasField("qName"))
         self.assertEqual(msg.question.qName, qname)
 
     # This method takes wire format values to check
     def checkProtobufHeaderFlagsAndEDNSVersion(self, msg, flags, ednsVersion):
-        self.assertTrue(msg.HasField('headerFlags'))
+        self.assertTrue(msg.HasField("headerFlags"))
         self.assertEqual(msg.headerFlags, socket.htons(flags))
-        self.assertTrue(msg.HasField('ednsVersion'))
+        self.assertTrue(msg.HasField("ednsVersion"))
         self.assertEqual(msg.ednsVersion, socket.htonl(ednsVersion))
 
-    def checkProtobufResponse(self, msg, protocol, response, initiator='127.0.0.1', receivedSize=None, vstate=dnsmessage_pb2.PBDNSMessage.VState.Indeterminate):
+    def checkProtobufResponse(
+        self,
+        msg,
+        protocol,
+        response,
+        initiator="127.0.0.1",
+        receivedSize=None,
+        vstate=dnsmessage_pb2.PBDNSMessage.VState.Indeterminate,
+    ):
         self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSResponseType)
         self.checkProtobufBase(msg, protocol, response, initiator, receivedSize=receivedSize)
-        self.assertTrue(msg.HasField('workerId'))
-        self.assertTrue(msg.HasField('packetCacheHit'))
-        self.assertTrue(msg.HasField('response'))
-        self.assertTrue(msg.response.HasField('queryTimeSec'))
-        self.assertTrue(msg.response.HasField('validationState'))
+        self.assertTrue(msg.HasField("workerId"))
+        self.assertTrue(msg.HasField("packetCacheHit"))
+        self.assertTrue(msg.HasField("response"))
+        self.assertTrue(msg.response.HasField("queryTimeSec"))
+        self.assertTrue(msg.response.HasField("validationState"))
         self.assertEqual(msg.response.validationState, vstate)
 
     def checkProtobufResponseRecord(self, record, rclass, rtype, rname, rttl, checkTTL=True):
-        self.assertTrue(record.HasField('class'))
-        self.assertEqual(getattr(record, 'class'), rclass)
-        self.assertTrue(record.HasField('type'))
+        self.assertTrue(record.HasField("class"))
+        self.assertEqual(getattr(record, "class"), rclass)
+        self.assertTrue(record.HasField("type"))
         self.assertEqual(record.type, rtype)
-        self.assertTrue(record.HasField('name'))
+        self.assertTrue(record.HasField("name"))
         self.assertEqual(record.name, rname)
-        self.assertTrue(record.HasField('ttl'))
+        self.assertTrue(record.HasField("ttl"))
         if checkTTL:
             self.assertEqual(record.ttl, rttl)
-        self.assertTrue(record.HasField('rdata'))
+        self.assertTrue(record.HasField("rdata"))
 
     def checkProtobufPolicy(self, msg, policyType, reason, trigger, hit, kind):
         self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSResponseType)
-        self.assertTrue(msg.response.HasField('appliedPolicyType'))
-        self.assertTrue(msg.response.HasField('appliedPolicy'))
-        self.assertTrue(msg.response.HasField('appliedPolicyTrigger'))
-        self.assertTrue(msg.response.HasField('appliedPolicyHit'))
-        self.assertTrue(msg.response.HasField('appliedPolicyKind'))
+        self.assertTrue(msg.response.HasField("appliedPolicyType"))
+        self.assertTrue(msg.response.HasField("appliedPolicy"))
+        self.assertTrue(msg.response.HasField("appliedPolicyTrigger"))
+        self.assertTrue(msg.response.HasField("appliedPolicyHit"))
+        self.assertTrue(msg.response.HasField("appliedPolicyKind"))
         self.assertEqual(msg.response.appliedPolicy, reason)
         self.assertEqual(msg.response.appliedPolicyType, policyType)
         self.assertEqual(msg.response.appliedPolicyTrigger, trigger)
@@ -223,74 +236,76 @@ class TestRecursorProtobuf(RecursorTest):
         self.assertEqual(msg.response.appliedPolicyKind, kind)
 
     def checkProtobufTags(self, msg, tags):
-        #print(tags)
-        #print('---')
-        #print(msg.response.tags)
+        # print(tags)
+        # print('---')
+        # print(msg.response.tags)
         self.assertEqual(len(msg.response.tags), len(tags))
         for tag in msg.response.tags:
             self.assertIn(tag, tags)
 
     def checkProtobufMetas(self, msg, metas):
-        #print(metas)
-        #print('---')
-        #print(msg.meta)
+        # print(metas)
+        # print('---')
+        # print(msg.meta)
         self.assertEqual(len(msg.meta), len(metas))
         for m in msg.meta:
-            self.assertTrue(m.HasField('key'))
-            self.assertTrue(m.HasField('value'))
+            self.assertTrue(m.HasField("key"))
+            self.assertTrue(m.HasField("value"))
             self.assertIn(m.key, metas)
-            for i in m.value.intVal :
-              self.assertIn(i, metas[m.key]['intVal'])
-            for s in m.value.stringVal :
-              self.assertIn(s, metas[m.key]['stringVal'])
-
-    def checkProtobufOutgoingQuery(self, msg, protocol, query, qclass, qtype, qname, initiator='127.0.0.1', length=None, expectedECS=None):
+            for i in m.value.intVal:
+                self.assertIn(i, metas[m.key]["intVal"])
+            for s in m.value.stringVal:
+                self.assertIn(s, metas[m.key]["stringVal"])
+
+    def checkProtobufOutgoingQuery(
+        self, msg, protocol, query, qclass, qtype, qname, initiator="127.0.0.1", length=None, expectedECS=None
+    ):
         self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSOutgoingQueryType)
         self.checkOutgoingProtobufBase(msg, protocol, query, initiator, length=length, expectedECS=expectedECS)
-        self.assertTrue(msg.HasField('to'))
-        self.assertTrue(msg.HasField('question'))
-        self.assertTrue(msg.question.HasField('qClass'))
+        self.assertTrue(msg.HasField("to"))
+        self.assertTrue(msg.HasField("question"))
+        self.assertTrue(msg.question.HasField("qClass"))
         self.assertEqual(msg.question.qClass, qclass)
-        self.assertTrue(msg.question.HasField('qType'))
+        self.assertTrue(msg.question.HasField("qType"))
         self.assertEqual(msg.question.qType, qtype)
-        self.assertTrue(msg.question.HasField('qName'))
+        self.assertTrue(msg.question.HasField("qName"))
         self.assertEqual(msg.question.qName, qname)
 
-    def checkProtobufIncomingResponse(self, msg, protocol, response, initiator='127.0.0.1', length=None):
+    def checkProtobufIncomingResponse(self, msg, protocol, response, initiator="127.0.0.1", length=None):
         self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSIncomingResponseType)
         self.checkOutgoingProtobufBase(msg, protocol, response, initiator, length=length)
-        self.assertTrue(msg.HasField('response'))
-        self.assertTrue(msg.response.HasField('rcode'))
-        self.assertTrue(msg.response.HasField('queryTimeSec'))
+        self.assertTrue(msg.HasField("response"))
+        self.assertTrue(msg.response.HasField("rcode"))
+        self.assertTrue(msg.response.HasField("queryTimeSec"))
 
-    def checkProtobufIncomingNetworkErrorResponse(self, msg, protocol, response, initiator='127.0.0.1'):
+    def checkProtobufIncomingNetworkErrorResponse(self, msg, protocol, response, initiator="127.0.0.1"):
         self.checkProtobufIncomingResponse(msg, protocol, response, initiator, length=0)
         self.assertEqual(msg.response.rcode, 65536)
 
     def checkProtobufIdentity(self, msg, requestorId, deviceId, deviceName):
-        #print(msg)
-        self.assertEqual(requestorId == '', not msg.HasField('requestorId'))
-        self.assertEqual(deviceId == b'', not msg.HasField('deviceId'))
-        self.assertEqual(deviceName == '', not msg.HasField('deviceName'))
+        # print(msg)
+        self.assertEqual(requestorId == "", not msg.HasField("requestorId"))
+        self.assertEqual(deviceId == b"", not msg.HasField("deviceId"))
+        self.assertEqual(deviceName == "", not msg.HasField("deviceName"))
         self.assertEqual(msg.requestorId, requestorId)
         self.assertEqual(msg.deviceId, deviceId)
         self.assertEqual(msg.deviceName, deviceName)
 
     def checkProtobufEDE(self, msg, ede, edeText):
-        #print(msg)
-        self.assertEqual(ede == 0, not msg.HasField('ede'))
-        self.assertEqual(edeText == '', not msg.HasField('edeText'))
+        # print(msg)
+        self.assertEqual(ede == 0, not msg.HasField("ede"))
+        self.assertEqual(edeText == "", not msg.HasField("edeText"))
         self.assertEqual(msg.ede, ede)
         self.assertEqual(msg.edeText, edeText)
 
-    def getOpenTelemetryEDNS(self, traceid=b'0123456701234567', spanid=b'01234567', flags=b'\x00'):
-      prefix = b'\x00\x00'
-      opt = dns.edns.GenericOption(65500, prefix + traceid + spanid + flags)
-      return opt
+    def getOpenTelemetryEDNS(self, traceid=b"0123456701234567", spanid=b"01234567", flags=b"\x00"):
+        prefix = b"\x00\x00"
+        opt = dns.edns.GenericOption(65500, prefix + traceid + spanid + flags)
+        return opt
 
     def checkProtobufOT(self, msg, openTelemetryData, openTelemetryTraceID):
-        self.assertEqual(openTelemetryData, msg.HasField('openTelemetryData'))
-        self.assertEqual(openTelemetryTraceID, msg.HasField('openTelemetryTraceID'))
+        self.assertEqual(openTelemetryData, msg.HasField("openTelemetryData"))
+        self.assertEqual(openTelemetryTraceID, msg.HasField("openTelemetryTraceID"))
 
     def setUp(self):
         super(TestRecursorProtobuf, self).setUp()
@@ -300,9 +315,10 @@ class TestRecursorProtobuf(RecursorTest):
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 tagged 3600 IN A 192.0.2.84
@@ -318,14 +334,16 @@ types 3600 IN SPF "v=spf1 -all"
 types 3600 IN SRV 10 20 443 a.example.
 cname 3600 IN CNAME a.example.
 
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(TestRecursorProtobuf, cls).generateRecursorConfig(confdir)
 
     @classmethod
     def generateRecursorYamlConfig(cls, confdir, flag):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 aaaa 3600 IN AAAA 2001:DB8::2
@@ -342,7 +360,8 @@ types 3600 IN SPF "v=spf1 -all"
 types 3600 IN SRV 10 20 443 a.example.
 cname 3600 IN CNAME a.example.
 
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(TestRecursorProtobuf, cls).generateRecursorYamlConfig(confdir, flag)
 
 
@@ -351,7 +370,7 @@ class ProtobufDefaultTest(TestRecursorProtobuf):
     This test makes sure that we correctly export queries and response over protobuf.
     """
 
-    _confdir = 'ProtobufDefault'
+    _confdir = "ProtobufDefault"
     _config_template = """
 recursor:
     auth_zones:
@@ -376,7 +395,7 @@ logging:
             expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, dnstype, content)
         query = dns.message.make_query(name, dnstype, want_dnssec=True, options=edns)
         query.flags |= dns.flags.CD
-        for method in ('sendUDPQuery', 'sendTCPQuery'):
+        for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
 
@@ -385,7 +404,7 @@ logging:
 
             # check the protobuf messages corresponding to the query and answer
             msg = self.getFirstProtobufMessage()
-            if method == 'sendUDPQuery':
+            if method == "sendUDPQuery":
                 protocol = dnsmessage_pb2.PBDNSMessage.UDP
             else:
                 protocol = dnsmessage_pb2.PBDNSMessage.TCP
@@ -394,7 +413,7 @@ logging:
             self.checkProtobufHeaderFlagsAndEDNSVersion(msg, 0x0110, 0x00008000)
             # then the response
             msg = self.getFirstProtobufMessage()
-            self.checkProtobufResponse(msg, protocol, res, '127.0.0.1')
+            self.checkProtobufResponse(msg, protocol, res, "127.0.0.1")
             if content is not None:
                 self.assertEqual(len(msg.response.rrs), 1)
                 rr = msg.response.rrs[0]
@@ -406,7 +425,7 @@ logging:
         #
         # again, for a PC cache hit
         #
-        for method in ('sendUDPQuery', 'sendTCPQuery'):
+        for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
 
@@ -415,7 +434,7 @@ logging:
 
             # check the protobuf messages corresponding to the UDP query and answer
             msg = self.getFirstProtobufMessage()
-            if method == 'sendUDPQuery':
+            if method == "sendUDPQuery":
                 protocol = dnsmessage_pb2.PBDNSMessage.UDP
             else:
                 protocol = dnsmessage_pb2.PBDNSMessage.TCP
@@ -424,7 +443,7 @@ logging:
             self.checkProtobufHeaderFlagsAndEDNSVersion(msg, 0x0110, 0x00008000)
             # then the response
             msg = self.getFirstProtobufMessage()
-            self.checkProtobufResponse(msg, protocol, res, '127.0.0.1')
+            self.checkProtobufResponse(msg, protocol, res, "127.0.0.1")
             if content is not None:
                 self.assertEqual(len(msg.response.rrs), 1)
                 rr = msg.response.rrs[0]
@@ -435,10 +454,10 @@ logging:
             self.checkNoRemainingMessage()
 
     def reloadConfig(self, config):
-      confdir = os.path.join('configs', ProtobufDefaultTest._confdir)
-      ProtobufDefaultTest._config_template = config
-      ProtobufDefaultTest.generateRecursorYamlConfig(confdir, False)
-      ProtobufDefaultTest.recControl(confdir, 'reload-yaml')
+        confdir = os.path.join("configs", ProtobufDefaultTest._confdir)
+        ProtobufDefaultTest._config_template = config
+        ProtobufDefaultTest.generateRecursorYamlConfig(confdir, False)
+        ProtobufDefaultTest.recControl(confdir, "reload-yaml")
 
     config_default = """
 recursor:
@@ -455,14 +474,14 @@ logging:
 
     def testADefault(self):
         self.reloadConfig(self.config_default)
-        self.runtest('a.example.', dns.rdatatype.A, '192.0.2.42', True, True)
+        self.runtest("a.example.", dns.rdatatype.A, "192.0.2.42", True, True)
 
     def testCNAMEDefault(self):
         self.reloadConfig(self.config_default)
-        name = 'cname.example.'
-        expectedCNAME = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'CNAME', 'a.example.')
-        expectedA = dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "cname.example."
+        expectedCNAME = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "CNAME", "a.example.")
+        expectedA = dns.rrset.from_text("a.example.", 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         raw = self.sendUDPQuery(query, decode=False)
         res = dns.message.from_wire(raw)
@@ -475,19 +494,18 @@ logging:
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
         # then the response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '127.0.0.1', receivedSize=len(raw))
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, "127.0.0.1", receivedSize=len(raw))
         self.assertEqual(len(msg.response.rrs), 2)
         rr = msg.response.rrs[0]
         # we don't want to check the TTL for the A record, it has been cached by the previous test
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 15, checkTTL=False)
-        self.assertEqual(rr.rdata, b'a.example.')
+        self.assertEqual(rr.rdata, b"a.example.")
         rr = msg.response.rrs[1]
-        self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, 'a.example.', 15, checkTTL=False)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, "a.example.", 15, checkTTL=False)
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         self.checkProtobufOT(msg, True, True)
         self.checkNoRemainingMessage()
 
-
     config_traceid_only = """
 recursor:
     auth_zones:
@@ -505,15 +523,15 @@ logging:
     def testATraceIDOnly(self):
         self.reloadConfig(self.config_traceid_only)
         edns = self.getOpenTelemetryEDNS()
-        self.runtest('a.example.', dns.rdatatype.A, '192.0.2.42', False, True, edns)
+        self.runtest("a.example.", dns.rdatatype.A, "192.0.2.42", False, True, edns)
 
     def testCNAMETraceIDOnly(self):
         self.reloadConfig(self.config_traceid_only)
-        name = 'cname.example.'
-        expectedCNAME = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'CNAME', 'a.example.')
-        expectedA = dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.42')
+        name = "cname.example."
+        expectedCNAME = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "CNAME", "a.example.")
+        expectedA = dns.rrset.from_text("a.example.", 0, dns.rdataclass.IN, "A", "192.0.2.42")
         edns = self.getOpenTelemetryEDNS()
-        query = dns.message.make_query(name, 'A', want_dnssec=True, options=[edns])
+        query = dns.message.make_query(name, "A", want_dnssec=True, options=[edns])
         query.flags |= dns.flags.CD
         raw = self.sendUDPQuery(query, decode=False)
         res = dns.message.from_wire(raw)
@@ -526,15 +544,15 @@ logging:
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
         # then the response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '127.0.0.1', receivedSize=len(raw))
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, "127.0.0.1", receivedSize=len(raw))
         self.assertEqual(len(msg.response.rrs), 2)
         rr = msg.response.rrs[0]
         # we don't want to check the TTL for the A record, it has been cached by the previous test
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.CNAME, name, 15, checkTTL=False)
-        self.assertEqual(rr.rdata, b'a.example.')
+        self.assertEqual(rr.rdata, b"a.example.")
         rr = msg.response.rrs[1]
-        self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, 'a.example.', 15, checkTTL=False)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, "a.example.", 15, checkTTL=False)
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         self.checkProtobufOT(msg, False, True)
         self.checkNoRemainingMessage()
 
@@ -555,12 +573,12 @@ logging:
 
     def testAOTAOnly(self):
         self.reloadConfig(self.config_otaonly)
-        self.runtest('a.example.', dns.rdatatype.A, '192.0.2.42', True, True)
+        self.runtest("a.example.", dns.rdatatype.A, "192.0.2.42", True, True)
 
     def testAAAAOTAOnly(self):
         self.reloadConfig(self.config_otaonly)
         edns = self.getOpenTelemetryEDNS()
-        self.runtest('aaaa.example.', dns.rdatatype.AAAA, '2001:db8::2', False, True, edns, socket.AF_INET6)
+        self.runtest("aaaa.example.", dns.rdatatype.AAAA, "2001:db8::2", False, True, edns, socket.AF_INET6)
 
     config_nameonly = """
 recursor:
@@ -580,12 +598,12 @@ logging:
     def testCorrectNameOnly(self):
         self.reloadConfig(self.config_nameonly)
         edns = self.getOpenTelemetryEDNS()
-        self.runtest('a.example.', dns.rdatatype.A, '192.0.2.42', True, True, edns)
+        self.runtest("a.example.", dns.rdatatype.A, "192.0.2.42", True, True, edns)
 
     def testOtherNameOnly(self):
         self.reloadConfig(self.config_nameonly)
         edns = self.getOpenTelemetryEDNS()
-        self.runtest('aaaa.example.', dns.rdatatype.AAAA, '2001:db8::2', False, True, edns, socket.AF_INET6)
+        self.runtest("aaaa.example.", dns.rdatatype.AAAA, "2001:db8::2", False, True, edns, socket.AF_INET6)
 
     config_nameandtypeonly = """
 recursor:
@@ -606,12 +624,12 @@ logging:
     def testCorrectNameAndTypeOnly(self):
         self.reloadConfig(self.config_nameandtypeonly)
         edns = self.getOpenTelemetryEDNS()
-        self.runtest('aaaa.example.', dns.rdatatype.AAAA, '2001:db8::2', True, True, edns, socket.AF_INET6)
+        self.runtest("aaaa.example.", dns.rdatatype.AAAA, "2001:db8::2", True, True, edns, socket.AF_INET6)
 
     def testCorrectNameWrongType(self):
         self.reloadConfig(self.config_nameandtypeonly)
         edns = self.getOpenTelemetryEDNS()
-        self.runtest('aaaa.example.', dns.rdatatype.A, None, False, True, edns, None)
+        self.runtest("aaaa.example.", dns.rdatatype.A, None, False, True, edns, None)
 
     config_nameandedns = """
 recursor:
@@ -631,11 +649,11 @@ logging:
     def testCorrectNameAndEDNSOnly(self):
         self.reloadConfig(self.config_nameandedns)
         edns = self.getOpenTelemetryEDNS()
-        self.runtest('aaaa.example.', dns.rdatatype.AAAA, '2001:db8::2', True, True, edns, socket.AF_INET6)
+        self.runtest("aaaa.example.", dns.rdatatype.AAAA, "2001:db8::2", True, True, edns, socket.AF_INET6)
 
     def testCorrectNameNoEDNS(self):
         self.reloadConfig(self.config_nameandedns)
-        self.runtest('aaaa.example.', dns.rdatatype.A, None, False, False, None, None)
+        self.runtest("aaaa.example.", dns.rdatatype.A, None, False, False, None, None)
 
     config_nonetmatch = """
 recursor:
@@ -652,19 +670,23 @@ logging:
 
     def testNoNetMatch(self):
         self.reloadConfig(self.config_nonetmatch)
-        self.runtest('aaaa.example.', dns.rdatatype.A, None, False, False, None, None)
+        self.runtest("aaaa.example.", dns.rdatatype.A, None, False, False, None, None)
+
 
 class ProtobufProxyMappingTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export queries and response over protobuf with a proxyMapping
     """
 
-    _confdir = 'ProtobufProxyMapping'
-    _config_template = """
+    _confdir = "ProtobufProxyMapping"
+    _config_template = (
+        """
     auth-zones=example=configs/%s/example.zone
     allow-from=3.4.5.0/24
     devonly-regression-test-mode
-    """ % _confdir
+    """
+        % _confdir
+    )
 
     _lua_config_file = """
     addProxyMapping("127.0.0.1/24", "3.4.5.6:99")
@@ -672,9 +694,9 @@ class ProtobufProxyMappingTest(TestRecursorProtobuf):
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
 
@@ -685,25 +707,29 @@ class ProtobufProxyMappingTest(TestRecursorProtobuf):
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
         # then the response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '127.0.0.1')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, "127.0.0.1")
         self.assertEqual(len(msg.response.rrs), 1)
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         self.checkNoRemainingMessage()
 
+
 class ProtobufProxyMappingLogMappedTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export queries and response over protobuf.
     """
 
-    _confdir = 'ProtobufProxyMappingLogMapped'
-    _config_template = """
+    _confdir = "ProtobufProxyMappingLogMapped"
+    _config_template = (
+        """
     auth-zones=example=configs/%s/example.zone
     devonly-regression-test-mode
     allow-from=3.4.5.0/0v
-    """ % _confdir
+    """
+        % _confdir
+    )
 
     _lua_config_file = """
     addProxyMapping("127.0.0.1/24", "3.4.5.6:99")
@@ -711,9 +737,9 @@ class ProtobufProxyMappingLogMappedTest(TestRecursorProtobuf):
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
 
@@ -721,64 +747,76 @@ class ProtobufProxyMappingLogMappedTest(TestRecursorProtobuf):
 
         # check the protobuf messages corresponding to the UDP query and answer
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '3.4.5.6')
+        self.checkProtobufQuery(
+            msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, "3.4.5.6"
+        )
         # then the response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '3.4.5.6')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, "3.4.5.6")
         self.assertEqual(len(msg.response.rrs), 1)
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         self.checkNoRemainingMessage()
 
+
 class ProtobufProxyTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export addresses over protobuf when the proxy protocol is used.
     """
 
-    _confdir = 'ProtobufProxy'
-    _config_template = """
+    _confdir = "ProtobufProxy"
+    _config_template = (
+        """
 auth-zones=example=configs/%s/example.zone
 proxy-protocol-from=127.0.0.1/32
 allow-from=127.0.0.1,6.6.6.6
 devonly-regression-test-mode
-""" % _confdir
+"""
+        % _confdir
+    )
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
-        res = self.sendUDPQueryWithProxyProtocol(query, False, '6.6.6.6', '7.7.7.7', 666, 777)
+        res = self.sendUDPQueryWithProxyProtocol(query, False, "6.6.6.6", "7.7.7.7", 666, 777)
 
         self.assertRRsetInAnswer(res, expected)
 
         # check the protobuf messages corresponding to the UDP query and answer
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '6.6.6.6', '7.7.7.7')
+        self.checkProtobufQuery(
+            msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, "6.6.6.6", "7.7.7.7"
+        )
         # then the response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '6.6.6.6')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, "6.6.6.6")
         self.assertEqual(len(msg.response.rrs), 1)
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         self.checkNoRemainingMessage()
 
+
 class ProtobufProxyWithProxyByTableTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export addresses over protobuf when the proxy protocol and a proxy table mapping is used
     """
 
-    _confdir = 'ProtobufProxyWithProxyByTable'
-    _config_template = """
+    _confdir = "ProtobufProxyWithProxyByTable"
+    _config_template = (
+        """
 auth-zones=example=configs/%s/example.zone
 proxy-protocol-from=127.0.0.1/32
 allow-from=3.4.5.6
 devonly-regression-test-mode
-""" % _confdir
+"""
+        % _confdir
+    )
 
     _lua_config_file = """
     addProxyMapping("6.6.6.6/24", "3.4.5.6:99")
@@ -786,39 +824,45 @@ devonly-regression-test-mode
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
-        res = self.sendUDPQueryWithProxyProtocol(query, False, '6.6.6.6', '7.7.7.7', 666, 777)
+        res = self.sendUDPQueryWithProxyProtocol(query, False, "6.6.6.6", "7.7.7.7", 666, 777)
 
         self.assertRRsetInAnswer(res, expected)
 
         # check the protobuf messages corresponding to the UDP query and answer
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '6.6.6.6', '7.7.7.7')
+        self.checkProtobufQuery(
+            msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, "6.6.6.6", "7.7.7.7"
+        )
         # then the response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '6.6.6.6')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, "6.6.6.6")
         self.assertEqual(len(msg.response.rrs), 1)
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         self.checkNoRemainingMessage()
 
+
 class ProtobufProxyWithProxyByTableLogMappedTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export addresses over protobuf when the proxy protocol and a proxy table mapping is used
     """
 
-    _confdir = 'ProtobufProxyWithProxyByTableLogMapped'
-    _config_template = """
+    _confdir = "ProtobufProxyWithProxyByTableLogMapped"
+    _config_template = (
+        """
 auth-zones=example=configs/%s/example.zone
 proxy-protocol-from=127.0.0.1/32
 allow-from=3.4.5.6
 devonly-regression-test-mode
-""" % _confdir
+"""
+        % _confdir
+    )
 
     _lua_config_file = """
     addProxyMapping("6.6.6.6/24", "3.4.5.6:99")
@@ -826,25 +870,27 @@ devonly-regression-test-mode
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
-        res = self.sendUDPQueryWithProxyProtocol(query, False, '6.6.6.6', '7.7.7.7', 666, 777)
+        res = self.sendUDPQueryWithProxyProtocol(query, False, "6.6.6.6", "7.7.7.7", 666, 777)
 
         self.assertRRsetInAnswer(res, expected)
 
         # check the protobuf messages corresponding to the UDP query and answer
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '3.4.5.6', '7.7.7.7')
+        self.checkProtobufQuery(
+            msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, "3.4.5.6", "7.7.7.7"
+        )
         # then the response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '3.4.5.6')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, "3.4.5.6")
         self.assertEqual(len(msg.response.rrs), 1)
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         self.checkNoRemainingMessage()
 
 
@@ -855,7 +901,7 @@ class OutgoingProtobufDefaultTest(TestRecursorProtobuf):
     that the recursor at least connects to the protobuf server.
     """
 
-    _confdir = 'OutgoingProtobufDefault'
+    _confdir = "OutgoingProtobufDefault"
     _config_template = """
     # Switch off QName Minimization, it generates much more protobuf messages
     # (or make the test much more smart!)
@@ -871,32 +917,30 @@ class OutgoingProtobufDefaultTest(TestRecursorProtobuf):
     def testA(self):
         # There is a race in priming (having the . DNSKEY in cache in particular) and this code.
         # So make sure we have the . DNSKEY in cache
-        query = dns.message.make_query('.', 'A', want_dnssec=True)
+        query = dns.message.make_query(".", "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
         time.sleep(1)
         self.emptyProtoBufQueue()
 
-        name = 'host1.secure.example.'
+        name = "host1.secure.example."
         expected = list()
 
         for qname, qtype, proto, responseSize in [
-                ('host1.secure.example.', dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 248),
-                ('host1.secure.example.', dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 221),
-                ('example.', dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 219),
-                ('host1.secure.example.', dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 175),
-                ('secure.example.', dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 233),
+            ("host1.secure.example.", dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 248),
+            ("host1.secure.example.", dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 221),
+            ("example.", dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 219),
+            ("host1.secure.example.", dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 175),
+            ("secure.example.", dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 233),
         ]:
             if not qname:
                 expected.append((None, None, None, None, None, None))
                 continue
             query = dns.message.make_query(qname, qtype, use_edns=True, want_dnssec=True)
             resp = dns.message.make_response(query)
-            expected.append((
-                qname, qtype, query, resp, proto, responseSize
-            ))
+            expected.append((qname, qtype, query, resp, proto, responseSize))
 
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         self.sendUDPQuery(query)
 
@@ -915,6 +959,7 @@ class OutgoingProtobufDefaultTest(TestRecursorProtobuf):
 
         self.checkNoRemainingMessage()
 
+
 class OutgoingProtobufWithECSMappingTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export outgoing queries over protobuf.
@@ -922,7 +967,7 @@ class OutgoingProtobufWithECSMappingTest(TestRecursorProtobuf):
     that the recursor at least connects to the protobuf server.
     """
 
-    _confdir = 'OutgoingProtobufWithECSMapping'
+    _confdir = "OutgoingProtobufWithECSMapping"
     _config_template = """
     # Switch off QName Minimization, it generates much more protobuf messages
     # (or make the test much more smart!)
@@ -942,33 +987,31 @@ class OutgoingProtobufWithECSMappingTest(TestRecursorProtobuf):
     def testA(self):
         # There is a race in priming (having the . DNSKEY in cache in particular) and this code.
         # So make sure we have the . DNSKEY in cache
-        query = dns.message.make_query('.', 'A', want_dnssec=True)
+        query = dns.message.make_query(".", "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         self.sendUDPQuery(query)
         time.sleep(1)
         self.emptyProtoBufQueue()
 
-        name = 'host1.secure.example.'
+        name = "host1.secure.example."
         expected = list()
 
         for qname, qtype, proto, responseSize, ecs in [
-                ('host1.secure.example.', dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 248, "1.2.3.0"),
-                ('host1.secure.example.', dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 221, "1.2.3.0"),
-                ('example.', dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 219, "1.2.3.0"),
-                ('host1.secure.example.', dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 175, "1.2.3.0"),
-                ('secure.example.', dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 233, "1.2.3.0"),
+            ("host1.secure.example.", dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 248, "1.2.3.0"),
+            ("host1.secure.example.", dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 221, "1.2.3.0"),
+            ("example.", dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 219, "1.2.3.0"),
+            ("host1.secure.example.", dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 175, "1.2.3.0"),
+            ("secure.example.", dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 233, "1.2.3.0"),
         ]:
             if not qname:
                 expected.append((None, None, None, None, None, None, None))
                 continue
-            ecso = clientsubnetoption.ClientSubnetOption('9.10.11.12', 24)
+            ecso = clientsubnetoption.ClientSubnetOption("9.10.11.12", 24)
             query = dns.message.make_query(qname, qtype, use_edns=True, want_dnssec=True, options=[ecso], payload=512)
             resp = dns.message.make_response(query)
-            expected.append((
-                qname, qtype, query, resp, proto, responseSize, ecs
-            ))
+            expected.append((qname, qtype, query, resp, proto, responseSize, ecs))
 
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
 
@@ -987,23 +1030,21 @@ class OutgoingProtobufWithECSMappingTest(TestRecursorProtobuf):
         self.checkNoRemainingMessage()
 
         # this query should use the unmapped ECS
-        name = 'mx1.secure.example.'
+        name = "mx1.secure.example."
         expected = list()
 
         for qname, qtype, proto, responseSize, ecs in [
-                ('mx1.secure.example.', dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 173, "127.0.0.1"),
+            ("mx1.secure.example.", dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 173, "127.0.0.1"),
         ]:
             if not qname:
                 expected.append((None, None, None, None, None, None, None))
                 continue
-            ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 32)
+            ecso = clientsubnetoption.ClientSubnetOption("127.0.0.1", 32)
             query = dns.message.make_query(qname, qtype, use_edns=True, want_dnssec=True, options=[ecso], payload=512)
             resp = dns.message.make_response(query)
-            expected.append((
-                qname, qtype, query, resp, proto, responseSize, ecs
-            ))
+            expected.append((qname, qtype, query, resp, proto, responseSize, ecs))
 
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         self.sendUDPQuery(query)
 
@@ -1021,6 +1062,7 @@ class OutgoingProtobufWithECSMappingTest(TestRecursorProtobuf):
 
         self.checkNoRemainingMessage()
 
+
 class OutgoingProtobufNoQueriesTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export incoming responses but not outgoing queries over protobuf.
@@ -1028,7 +1070,7 @@ class OutgoingProtobufNoQueriesTest(TestRecursorProtobuf):
     that the recursor at least connects to the protobuf server.
     """
 
-    _confdir = 'OutgoingProtobufNoQueries'
+    _confdir = "OutgoingProtobufNoQueries"
     _config_template = """
     # Switch off QName Minimization, it generates much more protobuf messages
     # (or make the test much more smart!)
@@ -1044,33 +1086,31 @@ class OutgoingProtobufNoQueriesTest(TestRecursorProtobuf):
     def testA(self):
         # There is a race in priming (having the . DNSKEY in cache in particular) and this code.
         # So make sure we have the . DNSKEY in cache
-        query = dns.message.make_query('.', 'A', want_dnssec=True)
+        query = dns.message.make_query(".", "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
         time.sleep(1)
         self.emptyProtoBufQueue()
 
-        name = 'host1.secure.example.'
+        name = "host1.secure.example."
         expected = list()
         # the root DNSKEY has been learned with priming the root NS already
         # ('.', dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 201),
         for qname, qtype, proto, size in [
-                ('host1.secure.example.', dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 248),
-                ('host1.secure.example.', dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 221),
-                ('example.', dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 219),
-                ('host1.secure.example.', dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 175),
-                ('secure.example.', dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 233),
+            ("host1.secure.example.", dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 248),
+            ("host1.secure.example.", dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 221),
+            ("example.", dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 219),
+            ("host1.secure.example.", dns.rdatatype.A, dnsmessage_pb2.PBDNSMessage.UDP, 175),
+            ("secure.example.", dns.rdatatype.DNSKEY, dnsmessage_pb2.PBDNSMessage.UDP, 233),
         ]:
             if not qname:
                 expected.append((None, None, None, None, None, None))
                 continue
             query = dns.message.make_query(qname, qtype, use_edns=True, want_dnssec=True)
             resp = dns.message.make_response(query)
-            expected.append((
-                qname, qtype, query, resp, proto, size
-            ))
+            expected.append((qname, qtype, query, resp, proto, size))
 
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         self.sendUDPQuery(query)
 
@@ -1085,15 +1125,19 @@ class OutgoingProtobufNoQueriesTest(TestRecursorProtobuf):
 
         self.checkNoRemainingMessage()
 
+
 class ProtobufMasksTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export queries and response over protobuf, respecting the configured initiator masking.
     """
 
-    _confdir = 'ProtobufMasks'
-    _config_template = """
+    _confdir = "ProtobufMasks"
+    _config_template = (
+        """
     devonly-regression-test-mode
-auth-zones=example=configs/%s/example.zone""" % _confdir
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _protobufMaskV4 = 4
     _protobufMaskV6 = 128
     _lua_config_file = """
@@ -1102,9 +1146,9 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port, _protobufMaskV4, _protobufMaskV6)
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1112,34 +1156,40 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         # check the protobuf messages corresponding to the UDP query and answer
         # but first let the protobuf messages the time to get there
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, '112.0.0.0')
+        self.checkProtobufQuery(
+            msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name, "112.0.0.0"
+        )
         # then the response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '112.0.0.0')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, "112.0.0.0")
         self.assertEqual(len(msg.response.rrs), 1)
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         self.checkNoRemainingMessage()
 
+
 class ProtobufQueriesOnlyTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export queries but not responses over protobuf.
     """
 
-    _confdir = 'ProtobufQueriesOnly'
-    _config_template = """
+    _confdir = "ProtobufQueriesOnly"
+    _config_template = (
+        """
     devonly-regression-test-mode
-auth-zones=example=configs/%s/example.zone""" % _confdir
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=true, logResponses=false } )
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1150,22 +1200,26 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         # no response
         self.checkNoRemainingMessage()
 
+
 class ProtobufResponsesOnlyTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export responses but not queries over protobuf.
     """
 
-    _confdir = 'ProtobufResponsesOnly'
-    _config_template = """
-auth-zones=example=configs/%s/example.zone""" % _confdir
+    _confdir = "ProtobufResponsesOnly"
+    _config_template = (
+        """
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=false, logResponses=true } )
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1177,24 +1231,28 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         # nothing else in the queue
         self.checkNoRemainingMessage()
 
+
 class ProtobufTaggedOnlyTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export queries and responses but only if they have been tagged.
     """
 
-    _confdir = 'ProtobufTaggedOnly'
-    _config_template = """
+    _confdir = "ProtobufTaggedOnly"
+    _config_template = (
+        """
     devonly-regression-test-mode
-auth-zones=example=configs/%s/example.zone""" % _confdir
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=true, logResponses=true, taggedOnly=true } )
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
-    _tags = ['tag1', 'tag2']
-    _tag_from_gettag = 'tag-from-gettag'
+    _tags = ["tag1", "tag2"]
+    _tag_from_gettag = "tag-from-gettag"
     _lua_dns_script_file = """
     function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
       if qname:equal('tagged.example.') then
@@ -1212,83 +1270,84 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
     """ % (_tag_from_gettag, _tags[0], _tags[1])
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         for method in ("sendUDPQuery", "sendTCPQuery"):
-          sender = getattr(self, method)
-          res = sender(query)
-          self.assertRRsetInAnswer(res, expected)
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertRRsetInAnswer(res, expected)
 
-          # check the protobuf message corresponding to the UDP response
-          # the first query and answer are not tagged, so there is nothing in the queue
-          #time.sleep(1)
+            # check the protobuf message corresponding to the UDP response
+            # the first query and answer are not tagged, so there is nothing in the queue
+            # time.sleep(1)
 
-          self.checkNoRemainingMessage()
-          # Again to check PC case
-          sender(query)
-          #time.sleep(1)
-          self.checkNoRemainingMessage()
+            self.checkNoRemainingMessage()
+            # Again to check PC case
+            sender(query)
+            # time.sleep(1)
+            self.checkNoRemainingMessage()
 
     def testTagged(self):
-        name = 'tagged.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.84')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "tagged.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.84")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         first = True
         for method in ("sendUDPQuery", "sendTCPQuery"):
-          messagetype = dnsmessage_pb2.PBDNSMessage.UDP
-          if not first:
-             messagetype = dnsmessage_pb2.PBDNSMessage.TCP
-          sender = getattr(self, method)
-          res = sender(query)
-          self.assertRRsetInAnswer(res, expected)
-
-          # check the protobuf messages corresponding to the query and answer
-          msg = self.getFirstProtobufMessage()
-          self.checkProtobufQuery(msg, messagetype, query, dns.rdataclass.IN, dns.rdatatype.A, name)
-          self.checkProtobufTags(msg, [ self._tag_from_gettag ])
-          # then the response
-          msg = self.getFirstProtobufMessage()
-          self.checkProtobufResponse(msg, messagetype, res)
-          self.assertEqual(len(msg.response.rrs), 1)
-          rr = msg.response.rrs[0]
-          # we have max-cache-ttl set to 15, but only check it first iteration
-          self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15, checkTTL=first)
-          self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
-          tags = [ self._tag_from_gettag ] + self._tags
-          self.checkProtobufTags(msg, tags)
-          self.checkNoRemainingMessage()
-
-          # Again to check PC case
-          res = sender(query)
-          self.assertRRsetInAnswer(res, expected)
-
-          # check the protobuf messages corresponding to the query and answer
-          msg = self.getFirstProtobufMessage()
-          self.checkProtobufQuery(msg, messagetype, query, dns.rdataclass.IN, dns.rdatatype.A, name)
-          self.checkProtobufTags(msg, [ self._tag_from_gettag ])
-          # then the response
-          msg = self.getFirstProtobufMessage()
-          self.checkProtobufResponse(msg, messagetype, res)
-          self.assertEqual(len(msg.response.rrs), 1)
-          rr = msg.response.rrs[0]
-          # time may have passed, so do not check TTL
-          self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15, checkTTL=False)
-          self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
-          tags = [ self._tag_from_gettag ] + self._tags
-          self.checkProtobufTags(msg, tags)
-          self.checkNoRemainingMessage()
-          first = False
+            messagetype = dnsmessage_pb2.PBDNSMessage.UDP
+            if not first:
+                messagetype = dnsmessage_pb2.PBDNSMessage.TCP
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertRRsetInAnswer(res, expected)
+
+            # check the protobuf messages corresponding to the query and answer
+            msg = self.getFirstProtobufMessage()
+            self.checkProtobufQuery(msg, messagetype, query, dns.rdataclass.IN, dns.rdatatype.A, name)
+            self.checkProtobufTags(msg, [self._tag_from_gettag])
+            # then the response
+            msg = self.getFirstProtobufMessage()
+            self.checkProtobufResponse(msg, messagetype, res)
+            self.assertEqual(len(msg.response.rrs), 1)
+            rr = msg.response.rrs[0]
+            # we have max-cache-ttl set to 15, but only check it first iteration
+            self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15, checkTTL=first)
+            self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.84")
+            tags = [self._tag_from_gettag] + self._tags
+            self.checkProtobufTags(msg, tags)
+            self.checkNoRemainingMessage()
+
+            # Again to check PC case
+            res = sender(query)
+            self.assertRRsetInAnswer(res, expected)
+
+            # check the protobuf messages corresponding to the query and answer
+            msg = self.getFirstProtobufMessage()
+            self.checkProtobufQuery(msg, messagetype, query, dns.rdataclass.IN, dns.rdatatype.A, name)
+            self.checkProtobufTags(msg, [self._tag_from_gettag])
+            # then the response
+            msg = self.getFirstProtobufMessage()
+            self.checkProtobufResponse(msg, messagetype, res)
+            self.assertEqual(len(msg.response.rrs), 1)
+            rr = msg.response.rrs[0]
+            # time may have passed, so do not check TTL
+            self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15, checkTTL=False)
+            self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.84")
+            tags = [self._tag_from_gettag] + self._tags
+            self.checkProtobufTags(msg, tags)
+            self.checkNoRemainingMessage()
+            first = False
+
 
 class ProtobufTagCacheBase(TestRecursorProtobuf):
     __test__ = False
 
     def testTagged(self):
-        name = 'tagged.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.84')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "tagged.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.84")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1299,7 +1358,7 @@ class ProtobufTagCacheBase(TestRecursorProtobuf):
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.84")
         self.checkNoRemainingMessage()
         self.assertEqual(len(msg.response.tags), 1)
         ts1 = msg.response.tags[0]
@@ -1314,16 +1373,16 @@ class ProtobufTagCacheBase(TestRecursorProtobuf):
         rr = msg.response.rrs[0]
         # time may have passed, so do not check TTL
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15, checkTTL=False)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.84")
         self.checkNoRemainingMessage()
         self.assertEqual(len(msg.response.tags), 1)
         ts2 = msg.response.tags[0]
         self.assertNotEqual(ts1, ts2)
 
     def testTaggedTCP(self):
-        name = 'taggedtcp.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.87')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "taggedtcp.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.87")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendTCPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1334,7 +1393,7 @@ class ProtobufTagCacheBase(TestRecursorProtobuf):
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.87')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.87")
         self.checkNoRemainingMessage()
         self.assertEqual(len(msg.response.tags), 1)
         ts1 = msg.response.tags[0]
@@ -1349,21 +1408,25 @@ class ProtobufTagCacheBase(TestRecursorProtobuf):
         rr = msg.response.rrs[0]
         # time may have passed, so do not check TTL
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15, checkTTL=False)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.87')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.87")
         self.checkNoRemainingMessage()
         self.assertEqual(len(msg.response.tags), 1)
         ts2 = msg.response.tags[0]
         self.assertNotEqual(ts1, ts2)
 
+
 class ProtobufTagCacheTest(ProtobufTagCacheBase):
     """
     This test makes sure that we correctly cache tags (actually not cache them)
     """
 
     __test__ = True
-    _confdir = 'ProtobufTagCache'
-    _config_template = """
-auth-zones=example=configs/%s/example.zone""" % _confdir
+    _confdir = "ProtobufTagCache"
+    _config_template = (
+        """
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=false, logResponses=true } )
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
@@ -1376,16 +1439,20 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
     end
     """
 
+
 class ProtobufTagCacheFFITest(ProtobufTagCacheBase):
     """
     This test makes sure that we correctly cache tags (actually not cache them) for the FFI case
     """
 
     __test__ = True
-    _confdir = 'ProtobufTagCacheFFI'
-    _config_template = """
+    _confdir = "ProtobufTagCacheFFI"
+    _config_template = (
+        """
     devonly-regression-test-mode
-auth-zones=example=configs/%s/example.zone""" % _confdir
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=false, logResponses=true } )
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
@@ -1408,14 +1475,18 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
     end
     """
 
+
 class ProtobufSelectedFromLuaTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export queries and responses but only if they have been selected from Lua.
     """
 
-    _confdir = 'ProtobufSelectedFromLua'
-    _config_template = """
-auth-zones=example=configs/%s/example.zone""" % _confdir
+    _confdir = "ProtobufSelectedFromLua"
+    _config_template = (
+        """
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=false, logResponses=false } )
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
@@ -1446,9 +1517,9 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
     """
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1458,9 +1529,9 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         self.checkNoRemainingMessage()
 
     def testQuerySelected(self):
-        name = 'query-selected.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.84')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "query-selected.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.84")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1472,9 +1543,9 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         self.checkNoRemainingMessage()
 
     def testResponseSelected(self):
-        name = 'answer-selected.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.84')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "answer-selected.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.84")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1486,36 +1557,41 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.84")
         self.checkNoRemainingMessage()
 
+
 class ProtobufExportTypesTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export other types than A, AAAA and CNAME over protobuf.
     """
 
-    _confdir = 'ProtobufExportTypes'
-    _config_template = """
+    _confdir = "ProtobufExportTypes"
+    _config_template = (
+        """
     devonly-regression-test-mode
-auth-zones=example=configs/%s/example.zone""" % _confdir
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { exportTypes={"AAAA", "MX", "SPF", "SRV", "TXT"} } )
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
 
     def testA(self):
-        name = 'types.example.'
-        expected = [dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.84'),
-                    dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'AAAA', '2001:DB8::1'),
-                    dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'MX', '10 a.example.'),
-                    dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'SPF', '"v=spf1 -all"'),
-                    dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'SRV', '10 20 443 a.example.'),
-                    dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', '"Lorem ipsum dolor sit amet"'),
-                   ]
-        query = dns.message.make_query(name, 'ANY', want_dnssec=True)
+        name = "types.example."
+        expected = [
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.84"),
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "AAAA", "2001:DB8::1"),
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "MX", "10 a.example."),
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "SPF", '"v=spf1 -all"'),
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "SRV", "10 20 443 a.example."),
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, "TXT", '"Lorem ipsum dolor sit amet"'),
+        ]
+        query = dns.message.make_query(name, "ANY", want_dnssec=True)
         query.flags |= dns.flags.CD
         raw1 = self.sendUDPQuery(query, decode=False)
         res = dns.message.from_wire(raw1)
-        self.assertMessageHasFlags(res, ['QR', 'TC', 'RD', 'RA', 'CD'], ['DO'])
+        self.assertMessageHasFlags(res, ["QR", "TC", "RD", "RA", "CD"], ["DO"])
         raw2 = self.sendTCPQuery(query, decode=False)
         res = dns.message.from_wire(raw2)
 
@@ -1527,52 +1603,58 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.ANY, name)
         # then TC response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '127.0.0.1', receivedSize=len(raw1))
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, "127.0.0.1", receivedSize=len(raw1))
         self.assertEqual(len(msg.response.rrs), 0)
 
         # check the protobuf messages corresponding to the TCP query and answer
         msg = self.getFirstProtobufMessage()
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.TCP, query, dns.rdataclass.IN, dns.rdatatype.ANY, name)
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, res, '127.0.0.1', receivedSize=len(raw2))
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, res, "127.0.0.1", receivedSize=len(raw2))
         self.assertEqual(len(msg.response.rrs), 5)
 
         for rr in msg.response.rrs:
-            self.assertIn(rr.type, [dns.rdatatype.AAAA, dns.rdatatype.TXT, dns.rdatatype.MX, dns.rdatatype.SPF, dns.rdatatype.SRV])
+            self.assertIn(
+                rr.type, [dns.rdatatype.AAAA, dns.rdatatype.TXT, dns.rdatatype.MX, dns.rdatatype.SPF, dns.rdatatype.SRV]
+            )
 
             if rr.type == dns.rdatatype.AAAA:
                 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.AAAA, name, 15)
-                self.assertEqual(socket.inet_ntop(socket.AF_INET6, rr.rdata), '2001:db8::1')
+                self.assertEqual(socket.inet_ntop(socket.AF_INET6, rr.rdata), "2001:db8::1")
             elif rr.type == dns.rdatatype.TXT:
                 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.TXT, name, 15)
                 self.assertEqual(rr.rdata, b'"Lorem ipsum dolor sit amet"')
             elif rr.type == dns.rdatatype.MX:
                 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.MX, name, 15)
-                self.assertEqual(rr.rdata, b'a.example.')
+                self.assertEqual(rr.rdata, b"a.example.")
             elif rr.type == dns.rdatatype.SPF:
                 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.SPF, name, 15)
                 self.assertEqual(rr.rdata, b'"v=spf1 -all"')
             elif rr.type == dns.rdatatype.SRV:
                 self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.SRV, name, 15)
-                self.assertEqual(rr.rdata, b'a.example.')
+                self.assertEqual(rr.rdata, b"a.example.")
 
         self.checkNoRemainingMessage()
 
+
 class ProtobufTaggedExtraFieldsTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export extra fields that may have been set while being tagged.
     """
 
-    _confdir = 'ProtobufTaggedExtraFields'
-    _config_template = """
+    _confdir = "ProtobufTaggedExtraFields"
+    _config_template = (
+        """
     devonly-regression-test-mode
-auth-zones=example=configs/%s/example.zone""" % _confdir
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=true, logResponses=true } )
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
-    _requestorId = 'S-000001727'
-    _deviceId = 'd1:0a:91:dc:cc:82'
-    _deviceName = 'Joe'
+    _requestorId = "S-000001727"
+    _deviceId = "d1:0a:91:dc:cc:82"
+    _deviceName = "Joe"
     _lua_dns_script_file = """
     function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
       if qname:equal('tagged.example.') then
@@ -1584,9 +1666,9 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
     """ % (_requestorId, _deviceId, _deviceName)
 
     def testA(self):
-        name = 'a.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "a.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1596,23 +1678,23 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         # check the protobuf messages corresponding to the UDP query and answer
         msg = self.getFirstProtobufMessage()
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
-        self.checkProtobufIdentity(msg, '', b'', '')
+        self.checkProtobufIdentity(msg, "", b"", "")
 
         # then the response
         msg = self.getFirstProtobufMessage()
-        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, '127.0.0.1')
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res, "127.0.0.1")
         self.assertEqual(len(msg.response.rrs), 1)
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
-        self.checkProtobufIdentity(msg, '', b'', '')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
+        self.checkProtobufIdentity(msg, "", b"", "")
         self.checkNoRemainingMessage()
 
     def testTagged(self):
-        name = 'tagged.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.84')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "tagged.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.84")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1620,8 +1702,10 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         # check the protobuf messages corresponding to the UDP query and answer
         msg = self.getFirstProtobufMessage()
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
-        port = ':' + str(msg.fromPort)
-        self.checkProtobufIdentity(msg, self._requestorId + port, (self._deviceId + port).encode('ascii'), self._deviceName + port)
+        port = ":" + str(msg.fromPort)
+        self.checkProtobufIdentity(
+            msg, self._requestorId + port, (self._deviceId + port).encode("ascii"), self._deviceName + port
+        )
 
         # then the response
         msg = self.getFirstProtobufMessage()
@@ -1630,20 +1714,24 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
-        self.checkProtobufIdentity(msg, self._requestorId + port, (self._deviceId + port).encode('ascii'), self._deviceName + port)
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.84")
+        self.checkProtobufIdentity(
+            msg, self._requestorId + port, (self._deviceId + port).encode("ascii"), self._deviceName + port
+        )
         self.checkNoRemainingMessage()
 
         # Again, but now the PC is involved
         # check the protobuf messages corresponding to the UDP query and answer
         # Re-init socket so we get a different port
-        self.setUpSockets();
+        self.setUpSockets()
         res = self.sendUDPQuery(query)
         msg = self.getFirstProtobufMessage()
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
-        port2 = ':' + str(msg.fromPort)
+        port2 = ":" + str(msg.fromPort)
         self.assertNotEqual(port, port2)
-        self.checkProtobufIdentity(msg, self._requestorId + port2, (self._deviceId + port2).encode('ascii'), self._deviceName + port2)
+        self.checkProtobufIdentity(
+            msg, self._requestorId + port2, (self._deviceId + port2).encode("ascii"), self._deviceName + port2
+        )
 
         # then the response
         msg = self.getFirstProtobufMessage()
@@ -1652,18 +1740,25 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
-        self.checkProtobufIdentity(msg, self._requestorId + port2, (self._deviceId + port2).encode('ascii'), self._deviceName + port2)
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.84")
+        self.checkProtobufIdentity(
+            msg, self._requestorId + port2, (self._deviceId + port2).encode("ascii"), self._deviceName + port2
+        )
         self.checkNoRemainingMessage()
 
+
 class ProtobufTaggedExtraFieldsFFITest(ProtobufTaggedExtraFieldsTest):
     """
     This test makes sure that we correctly export extra fields that may have been set while being tagged (FFI version).
     """
-    _confdir = 'ProtobufTaggedExtraFieldsFFI'
-    _config_template = """
+
+    _confdir = "ProtobufTaggedExtraFieldsFFI"
+    _config_template = (
+        """
     devonly-regression-test-mode
-auth-zones=example=configs/%s/example.zone""" % _confdir
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=true, logResponses=true } )
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
@@ -1692,17 +1787,25 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
       end
       return 0
     end
-    """ % (ProtobufTaggedExtraFieldsTest._requestorId, ProtobufTaggedExtraFieldsTest._deviceId, ProtobufTaggedExtraFieldsTest._deviceName)
+    """ % (
+        ProtobufTaggedExtraFieldsTest._requestorId,
+        ProtobufTaggedExtraFieldsTest._deviceId,
+        ProtobufTaggedExtraFieldsTest._deviceName,
+    )
+
 
 class ProtobufRPZTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export the RPZ applied policy in our protobuf messages
     """
 
-    _confdir = 'ProtobufRPZ'
-    _config_template = """
+    _confdir = "ProtobufRPZ"
+    _config_template = (
+        """
     devonly-regression-test-mode
-auth-zones=example=configs/%s/example.rpz.zone""" % _confdir
+auth-zones=example=configs/%s/example.rpz.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=true, logResponses=true } )
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", extendedErrorCode=99, extendedErrorExtra="EDEText"})
@@ -1710,28 +1813,32 @@ auth-zones=example=configs/%s/example.rpz.zone""" % _confdir
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.rpz.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.rpz.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 sub.test 3600 IN A 192.0.2.42
 ip  3600 IN A 33.22.11.99
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 *.test.example.zone.rpz. 60 IN CNAME rpz-passthru.
 24.0.11.22.33.rpz-ip     60 IN A 1.2.3.4
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
         super(ProtobufRPZTest, cls).generateRecursorConfig(confdir)
 
     def testA(self):
-        name = 'sub.test.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "sub.test.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1743,20 +1850,27 @@ ip  3600 IN A 33.22.11.99
         # then the response
         msg = self.getFirstProtobufMessage()
         self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res)
-        self.checkProtobufPolicy(msg, dnsmessage_pb2.PBDNSMessage.PolicyType.QNAME, 'zone.rpz.', '*.test.example.', 'sub.test.example', dnsmessage_pb2.PBDNSMessage.PolicyKind.NoAction)
-        self.checkProtobufEDE(msg, 99, 'EDEText')
+        self.checkProtobufPolicy(
+            msg,
+            dnsmessage_pb2.PBDNSMessage.PolicyType.QNAME,
+            "zone.rpz.",
+            "*.test.example.",
+            "sub.test.example",
+            dnsmessage_pb2.PBDNSMessage.PolicyKind.NoAction,
+        )
+        self.checkProtobufEDE(msg, 99, "EDEText")
         self.checkProtobufOT(msg, False, False)
         self.assertEqual(len(msg.response.rrs), 1)
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         self.checkNoRemainingMessage()
 
     def testB(self):
-        name = 'ip.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '1.2.3.4')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "ip.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "1.2.3.4")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1768,28 +1882,45 @@ ip  3600 IN A 33.22.11.99
         # then the response
         msg = self.getFirstProtobufMessage()
         self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res)
-        self.checkProtobufPolicy(msg, dnsmessage_pb2.PBDNSMessage.PolicyType.RESPONSEIP, 'zone.rpz.', '24.0.11.22.33.rpz-ip.', '33.22.11.99', dnsmessage_pb2.PBDNSMessage.PolicyKind.Custom)
-        self.checkProtobufEDE(msg, 99, 'EDEText')
+        self.checkProtobufPolicy(
+            msg,
+            dnsmessage_pb2.PBDNSMessage.PolicyType.RESPONSEIP,
+            "zone.rpz.",
+            "24.0.11.22.33.rpz-ip.",
+            "33.22.11.99",
+            dnsmessage_pb2.PBDNSMessage.PolicyKind.Custom,
+        )
+        self.checkProtobufEDE(msg, 99, "EDEText")
         self.checkProtobufOT(msg, False, False)
         self.assertEqual(len(msg.response.rrs), 1)
         self.checkNoRemainingMessage()
 
+
 class ProtobufRPZTagsTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export the RPZ tags in our protobuf messages
     """
 
-    _confdir = 'ProtobufRPZTags'
-    _config_template = """
+    _confdir = "ProtobufRPZTags"
+    _config_template = (
+        """
     devonly-regression-test-mode
-auth-zones=example=configs/%s/example.rpz.zone""" % _confdir
-    _tags = ['tag1', 'tag2']
-    _tags_from_gettag = ['tag1-from-gettag', 'tag2-from-gettag']
-    _tags_from_rpz = ['tag1-from-rpz', 'tag2-from-rpz' ]
+auth-zones=example=configs/%s/example.rpz.zone"""
+        % _confdir
+    )
+    _tags = ["tag1", "tag2"]
+    _tags_from_gettag = ["tag1-from-gettag", "tag2-from-gettag"]
+    _tags_from_rpz = ["tag1-from-rpz", "tag2-from-rpz"]
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=true, logResponses=true, tags={'tag1', 'tag2'} } )
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", tags={ '%s', '%s'} })
-    """ % (protobufServersParameters[0].port, protobufServersParameters[1].port, _confdir, _tags_from_rpz[0], _tags_from_rpz[1])
+    """ % (
+        protobufServersParameters[0].port,
+        protobufServersParameters[1].port,
+        _confdir,
+        _tags_from_rpz[0],
+        _tags_from_rpz[1],
+    )
     _lua_dns_script_file = """
     function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
       return 0, { '%s', '%s' }
@@ -1803,26 +1934,30 @@ auth-zones=example=configs/%s/example.rpz.zone""" % _confdir
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.rpz.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.rpz.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 sub.test 3600 IN A 192.0.2.42
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 *.test.example.zone.rpz. 60 IN CNAME rpz-passthru.
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
         super(ProtobufRPZTagsTest, cls).generateRecursorConfig(confdir)
 
     def testA(self):
-        name = 'sub.test.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "sub.test.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1834,13 +1969,20 @@ sub.test 3600 IN A 192.0.2.42
         # then the response
         msg = self.getFirstProtobufMessage()
         self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res)
-        self.checkProtobufPolicy(msg, dnsmessage_pb2.PBDNSMessage.PolicyType.QNAME, 'zone.rpz.', '*.test.example.', 'sub.test.example', dnsmessage_pb2.PBDNSMessage.PolicyKind.NoAction)
+        self.checkProtobufPolicy(
+            msg,
+            dnsmessage_pb2.PBDNSMessage.PolicyType.QNAME,
+            "zone.rpz.",
+            "*.test.example.",
+            "sub.test.example",
+            dnsmessage_pb2.PBDNSMessage.PolicyKind.NoAction,
+        )
         self.checkProtobufTags(msg, self._tags + self._tags_from_gettag + self._tags_from_rpz)
         self.assertEqual(len(msg.response.rrs), 1)
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.42')
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.42")
         self.checkNoRemainingMessage()
 
 
@@ -1848,10 +1990,14 @@ class ProtobufMetaFFITest(TestRecursorProtobuf):
     """
     This test makes sure that we can correctly add extra meta fields (FFI version).
     """
-    _confdir = 'ProtobufMetaFFI'
-    _config_template = """
+
+    _confdir = "ProtobufMetaFFI"
+    _config_template = (
+        """
     devonly-regression-test-mode
-auth-zones=example=configs/%s/example.zone""" % _confdir
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
     protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=true, logResponses=true } )
     """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
@@ -1877,10 +2023,11 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
       return 0
     end
     """
+
     def testMeta(self):
-        name = 'meta.example.'
-        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.85')
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "meta.example."
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.85")
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRRsetInAnswer(res, expected)
@@ -1888,7 +2035,9 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         # check the protobuf messages corresponding to the UDP query and answer
         msg = self.getFirstProtobufMessage()
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
-        self.checkProtobufMetas(msg, {'meta-str': { "stringVal" : ["content", "keyword"]}, 'meta-int': {"intVal" : [21, 42]}})
+        self.checkProtobufMetas(
+            msg, {"meta-str": {"stringVal": ["content", "keyword"]}, "meta-int": {"intVal": [21, 42]}}
+        )
 
         # then the response
         msg = self.getFirstProtobufMessage()
@@ -1897,7 +2046,9 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         rr = msg.response.rrs[0]
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
-        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.85')
-        self.checkProtobufMetas(msg, {'meta-str': { "stringVal" : ["content", "keyword"]}, 'meta-int': {"intVal" : [21, 42]}})
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), "192.0.2.85")
+        self.checkProtobufMetas(
+            msg, {"meta-str": {"stringVal": ["content", "keyword"]}, "meta-int": {"intVal": [21, 42]}}
+        )
 
         self.checkNoRemainingMessage()
index a3fa68d874fc614e4b7e48bc9678b81edf56d934..5c9490e3143126683a2748519a2fbfd5af941e10 100644 (file)
@@ -2,17 +2,22 @@ import dns
 import os
 from recursortests import RecursorTest
 
+
 class ProxyByTableTest(RecursorTest):
     """
     This test makes sure that we correctly use the proxy-mapped address during the ACL check
     """
-    _confdir = 'ProxyByTable'
+
+    _confdir = "ProxyByTable"
     _auth_zones = RecursorTest._default_auth_zones
 
-    _config_template = """dnssec=validate
+    _config_template = (
+        """dnssec=validate
     auth-zones=authzone.example=configs/%s/authzone.zone
     allow-from=3.4.5.0/24
-    """ % _confdir
+    """
+        % _confdir
+    )
 
     _lua_config_file = """
     addProxyMapping("127.0.0.0/24", "3.4.5.6:99")
@@ -20,18 +25,21 @@ class ProxyByTableTest(RecursorTest):
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'authzone.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN authzone.example.
+        authzonepath = os.path.join(confdir, "authzone.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN authzone.example.
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(ProxyByTableTest, cls).generateRecursorConfig(confdir)
 
-
     def testA(self):
-        expected = dns.rrset.from_text('ns.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.9'.format(prefix=self._PREFIX))
-        query = dns.message.make_query('ns.secure.example', 'A', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "ns.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.9".format(prefix=self._PREFIX)
+        )
+        query = dns.message.make_query("ns.secure.example", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -41,5 +49,3 @@ class ProxyByTableTest(RecursorTest):
             self.assertMessageIsAuthenticated(res)
             self.assertRRsetInAnswer(res, expected)
             self.assertMatchingRRSIGInAnswer(res, expected)
-
-
index a1f701688e2be597fdb3b1c18e9817dd37dd6fd2..58e9130b80b3454f7f20c9a2213657a303dd0a14 100644 (file)
@@ -14,12 +14,13 @@ except NameError:
 from recursortests import RecursorTest
 from proxyprotocol import ProxyProtocol
 
+
 class ProxyProtocolAllowedTest(RecursorTest):
-    _confdir = 'ProxyProtocolAllowed'
+    _confdir = "ProxyProtocolAllowed"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _lua_dns_script_file = """
 
     function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp, proxyProtocolValues)
@@ -129,8 +130,8 @@ api-key=%s
 """ % (_wsPort, _wsPassword, _apiKey)
 
     def checkStats(self, expected127001):
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/jsonstat?command=get-remote-ring&name=remotes'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/jsonstat?command=get-remote-ring&name=remotes"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
@@ -140,15 +141,15 @@ api-key=%s
         # testLocalProxyProtocol test, which actually does not set a source address.  If we see a
         # higher value than expected, some ProxyProtocol clients were accounted as 127.0.0.1, which
         # is not right as all other tests set a source address other than 127.0.0.1
-        for entry in content['entries']:
-            if entry[1] == '127.0.0.1':
+        for entry in content["entries"]:
+            if entry[1] == "127.0.0.1":
                 self.assertEqual(entry[0], expected127001)
 
     def testLocalProxyProtocol(self):
-        qname = 'local.proxy-protocol.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.255')
+        qname = "local.proxy-protocol.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.255")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         queryPayload = query.to_wire()
         ppPayload = ProxyProtocol.getPayload(True, False, False, None, None, None, None, [])
         payload = ppPayload + queryPayload
@@ -201,12 +202,12 @@ api-key=%s
         self.checkStats(2)
 
     def testInvalidMagicProxyProtocol(self):
-        qname = 'invalid-magic.proxy-protocol.recursor-tests.powerdns.com.'
+        qname = "invalid-magic.proxy-protocol.recursor-tests.powerdns.com."
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         queryPayload = query.to_wire()
         ppPayload = ProxyProtocol.getPayload(True, False, False, None, None, None, None, [])
-        ppPayload = b'\x00' + ppPayload[1:]
+        ppPayload = b"\x00" + ppPayload[1:]
         payload = ppPayload + queryPayload
 
         # UDP
@@ -253,12 +254,14 @@ api-key=%s
         self.assertEqual(res, None)
 
     def testTCPOneByteAtATimeProxyProtocol(self):
-        qname = 'tcp-one-byte-at-a-time.proxy-protocol.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.1')
+        qname = "tcp-one-byte-at-a-time.proxy-protocol.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.1")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         queryPayload = query.to_wire()
-        ppPayload = ProxyProtocol.getPayload(False, True, False, '127.0.0.42', '255.255.255.255', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
+        ppPayload = ProxyProtocol.getPayload(
+            False, True, False, "127.0.0.42", "255.255.255.255", 0, 65535, [[0, b"foo"], [255, b"bar"]]
+        )
 
         # TCP
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -267,14 +270,14 @@ api-key=%s
 
         try:
             for i in range(len(ppPayload)):
-                sock.send(ppPayload[i:i+1])
+                sock.send(ppPayload[i : i + 1])
                 time.sleep(0.01)
             value = struct.pack("!H", len(queryPayload))
             for i in range(len(value)):
-                sock.send(value[i:i+1])
+                sock.send(value[i : i + 1])
                 time.sleep(0.01)
             for i in range(len(queryPayload)):
-                sock.send(queryPayload[i:i+1])
+                sock.send(queryPayload[i : i + 1])
                 time.sleep(0.01)
 
             data = sock.recv(2)
@@ -299,11 +302,13 @@ api-key=%s
     def testTooLargeProxyProtocol(self):
         # the total payload (proxy protocol + DNS) is larger than proxy-protocol-maximum-size
         # so it should be dropped
-        qname = 'too-large.proxy-protocol.recursor-tests.powerdns.com.'
+        qname = "too-large.proxy-protocol.recursor-tests.powerdns.com."
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         queryPayload = query.to_wire()
-        ppPayload = ProxyProtocol.getPayload(False, True, False, '127.0.0.42', '255.255.255.255', 0, 65535, [ [0, b'foo' ], [1, b'A'*512], [ 255, b'bar'] ])
+        ppPayload = ProxyProtocol.getPayload(
+            False, True, False, "127.0.0.42", "255.255.255.255", 0, 65535, [[0, b"foo"], [1, b"A" * 512], [255, b"bar"]]
+        )
         payload = ppPayload + queryPayload
 
         # UDP
@@ -351,83 +356,85 @@ api-key=%s
         self.assertEqual(res, None)
 
     def testNoHeaderProxyProtocol(self):
-        qname = 'no-header.proxy-protocol.recursor-tests.powerdns.com.'
+        qname = "no-header.proxy-protocol.recursor-tests.powerdns.com."
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
             self.assertEqual(res, None)
 
     def testIPv4ProxyProtocol(self):
-        qname = 'ipv4.proxy-protocol.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.1')
+        qname = "ipv4.proxy-protocol.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.1")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, False, '127.0.0.42', '255.255.255.255', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
+            res = sender(query, False, "127.0.0.42", "255.255.255.255", 0, 65535, [[0, b"foo"], [255, b"bar"]])
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertRRsetInAnswer(res, expected)
 
     def testIPv4NoValuesProxyProtocol(self):
-        qname = 'ipv4-no-values.proxy-protocol.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.255')
+        qname = "ipv4-no-values.proxy-protocol.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.255")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, False, '127.0.0.42', '255.255.255.255', 0, 65535)
+            res = sender(query, False, "127.0.0.42", "255.255.255.255", 0, 65535)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertRRsetInAnswer(res, expected)
 
     def testIPv4ProxyProtocolNotAuthorized(self):
-        qname = 'ipv4-not-authorized.proxy-protocol.recursor-tests.powerdns.com.'
+        qname = "ipv4-not-authorized.proxy-protocol.recursor-tests.powerdns.com."
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, False, '192.0.2.255', '255.255.255.255', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
+            res = sender(query, False, "192.0.2.255", "255.255.255.255", 0, 65535, [[0, b"foo"], [255, b"bar"]])
             self.assertEqual(res, None)
 
     def testIPv6ProxyProtocol(self):
-        qname = 'ipv6.proxy-protocol.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.1')
+        qname = "ipv6.proxy-protocol.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.1")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, True, '::42', '2001:db8::ff', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
+            res = sender(query, True, "::42", "2001:db8::ff", 0, 65535, [[0, b"foo"], [255, b"bar"]])
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertRRsetInAnswer(res, expected)
 
     def testIPv6NoValuesProxyProtocol(self):
-        qname = 'ipv6-no-values.proxy-protocol.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.255')
+        qname = "ipv6-no-values.proxy-protocol.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.255")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, True, '::42', '2001:db8::ff', 0, 65535)
+            res = sender(query, True, "::42", "2001:db8::ff", 0, 65535)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertRRsetInAnswer(res, expected)
 
     def testIPv6ProxyProtocolNotAuthorized(self):
-        qname = 'ipv6-not-authorized.proxy-protocol.recursor-tests.powerdns.com.'
+        qname = "ipv6-not-authorized.proxy-protocol.recursor-tests.powerdns.com."
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, True, '2001:db8::1', '2001:db8::ff', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
+            res = sender(query, True, "2001:db8::1", "2001:db8::ff", 0, 65535, [[0, b"foo"], [255, b"bar"]])
             self.assertEqual(res, None)
 
     def testIPv6ProxyProtocolSeveralQueriesOverTCP(self):
-        qname = 'several-queries-tcp.proxy-protocol.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.1')
+        qname = "several-queries-tcp.proxy-protocol.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.1")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         queryPayload = query.to_wire()
-        ppPayload = ProxyProtocol.getPayload(False, True, True, '::42', '2001:db8::ff', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
+        ppPayload = ProxyProtocol.getPayload(
+            False, True, True, "::42", "2001:db8::ff", 0, 65535, [[0, b"foo"], [255, b"bar"]]
+        )
 
         # TCP
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -463,9 +470,10 @@ api-key=%s
         self.assertEqual(count, 5)
         sock.close()
 
+
 class ProxyProtocolAllowedFFITest(ProxyProtocolAllowedTest):
     # same tests than ProxyProtocolAllowedTest but with the Lua FFI interface instead of the regular one
-    _confdir = 'ProxyProtocolAllowedFFI'
+    _confdir = "ProxyProtocolAllowedFFI"
     _lua_dns_script_file = """
     local ffi = require("ffi")
 
@@ -613,8 +621,9 @@ class ProxyProtocolAllowedFFITest(ProxyProtocolAllowedTest):
     end
     """ % (ProxyProtocolAllowedTest._recursorPort)
 
+
 class ProxyProtocolNotAllowedTest(RecursorTest):
-    _confdir = 'ProxyProtocolNotAllowed'
+    _confdir = "ProxyProtocolNotAllowed"
     _lua_dns_script_file = """
 
     function preresolve(dq)
@@ -629,10 +638,10 @@ class ProxyProtocolNotAllowedTest(RecursorTest):
 """ % ()
 
     def testNoHeaderProxyProtocol(self):
-        qname = 'no-header.proxy-protocol-not-allowed.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.1')
+        qname = "no-header.proxy-protocol-not-allowed.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.1")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -640,17 +649,18 @@ class ProxyProtocolNotAllowedTest(RecursorTest):
             self.assertRRsetInAnswer(res, expected)
 
     def testIPv4ProxyProtocol(self):
-        qname = 'ipv4.proxy-protocol-not-allowed.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.1')
+        qname = "ipv4.proxy-protocol-not-allowed.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.1")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, False, '127.0.0.42', '255.255.255.255', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
+            res = sender(query, False, "127.0.0.42", "255.255.255.255", 0, 65535, [[0, b"foo"], [255, b"bar"]])
             self.assertEqual(res, None)
 
+
 class ProxyProtocolExceptionTest(RecursorTest):
-    _confdir = 'ProxyProtocolException'
+    _confdir = "ProxyProtocolException"
     _lua_dns_script_file = """
 
     function preresolve(dq)
@@ -666,10 +676,10 @@ class ProxyProtocolExceptionTest(RecursorTest):
 """ % (RecursorTest._recursorPort)
 
     def testNoHeaderProxyProtocol(self):
-        qname = 'no-header.proxy-protocol-not-allowed.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.1')
+        qname = "no-header.proxy-protocol-not-allowed.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.1")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
             res = sender(query)
@@ -677,17 +687,18 @@ class ProxyProtocolExceptionTest(RecursorTest):
             self.assertRRsetInAnswer(res, expected)
 
     def testIPv4ProxyProtocol(self):
-        qname = 'ipv4.proxy-protocol-not-allowed.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.1')
+        qname = "ipv4.proxy-protocol-not-allowed.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.1")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, False, '127.0.0.42', '255.255.255.255', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
+            res = sender(query, False, "127.0.0.42", "255.255.255.255", 0, 65535, [[0, b"foo"], [255, b"bar"]])
             self.assertEqual(res, None)
 
+
 class ProxyProtocolConfigReloadTest(RecursorTest):
-    _confdir = 'ProxyProtocolConfigReload'
+    _confdir = "ProxyProtocolConfigReload"
     _lua_dns_script_file = """
 
     function preresolve(dq)
@@ -702,30 +713,28 @@ class ProxyProtocolConfigReloadTest(RecursorTest):
 """
 
     def testIPv4ProxyProtocol(self):
-        qname = 'ipv4.proxy-protocol-not-allowed.recursor-tests.powerdns.com.'
-        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.1')
+        qname = "ipv4.proxy-protocol-not-allowed.recursor-tests.powerdns.com."
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, "A", "192.0.2.1")
 
-        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        query = dns.message.make_query(qname, "A", want_dnssec=True)
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, False, '127.0.0.42', '255.255.255.255', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
+            res = sender(query, False, "127.0.0.42", "255.255.255.255", 0, 65535, [[0, b"foo"], [255, b"bar"]])
             self.assertEqual(res, None)
         ProxyProtocolConfigReloadTest._config_template = """
         proxy-protocol-from=127.0.0.1/32
         allow-from=127.0.0.0/24, ::1/128
 """
-        confdir = os.path.join('configs', ProxyProtocolConfigReloadTest._confdir)
+        confdir = os.path.join("configs", ProxyProtocolConfigReloadTest._confdir)
         ProxyProtocolConfigReloadTest.generateRecursorConfig(confdir)
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % confdir,
-                          'reload-acls']
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % confdir, "reload-acls"]
         try:
             subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (rec_controlCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (rec_controlCmd, e.returncode, e.output))
 
         for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"):
             sender = getattr(self, method)
-            res = sender(query, False, '127.0.0.42', '255.255.255.255', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
+            res = sender(query, False, "127.0.0.42", "255.255.255.255", 0, 65535, [[0, b"foo"], [255, b"bar"]])
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertRRsetInAnswer(res, expected)
index d6d27dd8bd12a200d360172726f69e5dcf698246..d155028ce54effbb5b9c46d414a29e80133c1b6d 100644 (file)
@@ -1,14 +1,16 @@
 import dns
 from recursortests import RecursorTest
 
+
 class RDNotAllowedTest(RecursorTest):
-    _confdir = 'RDNotAllowed'
+    _confdir = "RDNotAllowed"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """
 """
+
     def testRD0(self):
-        query = dns.message.make_query('ns.secure.example', 'A', want_dnssec=True)
+        query = dns.message.make_query("ns.secure.example", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
         query.flags &= ~dns.flags.RD
 
@@ -17,17 +19,21 @@ class RDNotAllowedTest(RecursorTest):
         self.assertRcodeEqual(res, dns.rcode.REFUSED)
         self.assertAnswerEmpty(res)
 
+
 class RDAllowedTest(RecursorTest):
-    _confdir = 'RDAllowed'
+    _confdir = "RDAllowed"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """
     disable-packetcache=yes
     allow-no-rd=yes
 """
+
     def testRD0(self):
-        expected = dns.rrset.from_text('ns.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.9'.format(prefix=self._PREFIX))
-        query = dns.message.make_query('ns.secure.example', 'A', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "ns.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.9".format(prefix=self._PREFIX)
+        )
+        query = dns.message.make_query("ns.secure.example", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
         query.flags &= ~dns.flags.RD
 
index 8b89cae16ec4b5da7bfd3bdf63fadf70b7f1c474..15d13463f8ea4c4bf05060de2499c4f2c1446abd 100644 (file)
@@ -10,13 +10,13 @@ import time
 
 from recursortests import RecursorTest
 
-class RPZServer(object):
 
+class RPZServer(object):
     def __init__(self, port):
         self._currentSerial = 0
         self._targetSerial = 1
         self._serverPort = port
-        listener = threading.Thread(name='RPZ Listener', target=self._listener, args=[])
+        listener = threading.Thread(name="RPZ Listener", target=self._listener, args=[])
         listener.daemon = True
         listener.start()
 
@@ -28,7 +28,9 @@ class RPZServer(object):
             return False
 
         if newSerial != self._currentSerial + 1:
-            raise AssertionError("Asking the RPZ server to serve serial %d, already serving %d" % (newSerial, self._currentSerial))
+            raise AssertionError(
+                "Asking the RPZ server to serve serial %d, already serving %d" % (newSerial, self._currentSerial)
+            )
         self._targetSerial = newSerial
         return True
 
@@ -39,121 +41,378 @@ class RPZServer(object):
 
         if message.question[0].rdtype == dns.rdatatype.AXFR:
             if self._currentSerial != 0:
-                print('Received an AXFR query but IXFR expected because the current serial is %d' % (self._currentSerial))
+                print(
+                    "Received an AXFR query but IXFR expected because the current serial is %d" % (self._currentSerial)
+                )
                 return (None, self._currentSerial)
 
             newSerial = self._targetSerial
             records = [
-                dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                dns.rrset.from_text('a.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                ]
+                dns.rrset.from_text(
+                    "zone.rpz.",
+                    60,
+                    dns.rdataclass.IN,
+                    dns.rdatatype.SOA,
+                    "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                ),
+                dns.rrset.from_text("a.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                dns.rrset.from_text(
+                    "zone.rpz.",
+                    60,
+                    dns.rdataclass.IN,
+                    dns.rdatatype.SOA,
+                    "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                ),
+            ]
 
         elif message.question[0].rdtype == dns.rdatatype.IXFR:
             oldSerial = message.authority[0][0].serial
 
             # special case for the 9th update, which might get skipped
             if oldSerial != self._currentSerial and self._currentSerial != 9:
-                print('Received an IXFR query with an unexpected serial %d, expected %d' % (oldSerial, self._currentSerial))
+                print(
+                    "Received an IXFR query with an unexpected serial %d, expected %d"
+                    % (oldSerial, self._currentSerial)
+                )
                 return (None, self._currentSerial)
 
             newSerial = self._targetSerial
             if newSerial == 2:
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
                     # no deletion
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('b.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("b.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 3:
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('a.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text("a.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
                     # no addition
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 4:
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('b.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('c.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text("b.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("c.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 5:
                 # this one is a bit special, we are answering with a full AXFR
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('d.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    dns.rrset.from_text('tc.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.CNAME, 'rpz-tcp-only.'),
-                    dns.rrset.from_text('drop.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.CNAME, 'rpz-drop.'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("d.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                    dns.rrset.from_text(
+                        "tc.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "rpz-tcp-only."
+                    ),
+                    dns.rrset.from_text(
+                        "drop.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "rpz-drop."
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 6:
                 # back to IXFR
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('d.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    dns.rrset.from_text('tc.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.CNAME, 'rpz-tcp-only.'),
-                    dns.rrset.from_text('drop.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.CNAME, 'rpz-drop.'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('e.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1', '192.0.2.2'),
-                    dns.rrset.from_text('e.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.MX, '10 mx.example.'),
-                    dns.rrset.from_text('f.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.CNAME, 'e.example.'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text("d.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                    dns.rrset.from_text(
+                        "tc.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "rpz-tcp-only."
+                    ),
+                    dns.rrset.from_text(
+                        "drop.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "rpz-drop."
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "e.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2"
+                    ),
+                    dns.rrset.from_text(
+                        "e.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.MX, "10 mx.example."
+                    ),
+                    dns.rrset.from_text(
+                        "f.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "e.example."
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 7:
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('e.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1', '192.0.2.2'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('e.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'),
-                    dns.rrset.from_text('tc.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.CNAME, 'rpz-tcp-only.'),
-                    dns.rrset.from_text('drop.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.CNAME, 'rpz-drop.'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "e.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1", "192.0.2.2"
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("e.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.2"),
+                    dns.rrset.from_text(
+                        "tc.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "rpz-tcp-only."
+                    ),
+                    dns.rrset.from_text(
+                        "drop.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "rpz-drop."
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 8:
                 # this one is a bit special too, we are answering with a full AXFR and the new zone is empty
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 9:
                 # IXFR inserting a duplicate, we should not crash and skip it
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('dup.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.CNAME, 'rpz-passthru.'),
-                    dns.rrset.from_text('dup.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.CNAME, 'rpz-passthru.'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "dup.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "rpz-passthru."
+                    ),
+                    dns.rrset.from_text(
+                        "dup.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.CNAME, "rpz-passthru."
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 10:
                 # full AXFR to make sure we are removing the duplicate, adding a record, to check that the update was correctly applied
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('f.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("f.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                ]
             elif newSerial == 11:
                 # IXFR with two deltas, the first one adding a 'g' and the second one removing 'f'
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % (newSerial + 1)),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('g.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('f.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % (newSerial + 1)),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % (newSerial + 1))
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % (newSerial + 1),
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("g.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("f.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % (newSerial + 1),
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % (newSerial + 1),
+                    ),
+                ]
                 # this one has two updates in one
                 newSerial = newSerial + 1
                 self._targetSerial = self._targetSerial + 1
@@ -174,14 +433,14 @@ class RPZServer(object):
 
             message = dns.message.from_wire(data)
             if len(message.question) != 1:
-                print('Invalid RPZ query, qdcount is %d' % (len(message.question)))
+                print("Invalid RPZ query, qdcount is %d" % (len(message.question)))
                 break
             if not message.question[0].rdtype in [dns.rdatatype.AXFR, dns.rdatatype.IXFR]:
-                print('Invalid RPZ query, qtype is %d' % (message.question.rdtype))
+                print("Invalid RPZ query, qtype is %d" % (message.question.rdtype))
                 break
             (serial, answer) = self._getAnswer(message)
             if not answer:
-                print('Unable to get a response for %s %d' % (message.question[0].name, message.question[0].rdtype))
+                print("Unable to get a response for %s %d" % (message.question[0].name, message.question[0].rdtype))
                 break
 
             wire = answer.to_wire()
@@ -210,22 +469,21 @@ class RPZServer(object):
         while True:
             try:
                 (conn, _) = sock.accept()
-                thread = threading.Thread(name='RPZ Connection Handler',
-                                      target=self._connectionHandler,
-                                      args=[conn])
+                thread = threading.Thread(name="RPZ Connection Handler", target=self._connectionHandler, args=[conn])
                 thread.daemon = True
                 thread.start()
 
             except socket.error as e:
-                print('Error in RPZ socket: %s' % str(e))
+                print("Error in RPZ socket: %s" % str(e))
                 sock.close()
 
+
 class RPZRecursorTest(RecursorTest):
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
-    _confdir = 'RPZ'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
+    _confdir = "RPZ"
     _lua_dns_script_file = """
 
     function prerpz(dq)
@@ -248,12 +506,12 @@ log-rpz-changes=yes
 """ % (_confdir, _wsPort, _wsPassword, _apiKey)
 
     def sendNotify(self):
-        notify = dns.message.make_query('zone.rpz', 'SOA', want_dnssec=False)
-        notify.set_opcode(4) # notify
+        notify = dns.message.make_query("zone.rpz", "SOA", want_dnssec=False)
+        notify.set_opcode(4)  # notify
         res = self.sendUDPQuery(notify)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(res.opcode(), 4)
-        self.assertEqual(res.question[0].to_text(), 'zone.rpz. IN SOA')
+        self.assertEqual(res.question[0].to_text(), "zone.rpz. IN SOA")
 
     def assertAdditionalHasSOA(self, msg, name):
         if not isinstance(msg, dns.message.Message):
@@ -269,7 +527,7 @@ log-rpz-changes=yes
             raise AssertionError("No %s SOA record found in the additional section:\n%s" % (name, msg.to_text()))
 
     def checkBlocked(self, name, shouldBeBlocked=True, adQuery=False, singleCheck=False, soa=None):
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.CD
         if adQuery:
             query.flags |= dns.flags.AD
@@ -279,9 +537,9 @@ log-rpz-changes=yes
             res = sender(query)
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             if shouldBeBlocked:
-                expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.1')
+                expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.1")
             else:
-                expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
+                expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, "A", "192.0.2.42")
 
             self.assertRRsetInAnswer(res, expected)
             if soa:
@@ -314,7 +572,7 @@ log-rpz-changes=yes
             if soa:
                 self.assertAdditionalHasSOA(res, soa)
 
-    def checkNXD(self, qname, qtype='A'):
+    def checkNXD(self, qname, qtype="A"):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
         query.flags |= dns.flags.CD
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -324,12 +582,12 @@ log-rpz-changes=yes
             self.assertEqual(len(res.answer), 0)
             self.assertEqual(len(res.authority), 1)
 
-    def checkTruncated(self, qname, qtype='A', soa=None):
+    def checkTruncated(self, qname, qtype="A", soa=None):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD', 'TC'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD", "TC"])
         self.assertEqual(len(res.answer), 0)
         self.assertEqual(len(res.authority), 0)
         if soa:
@@ -337,12 +595,12 @@ log-rpz-changes=yes
 
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'CD'])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "CD"])
         self.assertEqual(len(res.answer), 0)
         self.assertEqual(len(res.authority), 1)
         self.assertEqual(len(res.additional), 0)
 
-    def checkDropped(self, qname, qtype='A'):
+    def checkDropped(self, qname, qtype="A"):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
         query.flags |= dns.flags.CD
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -351,41 +609,43 @@ log-rpz-changes=yes
             self.assertEqual(res, None)
 
     def checkRPZStats(self, serial, recordsCount, fullXFRCount, totalXFRCount):
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/rpzstatistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/rpzstatistics"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        self.assertIn('zone.rpz.', content)
-        zone = content['zone.rpz.']
-        for key in ['last_update', 'records', 'serial', 'transfers_failed', 'transfers_full', 'transfers_success']:
+        self.assertIn("zone.rpz.", content)
+        zone = content["zone.rpz."]
+        for key in ["last_update", "records", "serial", "transfers_failed", "transfers_full", "transfers_success"]:
             self.assertIn(key, zone)
 
-        self.assertEqual(zone['serial'], serial)
-        self.assertEqual(zone['records'], recordsCount)
-        self.assertEqual(zone['transfers_full'], fullXFRCount)
-        self.assertEqual(zone['transfers_success'], totalXFRCount)
+        self.assertEqual(zone["serial"], serial)
+        self.assertEqual(zone["records"], recordsCount)
+        self.assertEqual(zone["transfers_full"], fullXFRCount)
+        self.assertEqual(zone["transfers_success"], totalXFRCount)
+
 
 rpzServerPort = 4250
 rpzServer = RPZServer(rpzServerPort)
 
+
 class RPZXFRRecursorTest(RPZRecursorTest):
     """
     This test makes sure that we correctly update RPZ zones via AXFR then IXFR
     """
 
     global rpzServerPort
-    _confdir = 'RPZXFRRecursor'
+    _confdir = "RPZXFRRecursor"
     _lua_config_file = """
     -- The first server is a bogus one, to test that we correctly fail over to the second one
     rpzPrimary({'127.0.0.1:9999', '127.0.0.1:%d'}, 'zone.rpz.', { refresh=1, includeSOA=true, dumpFile="configs/%s/rpz.zone.dump"})
     """ % (rpzServerPort, _confdir)
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 auth-zones=example=configs/%s/example.zone
 webserver=yes
@@ -401,37 +661,42 @@ allow-notify-for=zone.rpz
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 b 3600 IN A 192.0.2.42
 c 3600 IN A 192.0.2.42
 d 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(RPZXFRRecursorTest, cls).generateRecursorConfig(confdir)
 
     def checkDump(self, serial, timeout=2):
-        file = 'configs/%s/rpz.zone.dump' % self._confdir
+        file = "configs/%s/rpz.zone.dump" % self._confdir
         attempts = 0
-        incr = .1
+        incr = 0.1
         # There's a file base race here, so do a few attempts
         while attempts < timeout:
             try:
-                zone = dns.zone.from_file(file, 'zone.rpz', relativize=False, check_origin=False, allow_include=False)
-                soa = zone['']
+                zone = dns.zone.from_file(file, "zone.rpz", relativize=False, check_origin=False, allow_include=False)
+                soa = zone[""]
                 soa.find_rdataset(dns.rdataclass.IN, dns.rdatatype.SOA)
                 # if the above call did not throw an exception, the SOA has the right owner, continue
                 soa = zone.get_soa()
-                if soa.serial == serial and soa.mname == dns.name.from_text('ns.zone.rpz.'):
-                    return # we found what we expected
+                if soa.serial == serial and soa.mname == dns.name.from_text("ns.zone.rpz."):
+                    return  # we found what we expected
             except FileNotFoundError as e:
                 pass
             attempts = attempts + incr
             time.sleep(incr)
-        raise AssertionError("Waited %d seconds for the dumpfile to be updated to %d but the serial is still %d" % (timeout, serial, soa.serial))
+        raise AssertionError(
+            "Waited %d seconds for the dumpfile to be updated to %d but the serial is still %d"
+            % (timeout, serial, soa.serial)
+        )
 
     def waitUntilCorrectSerialIsLoaded(self, serial, timeout=5):
         global rpzServer
@@ -439,7 +704,7 @@ e 3600 IN A 192.0.2.42
         rpzServer.moveToSerial(serial)
 
         attempts = 0
-        incr = .1
+        incr = 0.1
         while attempts < timeout:
             currentSerial = rpzServer.getCurrentSerial()
             if currentSerial > serial:
@@ -452,7 +717,10 @@ e 3600 IN A 192.0.2.42
             attempts = attempts + incr
             time.sleep(incr)
 
-        raise AssertionError("Waited %d seconds for the serial to be updated to %d but the serial is still %d" % (timeout, serial, currentSerial))
+        raise AssertionError(
+            "Waited %d seconds for the serial to be updated to %d but the serial is still %d"
+            % (timeout, serial, currentSerial)
+        )
 
     def testRPZ(self):
         # Fresh RPZ does not need a notify
@@ -460,86 +728,113 @@ e 3600 IN A 192.0.2.42
         # first zone, only a should be blocked
         self.waitUntilCorrectSerialIsLoaded(1)
         self.checkRPZStats(1, 1, 1, self._xfrDone)
-        self.checkBlocked('a.example.', soa='zone.rpz.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
+        self.checkBlocked("a.example.", soa="zone.rpz.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
 
         # second zone, a and b should be blocked
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(2)
         self.checkRPZStats(2, 2, 1, self._xfrDone)
-        self.checkBlocked('a.example.', soa='zone.rpz.')
-        self.checkBlocked('b.example.', soa='zone.rpz.')
-        self.checkNotBlocked('c.example.')
+        self.checkBlocked("a.example.", soa="zone.rpz.")
+        self.checkBlocked("b.example.", soa="zone.rpz.")
+        self.checkNotBlocked("c.example.")
 
         # third zone, only b should be blocked
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(3)
         self.checkRPZStats(3, 1, 1, self._xfrDone)
-        self.checkNotBlocked('a.example.')
-        self.checkBlocked('b.example.', soa='zone.rpz.')
-        self.checkNotBlocked('c.example.')
+        self.checkNotBlocked("a.example.")
+        self.checkBlocked("b.example.", soa="zone.rpz.")
+        self.checkNotBlocked("c.example.")
 
         # fourth zone, only c should be blocked
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(4)
         self.checkRPZStats(4, 1, 1, self._xfrDone)
-        self.checkNotBlocked('a.example.')
-        self.checkNotBlocked('b.example.')
-        self.checkBlocked('c.example.', soa='zone.rpz.')
+        self.checkNotBlocked("a.example.")
+        self.checkNotBlocked("b.example.")
+        self.checkBlocked("c.example.", soa="zone.rpz.")
 
         # fifth zone, we should get a full AXFR this time, and only d should be blocked
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(5)
         self.checkRPZStats(5, 3, 2, self._xfrDone)
-        self.checkNotBlocked('a.example.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
-        self.checkBlocked('d.example.', soa='zone.rpz.')
+        self.checkNotBlocked("a.example.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
+        self.checkBlocked("d.example.", soa="zone.rpz.")
 
         # sixth zone, only e should be blocked, f is a local data record
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(6)
         self.checkRPZStats(6, 2, 2, self._xfrDone)
-        self.checkNotBlocked('a.example.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
-        self.checkNotBlocked('d.example.')
-        self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1', '192.0.2.2'), soa='zone.rpz.')
-        self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'))
-        self.checkNoData('e.example.', 'AAAA', soa='zone.rpz.')
-        self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa='zone.rpz.')
+        self.checkNotBlocked("a.example.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
+        self.checkNotBlocked("d.example.")
+        self.checkCustom(
+            "e.example.",
+            "A",
+            dns.rrset.from_text("e.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1", "192.0.2.2"),
+            soa="zone.rpz.",
+        )
+        self.checkCustom(
+            "e.example.", "MX", dns.rrset.from_text("e.example.", 0, dns.rdataclass.IN, "MX", "10 mx.example.")
+        )
+        self.checkNoData("e.example.", "AAAA", soa="zone.rpz.")
+        self.checkCustom(
+            "f.example.",
+            "A",
+            dns.rrset.from_text("f.example.", 0, dns.rdataclass.IN, "CNAME", "e.example."),
+            soa="zone.rpz.",
+        )
 
         # seventh zone, e should only have one A
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(7)
         self.checkRPZStats(7, 4, 2, self._xfrDone)
-        self.checkNotBlocked('a.example.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
-        self.checkNotBlocked('d.example.')
-        self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2'), soa='zone.rpz.')
-        self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'), soa='zone.rpz.')
-        self.checkNoData('e.example.', 'AAAA', soa='zone.rpz.')
-        self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa='zone.rpz.')
+        self.checkNotBlocked("a.example.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
+        self.checkNotBlocked("d.example.")
+        self.checkCustom(
+            "e.example.",
+            "A",
+            dns.rrset.from_text("e.example.", 0, dns.rdataclass.IN, "A", "192.0.2.2"),
+            soa="zone.rpz.",
+        )
+        self.checkCustom(
+            "e.example.",
+            "MX",
+            dns.rrset.from_text("e.example.", 0, dns.rdataclass.IN, "MX", "10 mx.example."),
+            soa="zone.rpz.",
+        )
+        self.checkNoData("e.example.", "AAAA", soa="zone.rpz.")
+        self.checkCustom(
+            "f.example.",
+            "A",
+            dns.rrset.from_text("f.example.", 0, dns.rdataclass.IN, "CNAME", "e.example."),
+            soa="zone.rpz.",
+        )
         # check that the policy is disabled for AD=1 queries
-        self.checkNotBlocked('e.example.', True)
+        self.checkNotBlocked("e.example.", True)
         # check non-custom policies
-        self.checkTruncated('tc.example.', soa='zone.rpz.')
-        self.checkDropped('drop.example.')
+        self.checkTruncated("tc.example.", soa="zone.rpz.")
+        self.checkDropped("drop.example.")
 
         # eighth zone, all entries should be gone
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(8)
         self.checkRPZStats(8, 0, 3, self._xfrDone)
-        self.checkNotBlocked('a.example.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
-        self.checkNotBlocked('d.example.')
-        self.checkNotBlocked('e.example.')
-        self.checkNXD('f.example.')
-        self.checkNXD('tc.example.')
-        self.checkNXD('drop.example.')
+        self.checkNotBlocked("a.example.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
+        self.checkNotBlocked("d.example.")
+        self.checkNotBlocked("e.example.")
+        self.checkNXD("f.example.")
+        self.checkNXD("tc.example.")
+        self.checkNXD("drop.example.")
 
         # 9th zone is a duplicate, it might get skipped
         global rpzServer
@@ -549,14 +844,14 @@ e 3600 IN A 192.0.2.42
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(10)
         self.checkRPZStats(10, 1, 4, self._xfrDone)
-        self.checkNotBlocked('a.example.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
-        self.checkNotBlocked('d.example.')
-        self.checkNotBlocked('e.example.')
-        self.checkBlocked('f.example.', soa='zone.rpz.')
-        self.checkNXD('tc.example.')
-        self.checkNXD('drop.example.')
+        self.checkNotBlocked("a.example.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
+        self.checkNotBlocked("d.example.")
+        self.checkNotBlocked("e.example.")
+        self.checkBlocked("f.example.", soa="zone.rpz.")
+        self.checkNXD("tc.example.")
+        self.checkNXD("drop.example.")
 
         # the next update will update the zone twice
         rpzServer.moveToSerial(11)
@@ -565,22 +860,23 @@ e 3600 IN A 192.0.2.42
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(12)
         self.checkRPZStats(12, 1, 4, self._xfrDone)
-        self.checkNotBlocked('a.example.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
-        self.checkNotBlocked('d.example.')
-        self.checkNotBlocked('e.example.')
-        self.checkNXD('f.example.')
-        self.checkBlocked('g.example.', soa='zone.rpz.')
-        self.checkNXD('tc.example.')
-        self.checkNXD('drop.example.')
+        self.checkNotBlocked("a.example.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
+        self.checkNotBlocked("d.example.")
+        self.checkNotBlocked("e.example.")
+        self.checkNXD("f.example.")
+        self.checkBlocked("g.example.", soa="zone.rpz.")
+        self.checkNXD("tc.example.")
+        self.checkNXD("drop.example.")
+
 
 class RPZFileRecursorTest(RPZRecursorTest):
     """
     This test makes sure that we correctly load RPZ zones from a file
     """
 
-    _confdir = 'RPZFileRecursor'
+    _confdir = "RPZFileRecursor"
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", includeSOA=true })
     """ % (_confdir)
@@ -590,9 +886,10 @@ auth-zones=example=configs/%s/example.zone
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 b 3600 IN A 192.0.2.42
@@ -600,11 +897,13 @@ c 3600 IN A 192.0.2.42
 d 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
 z 3600 IN A 192.0.2.42
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 a.example.zone.rpz. 60 IN A 192.0.2.42
 a.example.zone.rpz. 60 IN A 192.0.2.43
@@ -612,29 +911,35 @@ a.example.zone.rpz. 60 IN TXT "some text"
 drop.example.zone.rpz. 60 IN CNAME rpz-drop.
 z.example.zone.rpz. 60 IN A 192.0.2.1
 tc.example.zone.rpz. 60 IN CNAME rpz-tcp-only.
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(RPZFileRecursorTest, cls).generateRecursorConfig(confdir)
 
     def testRPZ(self):
-        self.checkCustom('a.example.', 'A', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.42', '192.0.2.43'))
-        self.checkCustom('a.example.', 'TXT', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'TXT', '"some text"'))
-        self.checkBlocked('z.example.', soa='zone.rpz.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
-        self.checkNotBlocked('d.example.')
-        self.checkNotBlocked('e.example.')
+        self.checkCustom(
+            "a.example.", "A", dns.rrset.from_text("a.example.", 0, dns.rdataclass.IN, "A", "192.0.2.42", "192.0.2.43")
+        )
+        self.checkCustom(
+            "a.example.", "TXT", dns.rrset.from_text("a.example.", 0, dns.rdataclass.IN, "TXT", '"some text"')
+        )
+        self.checkBlocked("z.example.", soa="zone.rpz.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
+        self.checkNotBlocked("d.example.")
+        self.checkNotBlocked("e.example.")
         # check that the policy is disabled for AD=1 queries
-        self.checkNotBlocked('z.example.', True)
+        self.checkNotBlocked("z.example.", True)
         # check non-custom policies
-        self.checkTruncated('tc.example.', soa='zone.rpz.')
-        self.checkDropped('drop.example.')
+        self.checkTruncated("tc.example.", soa="zone.rpz.")
+        self.checkDropped("drop.example.")
+
 
 class RPZFileDefaultPolRecursorTest(RPZRecursorTest):
     """
     This test makes sure that we correctly load RPZ zones from a file with a default policy
     """
 
-    _confdir = 'RPZFileDefaultPolRecursor'
+    _confdir = "RPZFileDefaultPolRecursor"
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", defpol=Policy.NoAction })
     """ % (_confdir)
@@ -644,9 +949,10 @@ auth-zones=example=configs/%s/example.zone
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 b 3600 IN A 192.0.2.42
@@ -655,39 +961,43 @@ d 3600 IN A 192.0.2.42
 drop 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
 z 3600 IN A 192.0.2.42
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 a.example.zone.rpz. 60 IN A 192.0.2.42
 drop.example.zone.rpz. 60 IN CNAME rpz-drop.
 z.example.zone.rpz. 60 IN A 192.0.2.1
 tc.example.zone.rpz. 60 IN CNAME rpz-tcp-only.
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(RPZFileDefaultPolRecursorTest, cls).generateRecursorConfig(confdir)
 
     def testRPZ(self):
         # local data entries are overridden by default
-        self.checkCustom('a.example.', 'A', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.42'))
-        self.checkNoData('a.example.', 'TXT')
+        self.checkCustom("a.example.", "A", dns.rrset.from_text("a.example.", 0, dns.rdataclass.IN, "A", "192.0.2.42"))
+        self.checkNoData("a.example.", "TXT")
         # will not be blocked because the default policy overrides local data entries by default
-        self.checkNotBlocked('z.example.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
-        self.checkNotBlocked('d.example.')
-        self.checkNotBlocked('e.example.')
+        self.checkNotBlocked("z.example.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
+        self.checkNotBlocked("d.example.")
+        self.checkNotBlocked("e.example.")
         # check non-local policies, they should be overridden by the default policy
-        self.checkNXD('tc.example.', 'A')
-        self.checkNotBlocked('drop.example.')
+        self.checkNXD("tc.example.", "A")
+        self.checkNotBlocked("drop.example.")
+
 
 class RPZFileDefaultPolNotOverrideLocalRecursorTest(RPZRecursorTest):
     """
     This test makes sure that we correctly load RPZ zones from a file with a default policy, not overriding local data entries
     """
 
-    _confdir = 'RPZFileDefaultPolNotOverrideLocalRecursor'
+    _confdir = "RPZFileDefaultPolNotOverrideLocalRecursor"
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", defpol=Policy.NoAction, defpolOverrideLocalData=false })
     """ % (_confdir)
@@ -697,9 +1007,10 @@ auth-zones=example=configs/%s/example.zone
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 b 3600 IN A 192.0.2.42
@@ -708,11 +1019,13 @@ d 3600 IN A 192.0.2.42
 drop 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
 z 3600 IN A 192.0.2.42
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 a.example.zone.rpz. 60 IN A 192.0.2.42
 a.example.zone.rpz. 60 IN A 192.0.2.43
@@ -720,28 +1033,33 @@ a.example.zone.rpz. 60 IN TXT "some text"
 drop.example.zone.rpz. 60 IN CNAME rpz-drop.
 z.example.zone.rpz. 60 IN A 192.0.2.1
 tc.example.zone.rpz. 60 IN CNAME rpz-tcp-only.
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(RPZFileDefaultPolNotOverrideLocalRecursorTest, cls).generateRecursorConfig(confdir)
 
     def testRPZ(self):
         # local data entries will not be overridden by the default policy
-        self.checkCustom('a.example.', 'A', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.42', '192.0.2.43'))
-        self.checkCustom('a.example.', 'TXT', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'TXT', '"some text"'))
+        self.checkCustom(
+            "a.example.", "A", dns.rrset.from_text("a.example.", 0, dns.rdataclass.IN, "A", "192.0.2.42", "192.0.2.43")
+        )
+        self.checkCustom(
+            "a.example.", "TXT", dns.rrset.from_text("a.example.", 0, dns.rdataclass.IN, "TXT", '"some text"')
+        )
         # will be blocked because the default policy does not override local data entries
-        self.checkBlocked('z.example.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
-        self.checkNotBlocked('d.example.')
-        self.checkNotBlocked('e.example.')
+        self.checkBlocked("z.example.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
+        self.checkNotBlocked("d.example.")
+        self.checkNotBlocked("e.example.")
         # check non-local policies, they should be overridden by the default policy
-        self.checkNXD('tc.example.', 'A')
-        self.checkNotBlocked('drop.example.')
+        self.checkNXD("tc.example.", "A")
+        self.checkNotBlocked("drop.example.")
 
-class RPZSimpleAuthServer(object):
 
+class RPZSimpleAuthServer(object):
     def __init__(self, port):
         self._serverPort = port
-        listener = threading.Thread(name='RPZ Simple Auth Listener', target=self._listener, args=[])
+        listener = threading.Thread(name="RPZ Simple Auth Listener", target=self._listener, args=[])
         listener.daemon = True
         listener.start()
 
@@ -749,9 +1067,7 @@ class RPZSimpleAuthServer(object):
 
         response = dns.message.make_response(message)
         response.flags |= dns.flags.AA
-        records = [
-            dns.rrset.from_text('nsip.delegated.example.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.42')
-        ]
+        records = [dns.rrset.from_text("nsip.delegated.example.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.42")]
 
         response.answer = records
         return response
@@ -769,29 +1085,31 @@ class RPZSimpleAuthServer(object):
                 data, addr = sock.recvfrom(4096)
                 message = dns.message.from_wire(data)
                 if len(message.question) != 1:
-                    print('Invalid query, qdcount is %d' % (len(message.question)))
+                    print("Invalid query, qdcount is %d" % (len(message.question)))
                     break
 
                 answer = self._getAnswer(message)
                 if not answer:
-                    print('Unable to get a response for %s %d' % (message.question[0].name, message.question[0].rdtype))
+                    print("Unable to get a response for %s %d" % (message.question[0].name, message.question[0].rdtype))
                     break
 
                 wire = answer.to_wire()
                 sock.sendto(wire, addr)
 
             except socket.error as e:
-                print('Error in RPZ simple auth socket: %s' % str(e))
+                print("Error in RPZ simple auth socket: %s" % str(e))
+
 
 rpzAuthServerPort = 4260
 rpzAuthServer = RPZSimpleAuthServer(rpzAuthServerPort)
 
+
 class RPZOrderingPrecedenceRecursorTest(RPZRecursorTest):
     """
     This test makes sure that the recursor respects the RPZ ordering precedence rules
     """
 
-    _confdir = 'RPZOrderingPrecedenceRecursor'
+    _confdir = "RPZOrderingPrecedenceRecursor"
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz."})
     rpzFile('configs/%s/zone2.rpz', { policyName="zone2.rpz."})
@@ -803,36 +1121,42 @@ forward-zones=delegated.example=127.0.0.1:%d
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 sub.test 3600 IN A 192.0.2.42
 passthru-then-blocked-by-higher 3600 IN A 192.0.2.66
 passthru-then-blocked-by-same 3600 IN A 192.0.2.66
 blocked-then-passhtru-by-higher 3600 IN A 192.0.2.100
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 *.test.example.zone.rpz. 60 IN CNAME rpz-passthru.
 32.66.2.0.192.rpz-ip.zone.rpz. 60 IN A 192.0.2.1
 32.100.2.0.192.rpz-ip.zone.rpz. 60 IN CNAME rpz-passthru.
 passthru-then-blocked-by-same.example.zone.rpz. 60 IN CNAME rpz-passthru.
 32.1.0.0.127.rpz-nsip.zone.rpz. 60 IN CNAME rpz-passthru.
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone2.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone2.rpz.
+        rpzFilePath = os.path.join(confdir, "zone2.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone2.rpz.
 @ 3600 IN SOA {soa}
 sub.test.example.com.zone2.rpz. 60 IN CNAME .
 passthru-then-blocked-by-higher.example.zone2.rpz. 60 IN CNAME rpz-passthru.
 blocked-then-passhtru-by-higher.example.zone2.rpz. 60 IN A 192.0.2.1
 32.42.2.0.192.rpz-ip 60 IN CNAME .
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
         super(RPZOrderingPrecedenceRecursorTest, cls).generateRecursorConfig(confdir)
 
@@ -841,19 +1165,23 @@ blocked-then-passhtru-by-higher.example.zone2.rpz. 60 IN A 192.0.2.1
         # we respect the order of the RPZ zones), see the pass-thru rule
         # and only process RPZ rules of higher precedence.
         # The subsequent rule on the content of the A should therefore not trigger a NXDOMAIN.
-        self.checkNotBlocked('sub.test.example.')
+        self.checkNotBlocked("sub.test.example.")
 
     def testRPZOrderingWhitelistedThenBlockedByHigher(self):
         # we should first match on the qname from the second RPZ zone,
         # continue the resolution process, and get blocked by the content of the A record
         # based on the first RPZ zone, whose priority is higher than the second one.
-        self.checkBlocked('passthru-then-blocked-by-higher.example.')
+        self.checkBlocked("passthru-then-blocked-by-higher.example.")
 
     def testRPZOrderingWhitelistedThenBlockedBySame(self):
         # we should first match on the qname from the first RPZ zone,
         # continue the resolution process, and NOT get blocked by the content of the A record
         # based on the same RPZ zone, since it's not higher.
-        self.checkCustom('passthru-then-blocked-by-same.example.', 'A', dns.rrset.from_text('passthru-then-blocked-by-same.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.66'))
+        self.checkCustom(
+            "passthru-then-blocked-by-same.example.",
+            "A",
+            dns.rrset.from_text("passthru-then-blocked-by-same.example.", 0, dns.rdataclass.IN, "A", "192.0.2.66"),
+        )
 
     def testRPZOrderBlockedThenWhitelisted(self):
         # The qname is first blocked by the second RPZ zone
@@ -862,7 +1190,7 @@ blocked-then-passhtru-by-higher.example.zone2.rpz. 60 IN A 192.0.2.1
         # This is what the RPZ specification requires, but we currently decided that we
         # don't want to leak queries to malicious DNS servers and waste time if the qname is blacklisted.
         # We might change our opinion at some point, though.
-        self.checkBlocked('blocked-then-passhtru-by-higher.example.')
+        self.checkBlocked("blocked-then-passhtru-by-higher.example.")
 
     def testRPZOrderDelegate(self):
         # The IP of the NS we are going to contact is whitelisted (passthru) in zone 1,
@@ -870,14 +1198,15 @@ blocked-then-passhtru-by-higher.example.zone2.rpz. 60 IN A 192.0.2.1
         # by zone 2, it should not be blocked.
         # We only test once because after that the answer is cached, so the NS is not contacted
         # and the whitelist is not applied (yes, NSIP and NSDNAME are brittle).
-        self.checkNotBlocked('nsip.delegated.example.', singleCheck=True)
+        self.checkNotBlocked("nsip.delegated.example.", singleCheck=True)
+
 
 class RPZNSIPCustomTest(RPZRecursorTest):
     """
     This test makes sure that the recursor handles custom RPZ rules in a NSIP
     """
 
-    _confdir = 'RPZNSIPCustom'
+    _confdir = "RPZNSIPCustom"
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz."})
     rpzFile('configs/%s/zone2.rpz', { policyName="zone2.rpz."})
@@ -889,25 +1218,31 @@ forward-zones=delegated.example=127.0.0.1:%d
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 32.1.0.0.127.rpz-nsip.zone.rpz. 60 IN A 192.0.2.1
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone2.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone2.rpz.
+        rpzFilePath = os.path.join(confdir, "zone2.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone2.rpz.
 @ 3600 IN SOA {soa}
 32.1.2.0.192.rpz-ip 60 IN CNAME .
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
         super(RPZNSIPCustomTest, cls).generateRecursorConfig(confdir)
 
@@ -917,7 +1252,11 @@ forward-zones=delegated.example=127.0.0.1:%d
         # by zone 2, it should not be blocked.
         # We only test once because after that the answer is cached, so the NS is not contacted
         # and the whitelist is not applied (yes, NSIP and NSDNAME are brittle).
-        self.checkCustom('nsip.delegated.example.', 'A', dns.rrset.from_text('nsip.delegated.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1'))
+        self.checkCustom(
+            "nsip.delegated.example.",
+            "A",
+            dns.rrset.from_text("nsip.delegated.example.", 0, dns.rdataclass.IN, "A", "192.0.2.1"),
+        )
 
 
 class RPZResponseIPCNameChainCustomTest(RPZRecursorTest):
@@ -926,7 +1265,7 @@ class RPZResponseIPCNameChainCustomTest(RPZRecursorTest):
     and resolves the target of a custom CNAME.
     """
 
-    _confdir = 'RPZResponseIPCNameChainCustom'
+    _confdir = "RPZResponseIPCNameChainCustom"
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz."})
     """ % (_confdir)
@@ -937,22 +1276,26 @@ forward-zones=delegated.example=127.0.0.1:%d
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 name IN CNAME cname
 cname IN A 192.0.2.255
 custom-target IN A 192.0.2.254
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 cname.example IN CNAME custom-target.example.
 custom-target.example IN A 192.0.2.253
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
         super(RPZResponseIPCNameChainCustomTest, cls).generateRecursorConfig(confdir)
 
@@ -968,15 +1311,21 @@ custom-target.example IN A 192.0.2.253
 
         # two times to check the cache
         for _ in range(2):
-            query = dns.message.make_query('name.example.', 'A', want_dnssec=True)
+            query = dns.message.make_query("name.example.", "A", want_dnssec=True)
             query.flags |= dns.flags.CD
             for method in ("sendUDPQuery", "sendTCPQuery"):
                 sender = getattr(self, method)
                 res = sender(query)
                 self.assertRcodeEqual(res, dns.rcode.NOERROR)
-                self.assertRRsetInAnswer(res, dns.rrset.from_text('name.example.', 0, dns.rdataclass.IN, 'CNAME', 'cname.example.'))
-                self.assertRRsetInAnswer(res, dns.rrset.from_text('cname.example.', 0, dns.rdataclass.IN, 'CNAME', 'custom-target.example.'))
-                self.assertRRsetInAnswer(res, dns.rrset.from_text('custom-target.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.254'))
+                self.assertRRsetInAnswer(
+                    res, dns.rrset.from_text("name.example.", 0, dns.rdataclass.IN, "CNAME", "cname.example.")
+                )
+                self.assertRRsetInAnswer(
+                    res, dns.rrset.from_text("cname.example.", 0, dns.rdataclass.IN, "CNAME", "custom-target.example.")
+                )
+                self.assertRRsetInAnswer(
+                    res, dns.rrset.from_text("custom-target.example.", 0, dns.rdataclass.IN, "A", "192.0.2.254")
+                )
 
 
 class RPZCNameChainCustomTest(RPZRecursorTest):
@@ -986,8 +1335,8 @@ class RPZCNameChainCustomTest(RPZRecursorTest):
     (with QName Minimization).
     """
 
-    _PREFIX = os.environ['PREFIX']
-    _confdir = 'RPZCNameChainCustom'
+    _PREFIX = os.environ["PREFIX"]
+    _confdir = "RPZCNameChainCustom"
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz."})
     """ % (_confdir)
@@ -995,14 +1344,16 @@ class RPZCNameChainCustomTest(RPZRecursorTest):
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 32.100.2.0.192.rpz-ip IN CNAME .
 32.101.2.0.192.rpz-ip IN CNAME *.
 32.102.2.0.192.rpz-ip IN A 192.0.2.103
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
         super(RPZCNameChainCustomTest, cls).generateRecursorConfig(confdir)
 
@@ -1012,7 +1363,7 @@ class RPZCNameChainCustomTest(RPZRecursorTest):
 
         # two times to check the cache
         for _ in range(2):
-            query = dns.message.make_query('cname-nxd.example.', 'A', want_dnssec=True)
+            query = dns.message.make_query("cname-nxd.example.", "A", want_dnssec=True)
             query.flags |= dns.flags.CD
             for method in ("sendUDPQuery", "sendTCPQuery"):
                 sender = getattr(self, method)
@@ -1026,7 +1377,7 @@ class RPZCNameChainCustomTest(RPZRecursorTest):
 
         # two times to check the cache
         for _ in range(2):
-            query = dns.message.make_query('cname-nodata.example.', 'A', want_dnssec=True)
+            query = dns.message.make_query("cname-nodata.example.", "A", want_dnssec=True)
             query.flags |= dns.flags.CD
             for method in ("sendUDPQuery", "sendTCPQuery"):
                 sender = getattr(self, method)
@@ -1040,7 +1391,7 @@ class RPZCNameChainCustomTest(RPZRecursorTest):
 
         # two times to check the cache
         for _ in range(2):
-            query = dns.message.make_query('cname-custom-a.example.', 'A', want_dnssec=True)
+            query = dns.message.make_query("cname-custom-a.example.", "A", want_dnssec=True)
             query.flags |= dns.flags.CD
             for method in ("sendUDPQuery", "sendTCPQuery"):
                 sender = getattr(self, method)
@@ -1048,16 +1399,24 @@ class RPZCNameChainCustomTest(RPZRecursorTest):
                 self.assertRcodeEqual(res, dns.rcode.NOERROR)
                 # the original CNAME record is signed
                 self.assertEqual(len(res.answer), 3)
-                self.assertRRsetInAnswer(res, dns.rrset.from_text('cname-custom-a.example.', 0, dns.rdataclass.IN, 'CNAME', 'cname-custom-a-target.example.'))
-                self.assertRRsetInAnswer(res, dns.rrset.from_text('cname-custom-a-target.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.103'))
+                self.assertRRsetInAnswer(
+                    res,
+                    dns.rrset.from_text(
+                        "cname-custom-a.example.", 0, dns.rdataclass.IN, "CNAME", "cname-custom-a-target.example."
+                    ),
+                )
+                self.assertRRsetInAnswer(
+                    res, dns.rrset.from_text("cname-custom-a-target.example.", 0, dns.rdataclass.IN, "A", "192.0.2.103")
+                )
+
 
 class RPZCustomDefpolTest(RPZRecursorTest):
     """
     This test makes sure that the recursor applies defpol to hits and follows the CNAME
     """
 
-    _PREFIX = os.environ['PREFIX']
-    _confdir = 'RPZCustomDefpol'
+    _PREFIX = os.environ["PREFIX"]
+    _confdir = "RPZCustomDefpol"
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", defpol=Policy.Custom, defcontent="a.secure.example"})
     """ % (_confdir)
@@ -1065,34 +1424,41 @@ class RPZCustomDefpolTest(RPZRecursorTest):
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 hit.example IN CNAME .
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
         super(RPZCustomDefpolTest, cls).generateRecursorConfig(confdir)
 
     def testRPDefpol(self):
         # two times to check the cache
         for _ in range(2):
-            query = dns.message.make_query('hit.example.', 'A', want_dnssec=True)
+            query = dns.message.make_query("hit.example.", "A", want_dnssec=True)
             for method in ("sendUDPQuery", "sendTCPQuery"):
                 sender = getattr(self, method)
                 res = sender(query)
                 self.assertRcodeEqual(res, dns.rcode.NOERROR)
                 # the RPZ CNAME record is not signed
                 self.assertEqual(len(res.answer), 3)
-                self.assertRRsetInAnswer(res, dns.rrset.from_text('hit.example.', 0, dns.rdataclass.IN, 'CNAME', 'a.secure.example.'))
-                self.assertRRsetInAnswer(res, dns.rrset.from_text('a.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.20', '192.0.2.22'))
+                self.assertRRsetInAnswer(
+                    res, dns.rrset.from_text("hit.example.", 0, dns.rdataclass.IN, "CNAME", "a.secure.example.")
+                )
+                self.assertRRsetInAnswer(
+                    res, dns.rrset.from_text("a.secure.example.", 0, dns.rdataclass.IN, "A", "192.0.2.20", "192.0.2.22")
+                )
+
 
 class RPZFileModByLuaRecursorTest(RPZRecursorTest):
     """
     This test makes sure that we correctly load RPZ zones from a file while being modified by Lua callbacks
     """
 
-    _confdir = 'RPZFileModByLuaRecursor'
+    _confdir = "RPZFileModByLuaRecursor"
     _lua_dns_script_file = """
     function preresolve(dq)
       if dq.qname:equal('zmod.example.') then
@@ -1126,9 +1492,10 @@ auth-zones=example=configs/%s/example.zone
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 b 3600 IN A 192.0.2.42
@@ -1136,11 +1503,13 @@ c 3600 IN A 192.0.2.42
 d 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
 z 3600 IN A 192.0.2.42
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
 
-        rpzFilePath = os.path.join(confdir, 'zone.rpz')
-        with open(rpzFilePath, 'w') as rpzZone:
-            rpzZone.write("""$ORIGIN zone.rpz.
+        rpzFilePath = os.path.join(confdir, "zone.rpz")
+        with open(rpzFilePath, "w") as rpzZone:
+            rpzZone.write(
+                """$ORIGIN zone.rpz.
 @ 3600 IN SOA {soa}
 a.example.zone.rpz. 60 IN A 192.0.2.42
 a.example.zone.rpz. 60 IN A 192.0.2.43
@@ -1150,19 +1519,24 @@ zmod.example.zone.rpz. 60 IN A 192.0.2.1
 tc.example.zone.rpz. 60 IN CNAME rpz-tcp-only.
 nxmod.example.zone.rpz. 60 in CNAME .
 nodatamod.example.zone.rpz. 60 in CNAME *.
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(RPZFileModByLuaRecursorTest, cls).generateRecursorConfig(confdir)
 
     def testRPZ(self):
-        self.checkCustom('a.example.', 'A', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.42', '192.0.2.43'))
-        self.checkCustom('a.example.', 'TXT', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'TXT', '"some text"'))
-        self.checkDropped('zmod.example.')
-        self.checkDropped('nxmod.example.')
-        self.checkDropped('nodatamod.example.')
-        self.checkNotBlocked('b.example.')
-        self.checkNotBlocked('c.example.')
-        self.checkNotBlocked('d.example.')
-        self.checkNotBlocked('e.example.')
+        self.checkCustom(
+            "a.example.", "A", dns.rrset.from_text("a.example.", 0, dns.rdataclass.IN, "A", "192.0.2.42", "192.0.2.43")
+        )
+        self.checkCustom(
+            "a.example.", "TXT", dns.rrset.from_text("a.example.", 0, dns.rdataclass.IN, "TXT", '"some text"')
+        )
+        self.checkDropped("zmod.example.")
+        self.checkDropped("nxmod.example.")
+        self.checkDropped("nodatamod.example.")
+        self.checkNotBlocked("b.example.")
+        self.checkNotBlocked("c.example.")
+        self.checkNotBlocked("d.example.")
+        self.checkNotBlocked("e.example.")
         # check non-custom policies
-        self.checkTruncated('tc.example.')
-        self.checkDropped('drop.example.')
+        self.checkTruncated("tc.example.")
+        self.checkDropped("drop.example.")
index f8f9adc5f0fdefbc672c487b8dbbc9c482f340c8..d295af8ee7ef508db71876facf8cfdf39c5cf0a4 100644 (file)
@@ -9,13 +9,13 @@ import time
 
 from recursortests import RecursorTest
 
-class BadRPZServer(object):
 
+class BadRPZServer(object):
     def __init__(self, port):
         self._currentSerial = 0
         self._targetSerial = 1
         self._serverPort = port
-        listener = threading.Thread(name='RPZ Listener', target=self._listener, args=[])
+        listener = threading.Thread(name="RPZ Listener", target=self._listener, args=[])
         listener.daemon = True
         listener.start()
 
@@ -26,7 +26,7 @@ class BadRPZServer(object):
         if newSerial == self._currentSerial:
             return False
 
-        #if newSerial != self._currentSerial + 1:
+        # if newSerial != self._currentSerial + 1:
         #    raise AssertionError("Asking the RPZ server to serve serial %d, already serving %d" % (newSerial, self._currentSerial))
         self._targetSerial = newSerial
         return True
@@ -38,15 +38,29 @@ class BadRPZServer(object):
 
         if message.question[0].rdtype == dns.rdatatype.AXFR:
             if self._currentSerial != 0:
-                print('Received an AXFR query but IXFR expected because the current serial is %d' % (self._currentSerial))
+                print(
+                    "Received an AXFR query but IXFR expected because the current serial is %d" % (self._currentSerial)
+                )
                 return (None, self._currentSerial)
 
             newSerial = self._targetSerial
             records = [
-                dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                dns.rrset.from_text('a.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial)
-                ]
+                dns.rrset.from_text(
+                    "zone.rpz.",
+                    60,
+                    dns.rdataclass.IN,
+                    dns.rdatatype.SOA,
+                    "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                ),
+                dns.rrset.from_text("a.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                dns.rrset.from_text(
+                    "zone.rpz.",
+                    60,
+                    dns.rdataclass.IN,
+                    dns.rdatatype.SOA,
+                    "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                ),
+            ]
 
         elif message.question[0].rdtype == dns.rdatatype.IXFR:
             oldSerial = message.authority[0][0].serial
@@ -54,17 +68,41 @@ class BadRPZServer(object):
             newSerial = self._targetSerial
             if newSerial == 2:
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % oldSerial),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % oldSerial,
+                    ),
                     # no deletion
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('b.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("b.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                ]
             elif newSerial == 3:
                 records = [
-                    dns.rrset.from_text('zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1' % newSerial),
-                    dns.rrset.from_text('a.example.zone.rpz.', 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'),
-                    ]
+                    dns.rrset.from_text(
+                        "zone.rpz.",
+                        60,
+                        dns.rdataclass.IN,
+                        dns.rdatatype.SOA,
+                        "ns.zone.rpz. hostmaster.zone.rpz. %d 3600 3600 3600 1" % newSerial,
+                    ),
+                    dns.rrset.from_text("a.example.zone.rpz.", 60, dns.rdataclass.IN, dns.rdatatype.A, "192.0.2.1"),
+                ]
 
         response.answer = records
         return (newSerial, response)
@@ -82,14 +120,17 @@ class BadRPZServer(object):
 
             message = dns.message.from_wire(data)
             if len(message.question) != 1:
-                print('Invalid RPZ query, qdcount is %d' % (len(message.question)), file=sys.stderr)
+                print("Invalid RPZ query, qdcount is %d" % (len(message.question)), file=sys.stderr)
                 break
             if not message.question[0].rdtype in [dns.rdatatype.AXFR, dns.rdatatype.IXFR]:
-                print('Invalid RPZ query, qtype is %d' % (message.question.rdtype), file=sys.stderr)
+                print("Invalid RPZ query, qtype is %d" % (message.question.rdtype), file=sys.stderr)
                 break
             (serial, answer) = self._getAnswer(message)
             if not answer:
-                print('Unable to get a response for %s %d' % (message.question[0].name, message.question[0].rdtype), file=sys.stderr)
+                print(
+                    "Unable to get a response for %s %d" % (message.question[0].name, message.question[0].rdtype),
+                    file=sys.stderr,
+                )
                 break
 
             wire = answer.to_wire()
@@ -113,22 +154,21 @@ class BadRPZServer(object):
         while True:
             try:
                 (conn, _) = sock.accept()
-                thread = threading.Thread(name='RPZ Connection Handler',
-                                      target=self._connectionHandler,
-                                      args=[conn])
+                thread = threading.Thread(name="RPZ Connection Handler", target=self._connectionHandler, args=[conn])
                 thread.daemon = True
                 thread.start()
 
             except socket.error as e:
-                print('Error in RPZ socket: %s' % str(e))
+                print("Error in RPZ socket: %s" % str(e))
                 sock.close()
 
+
 class RPZIncompleteRecursorTest(RecursorTest):
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
-    _confdir = 'RPZIncompleteRecursor'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
+    _confdir = "RPZIncompleteRecursor"
 
     _config_template = """
 auth-zones=example=configs/%s/example.zone
@@ -141,27 +181,29 @@ log-rpz-changes=yes
 """ % (_confdir, _wsPort, _wsPassword, _apiKey)
 
     def checkRPZStats(self, serial, recordsCount, fullXFRCount, totalXFRCount, failedXFRCount):
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/rpzstatistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/rpzstatistics"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
-        self.assertIn('zone.rpz.', content)
-        zone = content['zone.rpz.']
-        for key in ['last_update', 'records', 'serial', 'transfers_failed', 'transfers_full', 'transfers_success']:
+        self.assertIn("zone.rpz.", content)
+        zone = content["zone.rpz."]
+        for key in ["last_update", "records", "serial", "transfers_failed", "transfers_full", "transfers_success"]:
             self.assertIn(key, zone)
 
-        self.assertEqual(zone['serial'], serial)
-        self.assertEqual(zone['records'], recordsCount)
-        self.assertEqual(zone['transfers_full'], fullXFRCount)
-        self.assertEqual(zone['transfers_success'], totalXFRCount)
-        self.assertEqual(zone['transfers_failed'], failedXFRCount)
+        self.assertEqual(zone["serial"], serial)
+        self.assertEqual(zone["records"], recordsCount)
+        self.assertEqual(zone["transfers_full"], fullXFRCount)
+        self.assertEqual(zone["transfers_success"], totalXFRCount)
+        self.assertEqual(zone["transfers_failed"], failedXFRCount)
+
 
 badrpzServerPort = 4251
 badrpzServer = BadRPZServer(badrpzServerPort)
 
+
 class RPZXFRIncompleteRecursorTest(RPZIncompleteRecursorTest):
     """
     This test makes sure that we correctly detect incomplete RPZ zones via AXFR then IXFR
@@ -172,11 +214,11 @@ class RPZXFRIncompleteRecursorTest(RPZIncompleteRecursorTest):
     -- The first server is a bogus one, to test that we correctly fail over to the second one
     rpzPrimary({'127.0.0.1:9999', '127.0.0.1:%d'}, 'zone.rpz.', { refresh=1 })
     """ % (badrpzServerPort)
-    _confdir = 'RPZXFRIncompleteRecursor'
+    _confdir = "RPZXFRIncompleteRecursor"
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
     _config_template = """
 auth-zones=example=configs/%s/example.zone
 webserver=yes
@@ -188,16 +230,18 @@ api-key=%s
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 b 3600 IN A 192.0.2.42
 c 3600 IN A 192.0.2.42
 d 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(RPZXFRIncompleteRecursorTest, cls).generateRecursorConfig(confdir)
 
     def waitUntilCorrectSerialIsLoaded(self, serial, timeout=5):
@@ -216,13 +260,16 @@ e 3600 IN A 192.0.2.42
             attempts = attempts + 1
             time.sleep(1)
 
-        raise AssertionError("Waited %d seconds for the serial to be updated to %d but the serial is still %d" % (timeout, serial, currentSerial))
+        raise AssertionError(
+            "Waited %d seconds for the serial to be updated to %d but the serial is still %d"
+            % (timeout, serial, currentSerial)
+        )
 
     def testRPZ(self):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
         # First zone
         self.waitUntilCorrectSerialIsLoaded(1)
-        self.checkRPZStats(1, 1, 1, 1, 1) # failure count includes a port 9999 attempt
+        self.checkRPZStats(1, 1, 1, 1, 1)  # failure count includes a port 9999 attempt
 
         # second zone, should fail, incomplete IXFR
         self.waitUntilCorrectSerialIsLoaded(2)
@@ -231,4 +278,3 @@ e 3600 IN A 192.0.2.42
         # third zone, should fail, incomplete AXFR
         self.waitUntilCorrectSerialIsLoaded(3)
         self.checkRPZStats(1, 1, 1, 1, 5)
-
index 16bca4e83e2e5b5e77fcd46a979b2a6342738cfb..f67f6b7fe8b2f26ca4abe5d0237ca9014ed6207f 100644 (file)
@@ -5,7 +5,7 @@ from recursortests import RecursorTest
 
 
 class ReadTrustAnchorsFromFileTest(RecursorTest):
-    _confdir = 'ReadTrustAnchorsFromFile'
+    _confdir = "ReadTrustAnchorsFromFile"
 
     _config_template = """dnssec=validate"""
     _lua_config_file = """clearTA()
@@ -13,9 +13,7 @@ readTrustAnchorsFromFile('root.keys')"""
 
     def testCorrectFile(self):
         """Ensure the file is read correctly"""
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'get-tas']
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % "configs/" + self._confdir, "get-tas"]
         expected = b"""Configured Trust Anchors:
 .
 \t\t36914 13 2 c94ed457ff79afe03804c26ce4fa832687db92bc231aff98617791fc71a65870
@@ -28,4 +26,3 @@ readTrustAnchorsFromFile('root.keys')"""
         except subprocess.CalledProcessError as e:
             print(e.output)
             raise
-
index bb9e1e5d8503afc33ec23e9d0f5a870ed6b1d1bd..bce53c8938d55785174dad1497f404a9a28228bd 100644 (file)
@@ -26,26 +26,26 @@ except ImportError:
 
 def checkDnstapBase(testinstance, dnstap, protocol, initiator, responder, response_port=53):
     testinstance.assertTrue(dnstap)
-    testinstance.assertTrue(dnstap.HasField('identity'))
-    #testinstance.assertEqual(dnstap.identity, b'a.server')
-    testinstance.assertTrue(dnstap.HasField('version'))
-    #testinstance.assertIn(b'dnsdist ', dnstap.version)
-    testinstance.assertTrue(dnstap.HasField('type'))
+    testinstance.assertTrue(dnstap.HasField("identity"))
+    # testinstance.assertEqual(dnstap.identity, b'a.server')
+    testinstance.assertTrue(dnstap.HasField("version"))
+    # testinstance.assertIn(b'dnsdist ', dnstap.version)
+    testinstance.assertTrue(dnstap.HasField("type"))
     testinstance.assertEqual(dnstap.type, dnstap.MESSAGE)
-    testinstance.assertTrue(dnstap.HasField('message'))
-    testinstance.assertTrue(dnstap.message.HasField('socket_protocol'))
+    testinstance.assertTrue(dnstap.HasField("message"))
+    testinstance.assertTrue(dnstap.message.HasField("socket_protocol"))
     testinstance.assertEqual(dnstap.message.socket_protocol, protocol)
-    testinstance.assertTrue(dnstap.message.HasField('socket_family'))
+    testinstance.assertTrue(dnstap.message.HasField("socket_family"))
     testinstance.assertEqual(dnstap.message.socket_family, dnstap_pb2.INET)
     #
     # The query address and port are from the recursor, we don't know the port
     #
-    testinstance.assertTrue(dnstap.message.HasField('query_address'))
+    testinstance.assertTrue(dnstap.message.HasField("query_address"))
     testinstance.assertEqual(socket.inet_ntop(socket.AF_INET, dnstap.message.query_address), initiator)
-    testinstance.assertTrue(dnstap.message.HasField('query_port'))
-    testinstance.assertTrue(dnstap.message.HasField('response_address'))
+    testinstance.assertTrue(dnstap.message.HasField("query_port"))
+    testinstance.assertTrue(dnstap.message.HasField("response_address"))
     testinstance.assertEqual(socket.inet_ntop(socket.AF_INET, dnstap.message.response_address), responder)
-    testinstance.assertTrue(dnstap.message.HasField('response_port'))
+    testinstance.assertTrue(dnstap.message.HasField("response_port"))
     testinstance.assertEqual(dnstap.message.response_port, response_port)
 
 
@@ -53,67 +53,73 @@ def checkDnstapQuery(testinstance, dnstap, protocol, initiator, responder):
     testinstance.assertEqual(dnstap.message.type, dnstap_pb2.Message.RESOLVER_QUERY)
     checkDnstapBase(testinstance, dnstap, protocol, initiator, responder)
 
-    testinstance.assertTrue(dnstap.message.HasField('query_time_sec'))
-    testinstance.assertTrue(dnstap.message.HasField('query_time_nsec'))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_sec"))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_nsec"))
 
-    testinstance.assertTrue(dnstap.message.HasField('query_message'))
+    testinstance.assertTrue(dnstap.message.HasField("query_message"))
     #
     # We cannot compare the incoming query with the outgoing one
     # The IDs and some other fields will be different
     #
-    #wire_message = dns.message.from_wire(dnstap.message.query_message)
-    #testinstance.assertEqual(wire_message, query)
+    # wire_message = dns.message.from_wire(dnstap.message.query_message)
+    # testinstance.assertEqual(wire_message, query)
+
 
 def checkDnstapNOD(testinstance, dnstap, protocol, initiator, responder, response_port, query_zone):
     testinstance.assertEqual(dnstap.message.type, dnstap_pb2.Message.CLIENT_QUERY)
     checkDnstapBase(testinstance, dnstap, protocol, initiator, responder, response_port)
 
-    testinstance.assertTrue(dnstap.message.HasField('query_time_sec'))
-    testinstance.assertTrue(dnstap.message.HasField('query_time_nsec'))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_sec"))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_nsec"))
 
-    testinstance.assertTrue(dnstap.message.HasField('query_zone'))
+    testinstance.assertTrue(dnstap.message.HasField("query_zone"))
     testinstance.assertEqual(dns.name.from_wire(dnstap.message.query_zone, 0)[0].to_text(), query_zone)
 
+
 def checkDnstapUDR(testinstance, dnstap, protocol, initiator, responder, response_port, query_zone):
     testinstance.assertEqual(dnstap.message.type, dnstap_pb2.Message.RESOLVER_RESPONSE)
     checkDnstapBase(testinstance, dnstap, protocol, initiator, responder, response_port)
 
-    testinstance.assertTrue(dnstap.message.HasField('query_time_sec'))
-    testinstance.assertTrue(dnstap.message.HasField('query_time_nsec'))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_sec"))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_nsec"))
 
-    testinstance.assertTrue(dnstap.message.HasField('query_zone'))
+    testinstance.assertTrue(dnstap.message.HasField("query_zone"))
     testinstance.assertEqual(dns.name.from_wire(dnstap.message.query_zone, 0)[0].to_text(), query_zone)
 
-    testinstance.assertTrue(dnstap.message.HasField('response_message'))
+    testinstance.assertTrue(dnstap.message.HasField("response_message"))
     wire_message = dns.message.from_wire(dnstap.message.response_message)
     testinstance.assertTrue(isinstance(wire_message, dns.message.Message))
 
+
 def checkDnstapExtra(testinstance, dnstap, expected):
-    testinstance.assertTrue(dnstap.HasField('extra'))
+    testinstance.assertTrue(dnstap.HasField("extra"))
     testinstance.assertEqual(dnstap.extra, expected)
 
 
 def checkDnstapNoExtra(testinstance, dnstap):
-    testinstance.assertFalse(dnstap.HasField('extra'))
+    testinstance.assertFalse(dnstap.HasField("extra"))
 
 
 def checkDnstapResponse(testinstance, dnstap, protocol, response, initiator, responder):
     testinstance.assertEqual(dnstap.message.type, dnstap_pb2.Message.RESOLVER_RESPONSE)
     checkDnstapBase(testinstance, dnstap, protocol, initiator, responder)
 
-    testinstance.assertTrue(dnstap.message.HasField('query_time_sec'))
-    testinstance.assertTrue(dnstap.message.HasField('query_time_nsec'))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_sec"))
+    testinstance.assertTrue(dnstap.message.HasField("query_time_nsec"))
 
-    testinstance.assertTrue(dnstap.message.HasField('response_time_sec'))
-    testinstance.assertTrue(dnstap.message.HasField('response_time_nsec'))
+    testinstance.assertTrue(dnstap.message.HasField("response_time_sec"))
+    testinstance.assertTrue(dnstap.message.HasField("response_time_nsec"))
 
-    testinstance.assertTrue(dnstap.message.response_time_sec > dnstap.message.query_time_sec or \
-                            dnstap.message.response_time_nsec > dnstap.message.query_time_nsec)
+    testinstance.assertTrue(
+        dnstap.message.response_time_sec > dnstap.message.query_time_sec
+        or dnstap.message.response_time_nsec > dnstap.message.query_time_nsec
+    )
 
-    testinstance.assertTrue(dnstap.message.HasField('response_message'))
+    testinstance.assertTrue(dnstap.message.HasField("response_message"))
     wire_message = dns.message.from_wire(dnstap.message.response_message)
     testinstance.assertEqual(wire_message, response)
 
+
 def fstrm_get_control_frame_type(data):
     (t,) = struct.unpack("!L", data[0:4])
     return t
@@ -122,21 +128,20 @@ def fstrm_get_control_frame_type(data):
 def fstrm_make_control_frame_reply(cft):
     if cft == FSTRM_CONTROL_READY:
         # Reply with ACCEPT frame and content-type
-        contenttype = b'protobuf:dnstap.Dnstap'
-        frame = struct.pack('!LLL', FSTRM_CONTROL_ACCEPT, 1,
-                            len(contenttype)) + contenttype
+        contenttype = b"protobuf:dnstap.Dnstap"
+        frame = struct.pack("!LLL", FSTRM_CONTROL_ACCEPT, 1, len(contenttype)) + contenttype
         buf = struct.pack("!LL", 0, len(frame)) + frame
         return buf
     elif cft == FSTRM_CONTROL_START:
         return None
     else:
-        raise Exception('unhandled control frame ' + str(cft))
+        raise Exception("unhandled control frame " + str(cft))
 
 
 def fstrm_read_and_dispatch_control_frame(conn):
     data = conn.recv(4)
     if not data:
-        raise Exception('length of control frame payload could not be read')
+        raise Exception("length of control frame payload could not be read")
     (datalen,) = struct.unpack("!L", data)
     data = conn.recv(datalen)
     cft = fstrm_get_control_frame_type(data)
@@ -167,7 +172,6 @@ def fstrm_handle_bidir_connection(conn, on_data):
             on_data(data)
 
 
-
 class DNSTapServerParams(object):
     def __init__(self, path):
         self.queue = Queue()
@@ -177,13 +181,13 @@ class DNSTapServerParams(object):
 DNSTapServerParameters = DNSTapServerParams("/tmp/dnstap.sock")
 DNSTapListeners = []
 
+
 class TestRecursorDNSTap(RecursorTest):
     @classmethod
     def FrameStreamUnixListener(cls, conn, param):
         while True:
             try:
-                fstrm_handle_bidir_connection(conn, lambda data: \
-                param.queue.put(data, True, timeout=2.0))
+                fstrm_handle_bidir_connection(conn, lambda data: param.queue.put(data, True, timeout=2.0))
             except socket.error as e:
                 if e.errno in (errno.EBADF, errno.EPIPE):
                     break
@@ -209,7 +213,9 @@ class TestRecursorDNSTap(RecursorTest):
         while True:
             try:
                 (conn, addr) = sock.accept()
-                listener = threading.Thread(name='DNSTap Worker', target=cls.FrameStreamUnixListener, args=[conn, param])
+                listener = threading.Thread(
+                    name="DNSTap Worker", target=cls.FrameStreamUnixListener, args=[conn, param]
+                )
                 listener.daemon = True
                 listener.start()
             except socket.error as e:
@@ -220,16 +226,18 @@ class TestRecursorDNSTap(RecursorTest):
         sock.close()
 
     @classmethod
-    @pytest.mark.skipif('dnstap-framestream' not in RecursorTest.recFeatures(), reason='dnstap feature not available')
+    @pytest.mark.skipif("dnstap-framestream" not in RecursorTest.recFeatures(), reason="dnstap feature not available")
     def setUpClass(cls):
         cls.setUpSockets()
         cls.startResponders()
 
-        listener = threading.Thread(name='DNSTap Listener', target=cls.FrameStreamUnixListenerMain, args=[DNSTapServerParameters])
+        listener = threading.Thread(
+            name="DNSTap Listener", target=cls.FrameStreamUnixListenerMain, args=[DNSTapServerParameters]
+        )
         listener.daemon = True
         listener.start()
 
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         cls.createConfigDir(confdir)
 
         cls.generateRecursorConfig(confdir)
@@ -243,9 +251,10 @@ class TestRecursorDNSTap(RecursorTest):
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'example.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN example.
+        authzonepath = os.path.join(confdir, "example.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN example.
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 tagged 3600 IN A 192.0.2.84
@@ -259,7 +268,8 @@ types 3600 IN SPF "v=spf1 -all"
 types 3600 IN SRV 10 20 443 a.example.
 cname 3600 IN CNAME a.example.
 
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(TestRecursorDNSTap, cls).generateRecursorConfig(confdir)
 
     @classmethod
@@ -278,6 +288,7 @@ cname 3600 IN CNAME a.example.
         dnstap.ParseFromString(data)
         return dnstap
 
+
 class DNSTapDefaultTest(TestRecursorDNSTap):
     """
     This test makes sure that we correctly export outgoing queries over DNSTap.
@@ -285,16 +296,22 @@ class DNSTapDefaultTest(TestRecursorDNSTap):
     that the recursor at least connects to the DNSTap server.
     """
 
-    _confdir = 'DNSTapDefault'
-    _config_template = """
-auth-zones=example=configs/%s/example.zone""" % _confdir
-    _lua_config_file = """
+    _confdir = "DNSTapDefault"
+    _config_template = (
+        """
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
+    _lua_config_file = (
+        """
 dnstapFrameStreamServer({"%s"})
-    """ % DNSTapServerParameters.path
+    """
+        % DNSTapServerParameters.path
+    )
 
     def testA(self):
-        name = 'www.example.org.'
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "www.example.org."
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
         self.assertNotEqual(res, None)
@@ -302,24 +319,27 @@ dnstapFrameStreamServer({"%s"})
         # check the dnstap message corresponding to the UDP query
         dnstap = self.getFirstDnstap()
 
-        checkDnstapQuery(self, dnstap, dnstap_pb2.UDP, '127.0.0.1', '127.0.0.8')
+        checkDnstapQuery(self, dnstap, dnstap_pb2.UDP, "127.0.0.1", "127.0.0.8")
         # We don't expect a response
         checkDnstapNoExtra(self, dnstap)
         # We don't expect anything more, but we'll sleep anyway to avoid a LeakSanitizer race
         time.sleep(1)
 
-class DNSTapLogNoQueriesTest(TestRecursorDNSTap):
 
-    _confdir = 'DNSTapLogNoQueries'
-    _config_template = """
-auth-zones=example=configs/%s/example.zone""" % _confdir
+class DNSTapLogNoQueriesTest(TestRecursorDNSTap):
+    _confdir = "DNSTapLogNoQueries"
+    _config_template = (
+        """
+auth-zones=example=configs/%s/example.zone"""
+        % _confdir
+    )
     _lua_config_file = """
 dnstapFrameStreamServer({"%s"}, {logQueries=false})
     """ % (DNSTapServerParameters.path)
 
     def testA(self):
-        name = 'www.example.org.'
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "www.example.org."
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
         self.assertNotEqual(res, None)
@@ -328,6 +348,7 @@ dnstapFrameStreamServer({"%s"}, {logQueries=false})
         time.sleep(1)
         self.assertTrue(DNSTapServerParameters.queue.empty())
 
+
 class DNSTapLogNODTest(TestRecursorDNSTap):
     """
     This test makes sure that we correctly export outgoing queries over DNSTap.
@@ -335,7 +356,7 @@ class DNSTapLogNODTest(TestRecursorDNSTap):
     that the recursor at least connects to the DNSTap server.
     """
 
-    _confdir = 'DNSTapLogNOD'
+    _confdir = "DNSTapLogNOD"
     _config_template = """
 new-domain-tracking=yes
 new-domain-history-dir=configs/%s/nod
@@ -349,13 +370,13 @@ dnstapNODFrameStreamServer({"%s"})
     @classmethod
     def generateRecursorConfig(cls, confdir):
         for directory in ["nod", "udr"]:
-            path = os.path.join('configs', cls._confdir, directory)
+            path = os.path.join("configs", cls._confdir, directory)
             cls.createConfigDir(path)
         super(DNSTapLogNODTest, cls).generateRecursorConfig(confdir)
 
     def testA(self):
-        name = 'types.example.'
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "types.example."
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
         self.assertNotEqual(res, None)
@@ -363,16 +384,16 @@ dnstapNODFrameStreamServer({"%s"})
         # check the dnstap message corresponding to the UDP query
         dnstap = self.getFirstDnstap()
 
-        checkDnstapNOD(self, dnstap, dnstap_pb2.UDP, '127.0.0.1', '127.0.0.1', 5300, name)
+        checkDnstapNOD(self, dnstap, dnstap_pb2.UDP, "127.0.0.1", "127.0.0.1", 5300, name)
         # We don't expect a response
         checkDnstapNoExtra(self, dnstap)
         # We don't expect anything more
         time.sleep(1)
         self.assertTrue(DNSTapServerParameters.queue.empty())
 
-class DNSTapLogUDRTest(TestRecursorDNSTap):
 
-    _confdir = 'DNSTapLogUDR'
+class DNSTapLogUDRTest(TestRecursorDNSTap):
+    _confdir = "DNSTapLogUDR"
     _config_template = """
 new-domain-tracking=yes
 new-domain-history-dir=configs/%s/nod
@@ -386,13 +407,13 @@ dnstapNODFrameStreamServer({"%s"}, {logNODs=false, logUDRs=true})
     @classmethod
     def generateRecursorConfig(cls, confdir):
         for directory in ["nod", "udr"]:
-            path = os.path.join('configs', cls._confdir, directory)
+            path = os.path.join("configs", cls._confdir, directory)
             cls.createConfigDir(path)
         super(DNSTapLogUDRTest, cls).generateRecursorConfig(confdir)
 
     def testA(self):
-        name = 'types.example.'
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "types.example."
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
         self.assertNotEqual(res, None)
@@ -400,16 +421,16 @@ dnstapNODFrameStreamServer({"%s"}, {logNODs=false, logUDRs=true})
         # check the dnstap message corresponding to the UDP query
         dnstap = self.getFirstDnstap()
 
-        checkDnstapUDR(self, dnstap, dnstap_pb2.UDP, '127.0.0.1', '127.0.0.1', 5300, name)
+        checkDnstapUDR(self, dnstap, dnstap_pb2.UDP, "127.0.0.1", "127.0.0.1", 5300, name)
         # We don't expect a rpasesponse
         checkDnstapNoExtra(self, dnstap)
         # We don't expect anything more
         time.sleep(1)
         self.assertTrue(DNSTapServerParameters.queue.empty())
 
-class DNSTapLogNODUDRTest(TestRecursorDNSTap):
 
-    _confdir = 'DNSTapLogNODUDR'
+class DNSTapLogNODUDRTest(TestRecursorDNSTap):
+    _confdir = "DNSTapLogNODUDR"
     _config_template = """
 new-domain-tracking=yes
 new-domain-history-dir=configs/%s/nod
@@ -423,22 +444,22 @@ dnstapNODFrameStreamServer({"%s"}, {logNODs=true, logUDRs=true})
     @classmethod
     def generateRecursorConfig(cls, confdir):
         for directory in ["nod", "udr"]:
-            path = os.path.join('configs', cls._confdir, directory)
+            path = os.path.join("configs", cls._confdir, directory)
             cls.createConfigDir(path)
         super(DNSTapLogNODUDRTest, cls).generateRecursorConfig(confdir)
 
     def testA(self):
-        name = 'types.example.'
-        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        name = "types.example."
+        query = dns.message.make_query(name, "A", want_dnssec=True)
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
         self.assertNotEqual(res, None)
 
         dnstap = self.getFirstDnstap()
-        checkDnstapUDR(self, dnstap, dnstap_pb2.UDP, '127.0.0.1', '127.0.0.1', 5300, name)
+        checkDnstapUDR(self, dnstap, dnstap_pb2.UDP, "127.0.0.1", "127.0.0.1", 5300, name)
 
         dnstap = self.getFirstDnstap()
-        checkDnstapNOD(self, dnstap, dnstap_pb2.UDP, '127.0.0.1', '127.0.0.1', 5300, name)
+        checkDnstapNOD(self, dnstap, dnstap_pb2.UDP, "127.0.0.1", "127.0.0.1", 5300, name)
 
         checkDnstapNoExtra(self, dnstap)
         # We don't expect anything more
index 62d60c5824de8dbf74b50bbff4ea5761b9e94487..f0a879c419a284ae635c1e9ff1f684cc1b90d85a 100644 (file)
@@ -5,19 +5,19 @@ import extendederrors
 
 from recursortests import RecursorTest
 
-class RootNXTrustRecursorTest(RecursorTest):
 
+class RootNXTrustRecursorTest(RecursorTest):
     def getOutgoingQueriesCount(self):
-        headers = {'x-api-key': self._apiKey}
-        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        headers = {"x-api-key": self._apiKey}
+        url = "http://127.0.0.1:" + str(self._wsPort) + "/api/v1/servers/localhost/statistics"
         r = requests.get(url, headers=headers, timeout=self._wsTimeout)
         self.assertTrue(r)
         self.assertEqual(r.status_code, 200)
         self.assertTrue(r.json())
         content = r.json()
         for entry in content:
-            if entry['name'] == 'all-outqueries':
-                return int(entry['value'])
+            if entry["name"] == "all-outqueries":
+                return int(entry["value"])
 
         return 0
 
@@ -26,19 +26,20 @@ class RootNXTrustRecursorTest(RecursorTest):
     # Code below is inherently racey, but better than a fixed sleep
     def waitForOutgoingToStabilize(self):
         for count in range(20):
-            outgoing1 = self.getOutgoingQueriesCount();
-            time.sleep(0.1);
-            outgoing2 = self.getOutgoingQueriesCount();
+            outgoing1 = self.getOutgoingQueriesCount()
+            time.sleep(0.1)
+            outgoing2 = self.getOutgoingQueriesCount()
             if outgoing1 == outgoing2:
                 break
 
+
 class RootNXTrustDisabledTest(RootNXTrustRecursorTest):
-    _confdir = 'RootNXTrustDisabled'
+    _confdir = "RootNXTrustDisabled"
     _auth_zones = RecursorTest._default_auth_zones
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
 
     _config_template = """
 root-nx-trust=no
@@ -62,7 +63,7 @@ extended-resolution-errors
         self.waitForOutgoingToStabilize()
         # First query nx.example.
         before = self.getOutgoingQueriesCount()
-        query = dns.message.make_query('www.nx-example.', 'A')
+        query = dns.message.make_query("www.nx-example.", "A")
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
@@ -75,7 +76,7 @@ extended-resolution-errors
 
         # then query nx2.example.
         before = after
-        query = dns.message.make_query('www2.nx-example.', 'A', use_edns=True)
+        query = dns.message.make_query("www2.nx-example.", "A", use_edns=True)
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
@@ -86,13 +87,14 @@ extended-resolution-errors
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 0)
 
+
 class RootNXTrustEnabledTest(RootNXTrustRecursorTest):
-    _confdir = 'RootNXTrustEnabled'
+    _confdir = "RootNXTrustEnabled"
     _auth_zones = RecursorTest._default_auth_zones
     _wsPort = 8042
     _wsTimeout = 2
-    _wsPassword = 'secretpassword'
-    _apiKey = 'secretapikey'
+    _wsPassword = "secretpassword"
+    _apiKey = "secretapikey"
 
     _config_template = """
 root-nx-trust=yes
@@ -115,7 +117,7 @@ extended-resolution-errors
         self.waitForOutgoingToStabilize()
         # first query nx.example.
         before = self.getOutgoingQueriesCount()
-        query = dns.message.make_query('www.nx-example.', 'A')
+        query = dns.message.make_query("www.nx-example.", "A")
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
@@ -128,7 +130,7 @@ extended-resolution-errors
 
         # then query nx2.example.
         before = after
-        query = dns.message.make_query('www2.nx-example.', 'A', use_edns=True)
+        query = dns.message.make_query("www2.nx-example.", "A", use_edns=True)
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
@@ -139,4 +141,4 @@ extended-resolution-errors
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 1)
         self.assertEqual(res.options[0].otype, 15)
-        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized by root-nx-trust'))
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b"Result synthesized by root-nx-trust"))
index 63d29211f516561e99c814ed0773862065c1fef2..5a10c7d1cb4f6454bfa45c4db4cec065b6cf745a 100644 (file)
@@ -9,12 +9,13 @@ from recursortests import RecursorTest
 from twisted.internet.protocol import DatagramProtocol
 from twisted.internet import reactor
 
-emptyECSText = 'No ECS received'
-nameECS = 'ecs-echo.example.'
-nameECSInvalidScope = 'invalid-scope.ecs-echo.example.'
+emptyECSText = "No ECS received"
+nameECS = "ecs-echo.example."
+nameECSInvalidScope = "invalid-scope.ecs-echo.example."
 ttlECS = 60
 routingReactorRunning = False
 
+
 class RoutingTagTest(RecursorTest):
     _config_template_default = """
 daemon=no
@@ -63,7 +64,7 @@ ecs-add-for=0.0.0.0/0
 
     def setRoutingTag(self, tag):
         # This value is picked up by the gettag()
-        with open('tagfile', 'w') as file:
+        with open("tagfile", "w") as file:
             if tag:
                 file.write(tag)
 
@@ -72,7 +73,7 @@ ecs-add-for=0.0.0.0/0
         global routingReactorRunning
         print("Launching responders..")
 
-        address = cls._PREFIX + '.24'
+        address = cls._PREFIX + ".24"
         port = 53
 
         if not routingReactorRunning:
@@ -83,17 +84,18 @@ ecs-add-for=0.0.0.0/0
 
     @classmethod
     def tearDownClass(cls):
-        os.unlink('tagfile')
+        os.unlink("tagfile")
         super().tearDownClass()
 
+
 class RoutingTagTest(RoutingTagTest):
-    _confdir = 'RoutingTag'
+    _confdir = "RoutingTag"
 
     _config_template = """
 use-incoming-edns-subnet=yes
 edns-subnet-allow-list=ecs-echo.example.
 forward-zones=ecs-echo.example=%s.24
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
     _lua_dns_script_file = """
 
 function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp, proxyProtocolValues)
@@ -108,53 +110,51 @@ end
 
     def testSendECS(self):
         # First send an ECS query with routingTag
-        self.setRoutingTag('foo')
-        expected1 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.0.2.0/24')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        self.setRoutingTag("foo")
+        expected1 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.0.2.0/24")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected1)
 
         # Now check a cache hit with the same routingTag (but no ECS)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN')
+        query = dns.message.make_query(nameECS, "TXT", "IN")
         self.checkECSQueryHit(query, expected1)
 
-        expected2 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
+        expected2 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
         # And see if a different tag does *not* hit the first one
-        self.setRoutingTag('bar')
-        query = dns.message.make_query(nameECS, 'TXT', 'IN')
+        self.setRoutingTag("bar")
+        query = dns.message.make_query(nameECS, "TXT", "IN")
         self.sendECSQuery(query, expected2)
 
         # And see if a *no* tag does *not* hit the first one
-        expected3 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.0.3.0/24')
+        expected3 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.0.3.0/24")
         self.setRoutingTag(None)
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.3.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.3.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected3)
 
         # And see if an unknown tag from the same subnet does hit the last
-        self.setRoutingTag('baz')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.3.2', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        self.setRoutingTag("baz")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.3.2", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.checkECSQueryHit(query, expected3)
 
         # And a no tag and no subnet query does hit the general case
         self.setRoutingTag(None)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN')
+        query = dns.message.make_query(nameECS, "TXT", "IN")
         self.sendECSQuery(query, expected2)
 
         # And an unknown tag and no subnet query does hit the general case
-        self.setRoutingTag('bag')
-        query = dns.message.make_query(nameECS, 'TXT', 'IN')
+        self.setRoutingTag("bag")
+        query = dns.message.make_query(nameECS, "TXT", "IN")
         self.sendECSQuery(query, expected2)
 
-        if not "PEEK_AT_CACHE" in os.environ: # set to peek at cache
+        if not "PEEK_AT_CACHE" in os.environ:  # set to peek at cache
             return
 
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'dump-cache', 'x']
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % "configs/" + self._confdir, "dump-cache", "x"]
         try:
-            expected = b'dumped 7 records\n'
+            expected = b"dumped 7 records\n"
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
             self.assertEqual(ret, expected)
 
@@ -162,14 +162,15 @@ end
             print(e.output)
             raise
 
+
 class RoutingTagFFITest(RoutingTagTest):
-    _confdir = 'RoutingTagFFI'
+    _confdir = "RoutingTagFFI"
 
     _config_template = """
 use-incoming-edns-subnet=yes
 edns-subnet-allow-list=ecs-echo.example.
 forward-zones=ecs-echo.example=%s.24
-    """ % (os.environ['PREFIX'])
+    """ % (os.environ["PREFIX"])
     _lua_dns_script_file = """
 
 local ffi = require("ffi")
@@ -189,55 +190,54 @@ function gettag_ffi(obj)
   return 0
 end
 """
+
     def testSendECS(self):
         # First send an ECS query with routingTag
-        self.setRoutingTag('foo')
-        expected1 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.0.2.0/24')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        self.setRoutingTag("foo")
+        expected1 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.0.2.0/24")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.2.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected1)
 
         # Now check a cache hit with the same routingTag (but no ECS)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN')
+        query = dns.message.make_query(nameECS, "TXT", "IN")
         self.checkECSQueryHit(query, expected1)
 
-        expected2 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '127.0.0.0/24')
+        expected2 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "127.0.0.0/24")
         # And see if a different tag does *not* hit the first one
-        self.setRoutingTag('bar')
-        query = dns.message.make_query(nameECS, 'TXT', 'IN')
+        self.setRoutingTag("bar")
+        query = dns.message.make_query(nameECS, "TXT", "IN")
         self.sendECSQuery(query, expected2)
 
         # And see if a *no* tag does *not* hit the first one
-        expected3 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'TXT', '192.0.3.0/24')
+        expected3 = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "TXT", "192.0.3.0/24")
         self.setRoutingTag(None)
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.3.1', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.3.1", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected3)
 
         # And see if an unknown tag from the same subnet does hit the last
-        self.setRoutingTag('baz')
-        ecso = clientsubnetoption.ClientSubnetOption('192.0.3.2', 32)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
+        self.setRoutingTag("baz")
+        ecso = clientsubnetoption.ClientSubnetOption("192.0.3.2", 32)
+        query = dns.message.make_query(nameECS, "TXT", "IN", use_edns=True, options=[ecso], payload=512)
         self.checkECSQueryHit(query, expected3)
 
         # And a no tag and no subnet query does hit the general case
         self.setRoutingTag(None)
-        query = dns.message.make_query(nameECS, 'TXT', 'IN')
+        query = dns.message.make_query(nameECS, "TXT", "IN")
         self.sendECSQuery(query, expected2)
 
         # And an unknown tag and no subnet query does hit the general case
-        self.setRoutingTag('bag')
-        query = dns.message.make_query(nameECS, 'TXT', 'IN')
+        self.setRoutingTag("bag")
+        query = dns.message.make_query(nameECS, "TXT", "IN")
         self.sendECSQuery(query, expected2)
 
-        if not "PEEK_AT_CACHE" in os.environ: # set to peek at cache
+        if not "PEEK_AT_CACHE" in os.environ:  # set to peek at cache
             return
 
-        rec_controlCmd = [os.environ['RECCONTROL'],
-                          '--config-dir=%s' % 'configs/' + self._confdir,
-                          'dump-cache y']
+        rec_controlCmd = [os.environ["RECCONTROL"], "--config-dir=%s" % "configs/" + self._confdir, "dump-cache y"]
         try:
-            expected = 'dumped 6 records\n'
+            expected = "dumped 6 records\n"
             ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
             self.assertEqual(ret, expected)
 
@@ -245,16 +245,14 @@ end
             print(e.output)
             raise
 
+
 class UDPRoutingResponder(DatagramProtocol):
     @staticmethod
     def ipToStr(option):
         if option.family == clientsubnetoption.FAMILY_IPV4:
-            ip = socket.inet_ntop(socket.AF_INET, struct.pack('!L', option.ip))
+            ip = socket.inet_ntop(socket.AF_INET, struct.pack("!L", option.ip))
         elif option.family == clientsubnetoption.FAMILY_IPV6:
-            ip = socket.inet_ntop(socket.AF_INET6,
-                                  struct.pack('!QQ',
-                                              option.ip >> 64,
-                                              option.ip & (2 ** 64 - 1)))
+            ip = socket.inet_ntop(socket.AF_INET6, struct.pack("!QQ", option.ip >> 64, option.ip & (2**64 - 1)))
         return ip
 
     def datagramReceived(self, datagram, address):
@@ -264,12 +262,16 @@ class UDPRoutingResponder(DatagramProtocol):
         response.flags |= dns.flags.AA
         ecso = None
 
-        if (request.question[0].name == dns.name.from_text(nameECS) or request.question[0].name == dns.name.from_text(nameECSInvalidScope)) and request.question[0].rdtype == dns.rdatatype.TXT:
-
+        if (
+            request.question[0].name == dns.name.from_text(nameECS)
+            or request.question[0].name == dns.name.from_text(nameECSInvalidScope)
+        ) and request.question[0].rdtype == dns.rdatatype.TXT:
             text = emptyECSText
             for option in request.options:
-                if option.otype == clientsubnetoption.ASSIGNED_OPTION_CODE and isinstance(option, clientsubnetoption.ClientSubnetOption):
-                    text = self.ipToStr(option) + '/' + str(option.mask)
+                if option.otype == clientsubnetoption.ASSIGNED_OPTION_CODE and isinstance(
+                    option, clientsubnetoption.ClientSubnetOption
+                ):
+                    text = self.ipToStr(option) + "/" + str(option.mask)
 
                     # Send a scope more specific than the received source for nameECSInvalidScope
                     if request.question[0].name == dns.name.from_text(nameECSInvalidScope):
@@ -277,16 +279,18 @@ class UDPRoutingResponder(DatagramProtocol):
                     else:
                         ecso = clientsubnetoption.ClientSubnetOption(self.ipToStr(option), option.mask, option.mask)
 
-            answer = dns.rrset.from_text(request.question[0].name, ttlECS, dns.rdataclass.IN, 'TXT', text)
+            answer = dns.rrset.from_text(request.question[0].name, ttlECS, dns.rdataclass.IN, "TXT", text)
             response.answer.append(answer)
 
         elif request.question[0].name == dns.name.from_text(nameECS) and request.question[0].rdtype == dns.rdatatype.NS:
-            answer = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, 'NS', 'ns1.ecs-echo.example.')
+            answer = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN, "NS", "ns1.ecs-echo.example.")
             response.answer.append(answer)
-            additional = dns.rrset.from_text('ns1.ecs-echo.example.', 15, dns.rdataclass.IN, 'A', os.environ['PREFIX'] + '.24')
+            additional = dns.rrset.from_text(
+                "ns1.ecs-echo.example.", 15, dns.rdataclass.IN, "A", os.environ["PREFIX"] + ".24"
+            )
             response.additional.append(additional)
 
         if ecso:
-            response.use_edns(options = [ecso])
+            response.use_edns(options=[ecso])
 
         self.transport.write(response.to_wire(), address)
index 2826386475a952a42f6e22b94e2b3c465e9806c4..b3c2a1f9266ae1723cfcd3ebfbe64598e1597b05 100644 (file)
@@ -4,18 +4,18 @@ from pysnmp.hlapi import *
 
 from recursortests import RecursorTest
 
-class SNMPTest(RecursorTest):
 
+class SNMPTest(RecursorTest):
     _snmpTimeout = 2.0
-    _snmpServer = '127.0.0.1'
+    _snmpServer = "127.0.0.1"
     _snmpPort = 161
-    _snmpV2Community = 'secretcommunity'
-    _snmpV3User = 'secretuser'
-    _snmpV3AuthKey = 'mysecretauthkey'
-    _snmpV3EncKey = 'mysecretenckey'
-    _snmpOID = '1.3.6.1.4.1.43315.2'
+    _snmpV2Community = "secretcommunity"
+    _snmpV3User = "secretuser"
+    _snmpV3AuthKey = "mysecretauthkey"
+    _snmpV3EncKey = "mysecretenckey"
+    _snmpOID = "1.3.6.1.4.1.43315.2"
     _queriesSent = 0
-    _confdir = 'SNMP'
+    _confdir = "SNMP"
     _config_template = """
     snmp-agent=yes
     """
@@ -23,26 +23,28 @@ class SNMPTest(RecursorTest):
     def _checkStatsValues(self, results):
         count = 161
         for i in list(range(1, count)):
-            oid = self._snmpOID + '.1.' + str(i) + '.0'
+            oid = self._snmpOID + ".1." + str(i) + ".0"
             self.assertIn(oid, results)
             self.assertTrue(isinstance(results[oid], Counter64))
 
-        oid = self._snmpOID + '.1.' + str(count + 1) + '.0'
+        oid = self._snmpOID + ".1." + str(count + 1) + ".0"
         self.assertNotIn(oid, results)
 
         # check uptime > 0
-        self.assertGreater(results['1.3.6.1.4.1.43315.2.1.75.0'], 0)
+        self.assertGreater(results["1.3.6.1.4.1.43315.2.1.75.0"], 0)
         # check memory usage > 0
-        self.assertGreater(results['1.3.6.1.4.1.43315.2.1.76.0'], 0)
+        self.assertGreater(results["1.3.6.1.4.1.43315.2.1.76.0"], 0)
 
     def _getSNMPStats(self, auth):
         results = {}
-        for (errorIndication, errorStatus, errorIndex, varBinds) in nextCmd(SnmpEngine(),
-                                                                            auth,
-                                                                            UdpTransportTarget((self._snmpServer, self._snmpPort), timeout=self._snmpTimeout),
-                                                                            ContextData(),
-                                                                            ObjectType(ObjectIdentity(self._snmpOID)),
-                                                                            lookupMib=False):
+        for errorIndication, errorStatus, errorIndex, varBinds in nextCmd(
+            SnmpEngine(),
+            auth,
+            UdpTransportTarget((self._snmpServer, self._snmpPort), timeout=self._snmpTimeout),
+            ContextData(),
+            ObjectType(ObjectIdentity(self._snmpOID)),
+            lookupMib=False,
+        ):
             self.assertFalse(errorIndication)
             self.assertFalse(errorStatus)
             self.assertTrue(varBinds)
@@ -74,9 +76,11 @@ class SNMPTest(RecursorTest):
         SNMP: Retrieve statistics via SNMPv3
         """
 
-        auth = UsmUserData(self._snmpV3User,
-                               authKey=self._snmpV3AuthKey,
-                               privKey=self._snmpV3EncKey,
-                               authProtocol=usmHMACSHAAuthProtocol,
-                               privProtocol=usmAesCfb128Protocol)
+        auth = UsmUserData(
+            self._snmpV3User,
+            authKey=self._snmpV3AuthKey,
+            privKey=self._snmpV3EncKey,
+            authProtocol=usmHMACSHAAuthProtocol,
+            privProtocol=usmAesCfb128Protocol,
+        )
         self._checkStats(auth)
index 4fdcc804c2d1576ffb6cc9001e6cd284253d59ed..320275151c82d463db0a8fb714e474148f372eed 100644 (file)
@@ -1,29 +1,29 @@
 import dns
 from recursortests import RecursorTest
 
+
 class ServerNamesTest(RecursorTest):
     """
     This tests all kinds naming things
     """
 
-    _confdir = 'ServerNames'
+    _confdir = "ServerNames"
     _auth_zones = RecursorTest._default_auth_zones
-    _servername = 'awesome-pdns1.example.com'
-    _versionbind = 'Awesome!'
-    _versionbind_expected = dns.rrset.from_text('version.bind.', 86400, 'CH', 'TXT', _versionbind)
-    _idserver_expected = dns.rrset.from_text('id.server.', 86400, 'CH', 'TXT', _servername)
+    _servername = "awesome-pdns1.example.com"
+    _versionbind = "Awesome!"
+    _versionbind_expected = dns.rrset.from_text("version.bind.", 86400, "CH", "TXT", _versionbind)
+    _idserver_expected = dns.rrset.from_text("id.server.", 86400, "CH", "TXT", _servername)
 
     _config_template = """
 server-id=%s
 version-string=%s
     """ % (_servername, _versionbind)
 
-
     def testVersionBindUDP(self):
         """
         Send a version.bind CH TXT query over UDP and look for the version string
         """
-        query = dns.message.make_query('version.bind', 'TXT', 'CH', use_edns=False)
+        query = dns.message.make_query("version.bind", "TXT", "CH", use_edns=False)
         response = self.sendUDPQuery(query)
 
         self.assertEqual(len(response.answer), 1)
@@ -33,7 +33,7 @@ version-string=%s
         """
         Send a version.bind CH TXT query over TCP and look for the version string
         """
-        query = dns.message.make_query('version.bind', 'TXT', 'CH', use_edns=False)
+        query = dns.message.make_query("version.bind", "TXT", "CH", use_edns=False)
         response = self.sendTCPQuery(query)
 
         self.assertEqual(len(response.answer), 1)
@@ -43,7 +43,7 @@ version-string=%s
         """
         Send a version.bind CH TXT query over UDP (with EDNS) and look for the version string
         """
-        query = dns.message.make_query('version.bind', 'TXT', 'CH', use_edns=True)
+        query = dns.message.make_query("version.bind", "TXT", "CH", use_edns=True)
         response = self.sendUDPQuery(query)
 
         self.assertEqual(len(response.answer), 1)
@@ -53,7 +53,7 @@ version-string=%s
         """
         Send a version.bind CH TXT query over TCP (with EDNS) and look for the version string
         """
-        query = dns.message.make_query('version.bind', 'TXT', 'CH', use_edns=True)
+        query = dns.message.make_query("version.bind", "TXT", "CH", use_edns=True)
         response = self.sendTCPQuery(query)
 
         self.assertEqual(len(response.answer), 1)
@@ -63,7 +63,7 @@ version-string=%s
         """
         Send an id.server CH TXT query over UDP and look for the server id
         """
-        query = dns.message.make_query('id.server', 'TXT', 'CH', use_edns=False)
+        query = dns.message.make_query("id.server", "TXT", "CH", use_edns=False)
         response = self.sendUDPQuery(query)
 
         self.assertEqual(len(response.answer), 1)
@@ -73,7 +73,7 @@ version-string=%s
         """
         Send an id.server CH TXT query over TCP and look for the server id
         """
-        query = dns.message.make_query('id.server', 'TXT', 'CH', use_edns=False)
+        query = dns.message.make_query("id.server", "TXT", "CH", use_edns=False)
         response = self.sendTCPQuery(query)
 
         self.assertEqual(len(response.answer), 1)
@@ -83,7 +83,7 @@ version-string=%s
         """
         Send an id.server CH TXT query over UDP (with EDNS) and look for the server id
         """
-        query = dns.message.make_query('id.server', 'TXT', 'CH', use_edns=True)
+        query = dns.message.make_query("id.server", "TXT", "CH", use_edns=True)
         response = self.sendUDPQuery(query)
 
         self.assertEqual(len(response.answer), 1)
@@ -93,7 +93,7 @@ version-string=%s
         """
         Send an id.server CH TXT query over TCP (with EDNS) and look for the server id
         """
-        query = dns.message.make_query('id.server', 'TXT', 'CH', use_edns=True)
+        query = dns.message.make_query("id.server", "TXT", "CH", use_edns=True)
         response = self.sendTCPQuery(query)
 
         self.assertEqual(len(response.answer), 1)
@@ -103,26 +103,26 @@ version-string=%s
         """
         Send a .|NS query with NSID option
         """
-        opts = [dns.edns.GenericOption(dns.edns.NSID, b'')]
-        query = dns.message.make_query('.', 'NS', 'IN', use_edns=True, options=opts)
+        opts = [dns.edns.GenericOption(dns.edns.NSID, b"")]
+        query = dns.message.make_query(".", "NS", "IN", use_edns=True, options=opts)
         response = self.sendUDPQuery(query)
 
         self.assertEqual(len(response.options), 1)
         if dns.version.MAJOR < 2 or (dns.version.MAJOR == 2 and dns.version.MINOR < 6):
-            self.assertEqual(response.options[0].data, self._servername.encode('ascii'))
+            self.assertEqual(response.options[0].data, self._servername.encode("ascii"))
         else:
-            self.assertEqual(response.options[0].to_text(), 'NSID ' + self._servername)
+            self.assertEqual(response.options[0].to_text(), "NSID " + self._servername)
 
     def testNSIDTCP(self):
         """
         Send a .|NS query with NSID option
         """
-        opts = [dns.edns.GenericOption(dns.edns.NSID, b'')]
-        query = dns.message.make_query('.', 'NS', 'IN', use_edns=True, options=opts)
+        opts = [dns.edns.GenericOption(dns.edns.NSID, b"")]
+        query = dns.message.make_query(".", "NS", "IN", use_edns=True, options=opts)
         response = self.sendTCPQuery(query)
 
         self.assertEqual(len(response.options), 1)
         if dns.version.MAJOR < 2 or (dns.version.MAJOR == 2 and dns.version.MINOR < 6):
-            self.assertEqual(response.options[0].data, self._servername.encode('ascii'))
+            self.assertEqual(response.options[0].data, self._servername.encode("ascii"))
         else:
-            self.assertEqual(response.options[0].to_text(), 'NSID ' + self._servername)
+            self.assertEqual(response.options[0].to_text(), "NSID " + self._servername)
index 8090e08192cd04bc0eb05f1b9a3518e296e9f453..f54f4be4deaab63832ff5f466b2bb7598b54b3f5 100644 (file)
@@ -2,27 +2,33 @@ import dns
 import os
 from recursortests import RecursorTest
 
+
 class SimpleTest(RecursorTest):
-    _confdir = 'Simple'
+    _confdir = "Simple"
     _auth_zones = RecursorTest._default_auth_zones
 
-    _config_template = """dnssec=validate
-auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
+    _config_template = (
+        """dnssec=validate
+auth-zones=authzone.example=configs/%s/authzone.zone"""
+        % _confdir
+    )
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'authzone.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN authzone.example.
+        authzonepath = os.path.join(confdir, "authzone.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN authzone.example.
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(SimpleTest, cls).generateRecursorConfig(confdir)
 
     def testSOAs(self):
-        for zone in ['.', 'example.', 'secure.example.']:
-            expected = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, 'SOA', self._SOA)
-            query = dns.message.make_query(zone, 'SOA', want_dnssec=True)
+        for zone in [".", "example.", "secure.example."]:
+            expected = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, "SOA", self._SOA)
+            query = dns.message.make_query(zone, "SOA", want_dnssec=True)
             query.flags |= dns.flags.AD
 
             res = self.sendUDPQuery(query)
@@ -32,8 +38,10 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
             self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testA(self):
-        expected = dns.rrset.from_text('ns.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.9'.format(prefix=self._PREFIX))
-        query = dns.message.make_query('ns.secure.example', 'A', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "ns.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.9".format(prefix=self._PREFIX)
+        )
+        query = dns.message.make_query("ns.secure.example", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
@@ -43,10 +51,10 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testDelegation(self):
-        query = dns.message.make_query('example', 'NS', want_dnssec=True)
+        query = dns.message.make_query("example", "NS", want_dnssec=True)
         query.flags |= dns.flags.AD
 
-        expectedNS = dns.rrset.from_text('example.', 0, 'IN', 'NS', 'ns1.example.', 'ns2.example.')
+        expectedNS = dns.rrset.from_text("example.", 0, "IN", "NS", "ns1.example.", "ns2.example.")
 
         res = self.sendUDPQuery(query)
 
@@ -54,16 +62,16 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertRRsetInAnswer(res, expectedNS)
 
     def testBogus(self):
-        query = dns.message.make_query('ted.bogus.example', 'A', want_dnssec=True)
+        query = dns.message.make_query("ted.bogus.example", "A", want_dnssec=True)
 
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
     def testAuthZone(self):
-        query = dns.message.make_query('authzone.example', 'A', want_dnssec=True)
+        query = dns.message.make_query("authzone.example", "A", want_dnssec=True)
 
-        expectedA = dns.rrset.from_text('authzone.example.', 0, 'IN', 'A', '192.0.2.88')
+        expectedA = dns.rrset.from_text("authzone.example.", 0, "IN", "A", "192.0.2.88")
 
         res = self.sendUDPQuery(query)
 
@@ -71,11 +79,11 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertRRsetInAnswer(res, expectedA)
 
     def testLocalhost(self):
-        queryA = dns.message.make_query('localhost', 'A', want_dnssec=True)
-        expectedA = dns.rrset.from_text('localhost.', 0, 'IN', 'A', '127.0.0.1')
+        queryA = dns.message.make_query("localhost", "A", want_dnssec=True)
+        expectedA = dns.rrset.from_text("localhost.", 0, "IN", "A", "127.0.0.1")
 
-        queryPTR = dns.message.make_query('1.0.0.127.in-addr.arpa', 'PTR', want_dnssec=True)
-        expectedPTR = dns.rrset.from_text('1.0.0.127.in-addr.arpa.', 0, 'IN', 'PTR', 'localhost.')
+        queryPTR = dns.message.make_query("1.0.0.127.in-addr.arpa", "PTR", want_dnssec=True)
+        expectedPTR = dns.rrset.from_text("1.0.0.127.in-addr.arpa.", 0, "IN", "PTR", "localhost.")
 
         resA = self.sendUDPQuery(queryA)
         resPTR = self.sendUDPQuery(queryPTR)
@@ -87,8 +95,8 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertRRsetInAnswer(resPTR, expectedPTR)
 
     def testLocalhostSubdomain(self):
-        queryA = dns.message.make_query('foo.localhost', 'A', want_dnssec=True)
-        expectedA = dns.rrset.from_text('foo.localhost.', 0, 'IN', 'A', '127.0.0.1')
+        queryA = dns.message.make_query("foo.localhost", "A", want_dnssec=True)
+        expectedA = dns.rrset.from_text("foo.localhost.", 0, "IN", "A", "127.0.0.1")
 
         resA = self.sendUDPQuery(queryA)
 
@@ -96,12 +104,11 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertRRsetInAnswer(resA, expectedA)
 
     def testIslandOfSecurity(self):
-        query = dns.message.make_query('cname-to-islandofsecurity.secure.example.', 'A', want_dnssec=True)
+        query = dns.message.make_query("cname-to-islandofsecurity.secure.example.", "A", want_dnssec=True)
 
-        expectedA = dns.rrset.from_text('node1.islandofsecurity.example.', 0, 'IN', 'A', '192.0.2.20')
+        expectedA = dns.rrset.from_text("node1.islandofsecurity.example.", 0, "IN", "A", "192.0.2.20")
 
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expectedA)
-
index 9cd92594d2c14c24e3c896ed2e6f014d8262682a..8ce478d67c5228277f58b8bb26e8e6b543dbe1b2 100644 (file)
@@ -4,11 +4,13 @@ import pytest
 import shutil
 from recursortests import RecursorTest
 
+
 class SimpleCookiesTest(RecursorTest):
-    _confdir = 'SimpleCookies'
+    _confdir = "SimpleCookies"
     _auth_zones = RecursorTest._default_auth_zones
 
-    _config_template = """
+    _config_template = (
+        """
 recursor:
   auth_zones:
   - zone: authzone.example
@@ -16,34 +18,39 @@ recursor:
 dnssec:
   validation: validate
 outgoing:
-  cookies: true""" % _confdir
+  cookies: true"""
+        % _confdir
+    )
+
+    _expectedCookies = "Unsupported"
 
-    _expectedCookies = 'Unsupported'
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'authzone.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN authzone.example.
+        authzonepath = os.path.join(confdir, "authzone.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN authzone.example.
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(SimpleCookiesTest, cls).generateRecursorYamlConfig(confdir)
 
     def checkCookies(self):
-        confdir = os.path.join('configs', self._confdir)
-        output = self.recControl(confdir, 'dump-cookies', '-')
+        confdir = os.path.join("configs", self._confdir)
+        output = self.recControl(confdir, "dump-cookies", "-")
         for line in output.splitlines():
             tokens = line.split()
-            if tokens[0] == ';' or tokens[0] == 'dump-cookies:':
+            if tokens[0] == ";" or tokens[0] == "dump-cookies:":
                 continue
             print(tokens)
             self.assertEqual(len(tokens), 5)
             self.assertEqual(tokens[3], self._expectedCookies)
 
     def testSOAs(self):
-        for zone in ['.', 'example.', 'secure.example.']:
-            expected = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, 'SOA', self._SOA)
-            query = dns.message.make_query(zone, 'SOA', want_dnssec=True)
+        for zone in [".", "example.", "secure.example."]:
+            expected = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, "SOA", self._SOA)
+            query = dns.message.make_query(zone, "SOA", want_dnssec=True)
             query.flags |= dns.flags.AD
 
             res = self.sendUDPQuery(query)
@@ -54,8 +61,10 @@ outgoing:
         self.checkCookies()
 
     def testA(self):
-        expected = dns.rrset.from_text('ns.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.9'.format(prefix=self._PREFIX))
-        query = dns.message.make_query('ns.secure.example', 'A', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "ns.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.9".format(prefix=self._PREFIX)
+        )
+        query = dns.message.make_query("ns.secure.example", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
@@ -66,10 +75,10 @@ outgoing:
         self.checkCookies()
 
     def testDelegation(self):
-        query = dns.message.make_query('example', 'NS', want_dnssec=True)
+        query = dns.message.make_query("example", "NS", want_dnssec=True)
         query.flags |= dns.flags.AD
 
-        expectedNS = dns.rrset.from_text('example.', 0, 'IN', 'NS', 'ns1.example.', 'ns2.example.')
+        expectedNS = dns.rrset.from_text("example.", 0, "IN", "NS", "ns1.example.", "ns2.example.")
 
         res = self.sendUDPQuery(query)
 
@@ -78,7 +87,7 @@ outgoing:
         self.checkCookies()
 
     def testBogus(self):
-        query = dns.message.make_query('ted.bogus.example', 'A', want_dnssec=True)
+        query = dns.message.make_query("ted.bogus.example", "A", want_dnssec=True)
 
         res = self.sendUDPQuery(query)
 
@@ -86,9 +95,9 @@ outgoing:
         self.checkCookies()
 
     def testAuthZone(self):
-        query = dns.message.make_query('authzone.example', 'A', want_dnssec=True)
+        query = dns.message.make_query("authzone.example", "A", want_dnssec=True)
 
-        expectedA = dns.rrset.from_text('authzone.example.', 0, 'IN', 'A', '192.0.2.88')
+        expectedA = dns.rrset.from_text("authzone.example.", 0, "IN", "A", "192.0.2.88")
 
         res = self.sendUDPQuery(query)
 
@@ -97,11 +106,11 @@ outgoing:
         self.checkCookies()
 
     def testLocalhost(self):
-        queryA = dns.message.make_query('localhost', 'A', want_dnssec=True)
-        expectedA = dns.rrset.from_text('localhost.', 0, 'IN', 'A', '127.0.0.1')
+        queryA = dns.message.make_query("localhost", "A", want_dnssec=True)
+        expectedA = dns.rrset.from_text("localhost.", 0, "IN", "A", "127.0.0.1")
 
-        queryPTR = dns.message.make_query('1.0.0.127.in-addr.arpa', 'PTR', want_dnssec=True)
-        expectedPTR = dns.rrset.from_text('1.0.0.127.in-addr.arpa.', 0, 'IN', 'PTR', 'localhost.')
+        queryPTR = dns.message.make_query("1.0.0.127.in-addr.arpa", "PTR", want_dnssec=True)
+        expectedPTR = dns.rrset.from_text("1.0.0.127.in-addr.arpa.", 0, "IN", "PTR", "localhost.")
 
         resA = self.sendUDPQuery(queryA)
         resPTR = self.sendUDPQuery(queryPTR)
@@ -114,8 +123,8 @@ outgoing:
         self.checkCookies()
 
     def testLocalhostSubdomain(self):
-        queryA = dns.message.make_query('foo.localhost', 'A', want_dnssec=True)
-        expectedA = dns.rrset.from_text('foo.localhost.', 0, 'IN', 'A', '127.0.0.1')
+        queryA = dns.message.make_query("foo.localhost", "A", want_dnssec=True)
+        expectedA = dns.rrset.from_text("foo.localhost.", 0, "IN", "A", "127.0.0.1")
 
         resA = self.sendUDPQuery(queryA)
 
@@ -124,9 +133,9 @@ outgoing:
         self.checkCookies()
 
     def testIslandOfSecurity(self):
-        query = dns.message.make_query('cname-to-islandofsecurity.secure.example.', 'A', want_dnssec=True)
+        query = dns.message.make_query("cname-to-islandofsecurity.secure.example.", "A", want_dnssec=True)
 
-        expectedA = dns.rrset.from_text('node1.islandofsecurity.example.', 0, 'IN', 'A', '192.0.2.20')
+        expectedA = dns.rrset.from_text("node1.islandofsecurity.example.", 0, "IN", "A", "192.0.2.20")
 
         res = self.sendUDPQuery(query)
 
@@ -134,14 +143,17 @@ outgoing:
         self.assertRRsetInAnswer(res, expectedA)
         self.checkCookies()
 
+
 class SimpleCookiesAuthEnabledTest(SimpleCookiesTest):
-    _confdir = 'SimpleCookiesAuthEnabled'
+    _confdir = "SimpleCookiesAuthEnabled"
     _auth_zones = SimpleCookiesTest._auth_zones
-    _expectedCookies = 'Supported'
+    _expectedCookies = "Supported"
 
     @classmethod
     def generateAuthConfig(cls, confdir, threads):
-        super(SimpleCookiesAuthEnabledTest, cls).generateAuthConfig(confdir, threads, "edns-cookie-secret=01234567890123456789012345678901")
+        super(SimpleCookiesAuthEnabledTest, cls).generateAuthConfig(
+            confdir, threads, "edns-cookie-secret=01234567890123456789012345678901"
+        )
 
     @classmethod
     def setUpClass(cls):
@@ -150,12 +162,12 @@ class SimpleCookiesAuthEnabledTest(SimpleCookiesTest):
 
     @classmethod
     def tearDownClass(cls):
-        confdir = os.path.join('configs', 'auths')
+        confdir = os.path.join("configs", "auths")
         print("Specialized auth teardown " + confdir)
         # tear down specialized auths, and then start standard ones
         super().tearDownClass(True)
         print("Starting default auths")
-        #confdir = 'configs/auths'
+        # confdir = 'configs/auths'
         shutil.rmtree(confdir, True)
         os.mkdir(confdir)
         # Be careful here, we don't want the overridden secureZone(), so call RecursorTest explicitly
index 8658f1597f2cea99188743894df00329118ab3c4..9cb8ef2de70df4255bc6e49e1c29da74fd766782 100644 (file)
@@ -2,27 +2,33 @@ import dns
 import os
 from recursortests import RecursorTest
 
+
 class SimpleTCPTest(RecursorTest):
-    _confdir = 'SimpleTCP'
+    _confdir = "SimpleTCP"
     _auth_zones = RecursorTest._default_auth_zones
 
-    _config_template = """dnssec=validate
-auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
+    _config_template = (
+        """dnssec=validate
+auth-zones=authzone.example=configs/%s/authzone.zone"""
+        % _confdir
+    )
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'authzone.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN authzone.example.
+        authzonepath = os.path.join(confdir, "authzone.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN authzone.example.
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(SimpleTCPTest, cls).generateRecursorConfig(confdir)
 
     def testSOAs(self):
-        for zone in ['.', 'example.', 'secure.example.']:
-            expected = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, 'SOA', self._SOA)
-            query = dns.message.make_query(zone, 'SOA', want_dnssec=True)
+        for zone in [".", "example.", "secure.example."]:
+            expected = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, "SOA", self._SOA)
+            query = dns.message.make_query(zone, "SOA", want_dnssec=True)
             query.flags |= dns.flags.AD
 
             res = self.sendTCPQuery(query)
@@ -32,8 +38,10 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
             self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testA(self):
-        expected = dns.rrset.from_text('ns.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.9'.format(prefix=self._PREFIX))
-        query = dns.message.make_query('ns.secure.example', 'A', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "ns.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.9".format(prefix=self._PREFIX)
+        )
+        query = dns.message.make_query("ns.secure.example", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         res = self.sendTCPQuery(query)
@@ -43,10 +51,10 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testDelegation(self):
-        query = dns.message.make_query('example', 'NS', want_dnssec=True)
+        query = dns.message.make_query("example", "NS", want_dnssec=True)
         query.flags |= dns.flags.AD
 
-        expectedNS = dns.rrset.from_text('example.', 0, 'IN', 'NS', 'ns1.example.', 'ns2.example.')
+        expectedNS = dns.rrset.from_text("example.", 0, "IN", "NS", "ns1.example.", "ns2.example.")
 
         res = self.sendTCPQuery(query)
 
@@ -54,16 +62,16 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertRRsetInAnswer(res, expectedNS)
 
     def testBogus(self):
-        query = dns.message.make_query('ted.bogus.example', 'A', want_dnssec=True)
+        query = dns.message.make_query("ted.bogus.example", "A", want_dnssec=True)
 
         res = self.sendTCPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
     def testAuthZone(self):
-        query = dns.message.make_query('authzone.example', 'A', want_dnssec=True)
+        query = dns.message.make_query("authzone.example", "A", want_dnssec=True)
 
-        expectedA = dns.rrset.from_text('authzone.example.', 0, 'IN', 'A', '192.0.2.88')
+        expectedA = dns.rrset.from_text("authzone.example.", 0, "IN", "A", "192.0.2.88")
 
         res = self.sendTCPQuery(query)
 
@@ -71,11 +79,11 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertRRsetInAnswer(res, expectedA)
 
     def testLocalhost(self):
-        queryA = dns.message.make_query('localhost', 'A', want_dnssec=True)
-        expectedA = dns.rrset.from_text('localhost.', 0, 'IN', 'A', '127.0.0.1')
+        queryA = dns.message.make_query("localhost", "A", want_dnssec=True)
+        expectedA = dns.rrset.from_text("localhost.", 0, "IN", "A", "127.0.0.1")
 
-        queryPTR = dns.message.make_query('1.0.0.127.in-addr.arpa', 'PTR', want_dnssec=True)
-        expectedPTR = dns.rrset.from_text('1.0.0.127.in-addr.arpa.', 0, 'IN', 'PTR', 'localhost.')
+        queryPTR = dns.message.make_query("1.0.0.127.in-addr.arpa", "PTR", want_dnssec=True)
+        expectedPTR = dns.rrset.from_text("1.0.0.127.in-addr.arpa.", 0, "IN", "PTR", "localhost.")
 
         resA = self.sendTCPQuery(queryA)
         resPTR = self.sendTCPQuery(queryPTR)
@@ -87,8 +95,8 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertRRsetInAnswer(resPTR, expectedPTR)
 
     def testLocalhostSubdomain(self):
-        queryA = dns.message.make_query('foo.localhost', 'A', want_dnssec=True)
-        expectedA = dns.rrset.from_text('foo.localhost.', 0, 'IN', 'A', '127.0.0.1')
+        queryA = dns.message.make_query("foo.localhost", "A", want_dnssec=True)
+        expectedA = dns.rrset.from_text("foo.localhost.", 0, "IN", "A", "127.0.0.1")
 
         resA = self.sendTCPQuery(queryA)
 
@@ -96,29 +104,30 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
         self.assertRRsetInAnswer(resA, expectedA)
 
     def testIslandOfSecurity(self):
-        query = dns.message.make_query('cname-to-islandofsecurity.secure.example.', 'A', want_dnssec=True)
+        query = dns.message.make_query("cname-to-islandofsecurity.secure.example.", "A", want_dnssec=True)
 
-        expectedA = dns.rrset.from_text('node1.islandofsecurity.example.', 0, 'IN', 'A', '192.0.2.20')
+        expectedA = dns.rrset.from_text("node1.islandofsecurity.example.", 0, "IN", "A", "192.0.2.20")
 
         res = self.sendTCPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expectedA)
 
-
     def testVeryBasicPipeline(self):
         # This test does not enforce order, it will accept replies in any order. So
         # it does not actually test OOO behaviour.
         expected = {}
         queries = []
-        for zone in ['.', 'example.', 'secure.example.']:
-            expected[zone] = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, 'SOA', self._SOA)
-            query = dns.message.make_query(zone, 'SOA', want_dnssec=True)
+        for zone in [".", "example.", "secure.example."]:
+            expected[zone] = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, "SOA", self._SOA)
+            query = dns.message.make_query(zone, "SOA", want_dnssec=True)
             query.flags |= dns.flags.AD
             queries.append(query)
 
-        expected['ns.secure.example.'] = dns.rrset.from_text('ns.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.9'.format(prefix=self._PREFIX))
-        query = dns.message.make_query('ns.secure.example', 'A', want_dnssec=True)
+        expected["ns.secure.example."] = dns.rrset.from_text(
+            "ns.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.9".format(prefix=self._PREFIX)
+        )
+        query = dns.message.make_query("ns.secure.example", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
         queries.append(query)
 
@@ -131,4 +140,3 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
             self.assertMessageIsAuthenticated(res)
             self.assertRRsetInAnswer(res, exp)
             self.assertMatchingRRSIGInAnswer(res, exp)
-
index f6ee86383093d38223debd5501395a215ea4582c..8962d18c44f77cf531d2e30b2b065fda49f5eee6 100644 (file)
@@ -2,32 +2,38 @@ import dns
 import os
 from recursortests import RecursorTest
 
+
 class SimpleYAMLTest(RecursorTest):
-    _confdir = 'SimpleYAML'
+    _confdir = "SimpleYAML"
     _auth_zones = RecursorTest._default_auth_zones
 
-    _config_template = """
+    _config_template = (
+        """
 recursor:
   auth_zones:
   - zone: authzone.example
     file: configs/%s/authzone.zone
 dnssec:
-  validation: validate""" % _confdir
+  validation: validate"""
+        % _confdir
+    )
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        authzonepath = os.path.join(confdir, 'authzone.zone')
-        with open(authzonepath, 'w') as authzone:
-            authzone.write("""$ORIGIN authzone.example.
+        authzonepath = os.path.join(confdir, "authzone.zone")
+        with open(authzonepath, "w") as authzone:
+            authzone.write(
+                """$ORIGIN authzone.example.
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
-""".format(soa=cls._SOA))
+""".format(soa=cls._SOA)
+            )
         super(SimpleYAMLTest, cls).generateRecursorYamlConfig(confdir)
 
     def testSOAs(self):
-        for zone in ['.', 'example.', 'secure.example.']:
-            expected = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, 'SOA', self._SOA)
-            query = dns.message.make_query(zone, 'SOA', want_dnssec=True)
+        for zone in [".", "example.", "secure.example."]:
+            expected = dns.rrset.from_text(zone, 0, dns.rdataclass.IN, "SOA", self._SOA)
+            query = dns.message.make_query(zone, "SOA", want_dnssec=True)
             query.flags |= dns.flags.AD
 
             res = self.sendUDPQuery(query)
@@ -37,8 +43,10 @@ dnssec:
             self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testA(self):
-        expected = dns.rrset.from_text('ns.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.9'.format(prefix=self._PREFIX))
-        query = dns.message.make_query('ns.secure.example', 'A', want_dnssec=True)
+        expected = dns.rrset.from_text(
+            "ns.secure.example.", 0, dns.rdataclass.IN, "A", "{prefix}.9".format(prefix=self._PREFIX)
+        )
+        query = dns.message.make_query("ns.secure.example", "A", want_dnssec=True)
         query.flags |= dns.flags.AD
 
         res = self.sendUDPQuery(query)
@@ -48,10 +56,10 @@ dnssec:
         self.assertMatchingRRSIGInAnswer(res, expected)
 
     def testDelegation(self):
-        query = dns.message.make_query('example', 'NS', want_dnssec=True)
+        query = dns.message.make_query("example", "NS", want_dnssec=True)
         query.flags |= dns.flags.AD
 
-        expectedNS = dns.rrset.from_text('example.', 0, 'IN', 'NS', 'ns1.example.', 'ns2.example.')
+        expectedNS = dns.rrset.from_text("example.", 0, "IN", "NS", "ns1.example.", "ns2.example.")
 
         res = self.sendUDPQuery(query)
 
@@ -59,16 +67,16 @@ dnssec:
         self.assertRRsetInAnswer(res, expectedNS)
 
     def testBogus(self):
-        query = dns.message.make_query('ted.bogus.example', 'A', want_dnssec=True)
+        query = dns.message.make_query("ted.bogus.example", "A", want_dnssec=True)
 
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
     def testAuthZone(self):
-        query = dns.message.make_query('authzone.example', 'A', want_dnssec=True)
+        query = dns.message.make_query("authzone.example", "A", want_dnssec=True)
 
-        expectedA = dns.rrset.from_text('authzone.example.', 0, 'IN', 'A', '192.0.2.88')
+        expectedA = dns.rrset.from_text("authzone.example.", 0, "IN", "A", "192.0.2.88")
 
         res = self.sendUDPQuery(query)
 
@@ -76,11 +84,11 @@ dnssec:
         self.assertRRsetInAnswer(res, expectedA)
 
     def testLocalhost(self):
-        queryA = dns.message.make_query('localhost', 'A', want_dnssec=True)
-        expectedA = dns.rrset.from_text('localhost.', 0, 'IN', 'A', '127.0.0.1')
+        queryA = dns.message.make_query("localhost", "A", want_dnssec=True)
+        expectedA = dns.rrset.from_text("localhost.", 0, "IN", "A", "127.0.0.1")
 
-        queryPTR = dns.message.make_query('1.0.0.127.in-addr.arpa', 'PTR', want_dnssec=True)
-        expectedPTR = dns.rrset.from_text('1.0.0.127.in-addr.arpa.', 0, 'IN', 'PTR', 'localhost.')
+        queryPTR = dns.message.make_query("1.0.0.127.in-addr.arpa", "PTR", want_dnssec=True)
+        expectedPTR = dns.rrset.from_text("1.0.0.127.in-addr.arpa.", 0, "IN", "PTR", "localhost.")
 
         resA = self.sendUDPQuery(queryA)
         resPTR = self.sendUDPQuery(queryPTR)
@@ -92,8 +100,8 @@ dnssec:
         self.assertRRsetInAnswer(resPTR, expectedPTR)
 
     def testLocalhostSubdomain(self):
-        queryA = dns.message.make_query('foo.localhost', 'A', want_dnssec=True)
-        expectedA = dns.rrset.from_text('foo.localhost.', 0, 'IN', 'A', '127.0.0.1')
+        queryA = dns.message.make_query("foo.localhost", "A", want_dnssec=True)
+        expectedA = dns.rrset.from_text("foo.localhost.", 0, "IN", "A", "127.0.0.1")
 
         resA = self.sendUDPQuery(queryA)
 
@@ -101,12 +109,11 @@ dnssec:
         self.assertRRsetInAnswer(resA, expectedA)
 
     def testIslandOfSecurity(self):
-        query = dns.message.make_query('cname-to-islandofsecurity.secure.example.', 'A', want_dnssec=True)
+        query = dns.message.make_query("cname-to-islandofsecurity.secure.example.", "A", want_dnssec=True)
 
-        expectedA = dns.rrset.from_text('node1.islandofsecurity.example.', 0, 'IN', 'A', '192.0.2.20')
+        expectedA = dns.rrset.from_text("node1.islandofsecurity.example.", 0, "IN", "A", "192.0.2.20")
 
         res = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expectedA)
-
index a8b22588ac25f3cc749cd02f84197725b78916c5..3ab67ba3a2895f3e9abb6061e0f1404794356ed7 100644 (file)
@@ -3,7 +3,7 @@ from recursortests import RecursorTest
 
 
 class SortlistTest(RecursorTest):
-    _confdir = 'Sortlist'
+    _confdir = "Sortlist"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """dnssec=off"""
@@ -15,13 +15,13 @@ class SortlistTest(RecursorTest):
 
     def testSortlist(self):
         msg = dns.message.make_query("sortcname.example.", dns.rdatatype.ANY)
-        msg.flags = dns.flags.from_text('RD')
+        msg.flags = dns.flags.from_text("RD")
 
         res = self.sendUDPQuery(msg, fwparams=dict(one_rr_per_rrset=True))
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD', 'TC'], [])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD", "TC"], [])
 
         res = self.sendTCPQuery(msg, fwparams=dict(one_rr_per_rrset=True))
-        self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], [])
+        self.assertMessageHasFlags(res, ["QR", "RA", "RD"], [])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
         indexCNAME = -1
@@ -41,4 +41,4 @@ class SortlistTest(RecursorTest):
         self.assertEqual(indexCNAME, 0)
         self.assertGreater(indexMX, 0)
 
-        self.assertEqual(recordsA, ['17.238.240.5', '17.38.42.80', '192.168.0.1'])
+        self.assertEqual(recordsA, ["17.238.240.5", "17.38.42.80", "192.168.0.1"])
index c484b5c2f4a042e008479708c7d0c5248cab75ec..30fa3d77bbffaf4813974169d7af905c83061d0b 100644 (file)
@@ -2,8 +2,9 @@ import dns
 import os
 from recursortests import RecursorTest
 
+
 class BogusMaxTTLTest(RecursorTest):
-    _confdir = 'BogusMaxTTL'
+    _confdir = "BogusMaxTTL"
     _auth_zones = RecursorTest._default_auth_zones
 
     _config_template = """dnssec=validate
@@ -11,20 +12,20 @@ max-cache-bogus-ttl=5"""
 
     @classmethod
     def setUp(cls):
-        confdir = os.path.join('configs', cls._confdir)
+        confdir = os.path.join("configs", cls._confdir)
         cls.wipeRecursorCache(confdir)
 
     def testBogusCheckDisabled(self):
         # first query with CD=0, so we should get a ServFail
-        query = self.createQuery('ted.bogus.example.', 'A', 'AD', 'DO')
+        query = self.createQuery("ted.bogus.example.", "A", "AD", "DO")
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
         # then with CD=1 so we should get the A + RRSIG
         # check that we correctly applied the maximum TTL when caching Bogus entries
-        query = self.createQuery('ted.bogus.example.', 'A', 'AD CD', 'DO')
+        query = self.createQuery("ted.bogus.example.", "A", "AD CD", "DO")
         res = self.sendUDPQuery(query)
-        self.assertMessageHasFlags(res, ['CD', 'QR', 'RA', 'RD'], ['DO'])
+        self.assertMessageHasFlags(res, ["CD", "QR", "RA", "RD"], ["DO"])
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertEqual(len(res.answer), 2)
         for ans in res.answer:
index 3c84ee3b8b626b677280a5d6656a8ced35b69649..40d28407078a866535f27646a09037671c992952 100644 (file)
@@ -3,8 +3,9 @@ import time
 import subprocess
 from recursortests import RecursorTest
 
+
 class TraceFailTest(RecursorTest):
-    _confdir = 'TraceFail'
+    _confdir = "TraceFail"
 
     _config_template = """
 trace=fail
@@ -12,19 +13,19 @@ forward-zones-recurse=.=127.0.0.1:9999
 """
 
     def testA(self):
-        query = dns.message.make_query('example', 'A', want_dnssec=False)
+        query = dns.message.make_query("example", "A", want_dnssec=False)
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
-        grepCmd = ['grep', 'END OF FAIL TRACE', 'configs/' + self._confdir + '/recursor.log']
-        ret = b''
+        grepCmd = ["grep", "END OF FAIL TRACE", "configs/" + self._confdir + "/recursor.log"]
+        ret = b""
         for i in range(1000):
             time.sleep(0.01)
             try:
                 ret = subprocess.check_output(grepCmd, stderr=subprocess.STDOUT)
             except subprocess.CalledProcessError as e:
                 continue
-            print(b'A' + ret)
+            print(b"A" + ret)
             break
         print(ret)
-        self.assertNotEqual(ret, b'')
+        self.assertNotEqual(ret, b"")
index 5a401801b5ab84c558d914ffd82bba8add64adaa..bbff903e72844d24f0be74f8ecd5387d92f1ae79 100644 (file)
@@ -6,7 +6,7 @@ class TrustAnchorsEnabledTest(RecursorTest):
     """This test will do a query for "trustanchor.server CH TXT" and hopes to get
     a proper answer"""
 
-    _confdir = 'TrustAnchorsEnabled'
+    _confdir = "TrustAnchorsEnabled"
     _roothints = None
     _root_DS = None
     _config_template = """
@@ -20,10 +20,9 @@ addNTA("example.com", "some reason")
 
     def testTrustanchorDotServer(self):
         expected = dns.rrset.from_text_list(
-            'trustanchor.server.', 86400, dns.rdataclass.CH, 'TXT',
-            ['". 20326 38696"', '"powerdns.com. 44030"'])
-        query = dns.message.make_query('trustanchor.server', 'TXT',
-                                       dns.rdataclass.CH)
+            "trustanchor.server.", 86400, dns.rdataclass.CH, "TXT", ['". 20326 38696"', '"powerdns.com. 44030"']
+        )
+        query = dns.message.make_query("trustanchor.server", "TXT", dns.rdataclass.CH)
         result = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(result, dns.rcode.NOERROR)
@@ -31,10 +30,9 @@ addNTA("example.com", "some reason")
 
     def testNegativerustanchorDotServer(self):
         expected = dns.rrset.from_text_list(
-            'negativetrustanchor.server.', 86400, dns.rdataclass.CH, 'TXT',
-            ['"example."', '"example.com. some reason"'])
-        query = dns.message.make_query('negativetrustanchor.server', 'TXT',
-                                       dns.rdataclass.CH)
+            "negativetrustanchor.server.", 86400, dns.rdataclass.CH, "TXT", ['"example."', '"example.com. some reason"']
+        )
+        query = dns.message.make_query("negativetrustanchor.server", "TXT", dns.rdataclass.CH)
         result = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(result, dns.rcode.NOERROR)
@@ -45,22 +43,20 @@ class TrustAnchorsDisabledTest(RecursorTest):
     """This test will do a query for "trustanchor.server CH TXT" and hopes to get
     a proper answer"""
 
-    _confdir = 'TrustAnchorsDisabled'
+    _confdir = "TrustAnchorsDisabled"
     _roothints = None
     _root_DS = None
     _config_template = """
 """
 
     def testTrustanchorDotServer(self):
-        query = dns.message.make_query('trustanchor.server', 'TXT',
-                                       dns.rdataclass.CH)
+        query = dns.message.make_query("trustanchor.server", "TXT", dns.rdataclass.CH)
         result = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(result, dns.rcode.SERVFAIL)
 
     def testNegativerustanchorDotServer(self):
-        query = dns.message.make_query('negativetrustanchor.server', 'TXT',
-                                       dns.rdataclass.CH)
+        query = dns.message.make_query("negativetrustanchor.server", "TXT", dns.rdataclass.CH)
         result = self.sendUDPQuery(query)
 
         self.assertRcodeEqual(result, dns.rcode.SERVFAIL)
index fa04a9692c92485bb3f1b83ef1fd6c73eab5e31d..10192d136aac42beffb92c46388677236161a1d7 100644 (file)
@@ -2,19 +2,20 @@ import pytest
 import dns
 from recursortests import RecursorTest
 
+
 @pytest.mark.external
 class WellKnownTest(RecursorTest):
     _auths_zones = None
-    _confdir = 'WellKnown'
+    _confdir = "WellKnown"
     _roothints = None
     _root_DS = None
     _config_template = """dnssec=validate"""
 
     def testServFail(self):
-        names = ['servfail.nl', 'dnssec-failed.org']
+        names = ["servfail.nl", "dnssec-failed.org"]
         results = []
         for name in names:
-            query = dns.message.make_query(name, 'SOA')
+            query = dns.message.make_query(name, "SOA")
             results.append(self.sendUDPQuery(query, timeout=5.0))
 
         self.assertEqual(len(results), len(names))
@@ -23,10 +24,10 @@ class WellKnownTest(RecursorTest):
             self.assertRcodeEqual(result, dns.rcode.SERVFAIL)
 
     def testNoError(self):
-        names = ['powerdns.com', 'nlnetlabs.nl', 'knot-dns.cz']
+        names = ["powerdns.com", "nlnetlabs.nl", "knot-dns.cz"]
         results = []
         for name in names:
-            query = dns.message.make_query(name, 'SOA')
+            query = dns.message.make_query(name, "SOA")
             results.append(self.sendUDPQuery(query))
 
         self.assertEqual(len(results), len(names))
index 6a1d2945531f37839d63d9b35a27b2314439b9c9..30663ee41fce2e55c9f28466119d359f4b4b2586 100644 (file)
@@ -3,8 +3,9 @@ import subprocess
 
 from recursortests import RecursorTest
 
+
 class ZTCTest(RecursorTest):
-    _confdir = 'ZTC'
+    _confdir = "ZTC"
     _config_template = """
 dnssec:
     validation: validate
@@ -21,16 +22,15 @@ recordcache:
         super(ZTCTest, cls).generateRecursorYamlConfig(confdir, False)
 
     def testZTC(self):
-        grepCmd = ['grep', 'validationStatus="Secure"', 'configs/' + self._confdir + '/recursor.log']
-        ret = b''
+        grepCmd = ["grep", 'validationStatus="Secure"', "configs/" + self._confdir + "/recursor.log"]
+        ret = b""
         for i in range(3000):
             time.sleep(0.01)
             try:
                 ret = subprocess.check_output(grepCmd, stderr=subprocess.STDOUT)
             except subprocess.CalledProcessError as e:
                 continue
-            print(b'A' + ret)
+            print(b"A" + ret)
             break
         print(ret)
-        self.assertNotEqual(ret, b'')
-
+        self.assertNotEqual(ret, b"")
index cd432aa277fa7567335f2936fe1ea34b5f1888b1..53d4dec041b40ba6af0906d73fe9c9a8043a7d1f 100644 (file)
@@ -1,6 +1,7 @@
 from basicDNSSEC import BasicDNSSEC
 
+
 class basicNSECTest(BasicDNSSEC):
     __test__ = True
-    _confdir = 'basicNSEC'
+    _confdir = "basicNSEC"
     _auth_zones = BasicDNSSEC._auth_zones
index 5793e03ab267d71a9201d01f87223662da106e18..e87859bd4a6bf14e5e566237809131abe804dad8 100644 (file)
@@ -3,51 +3,47 @@ from basicDNSSEC import BasicDNSSEC
 import os
 import subprocess
 
+
 class basicNSEC3Test(BasicDNSSEC):
     __test__ = True
-    _confdir = 'basicNSEC3'
+    _confdir = "basicNSEC3"
     _auth_zones = BasicDNSSEC._auth_zones
 
     @classmethod
     def secureZone(cls, confdir, zonename, key=None):
-        zone = '.' if zonename == 'ROOT' else zonename
+        zone = "." if zonename == "ROOT" else zonename
         if not key:
-            pdnsutilCmd = [os.environ['PDNSUTIL'],
-                           '--config-dir=%s' % confdir,
-                           'secure-zone',
-                           zone]
+            pdnsutilCmd = [os.environ["PDNSUTIL"], "--config-dir=%s" % confdir, "secure-zone", zone]
         else:
-            keyfile = os.path.join(confdir, 'dnssec.key')
-            with open(keyfile, 'w') as fdKeyfile:
+            keyfile = os.path.join(confdir, "dnssec.key")
+            with open(keyfile, "w") as fdKeyfile:
                 fdKeyfile.write(key)
 
-            pdnsutilCmd = [os.environ['PDNSUTIL'],
-                           '--config-dir=%s' % confdir,
-                           'import-zone-key',
-                           zone,
-                           keyfile,
-                           'active',
-                           'ksk']
-
-        print(' '.join(pdnsutilCmd))
+            pdnsutilCmd = [
+                os.environ["PDNSUTIL"],
+                "--config-dir=%s" % confdir,
+                "import-zone-key",
+                zone,
+                keyfile,
+                "active",
+                "ksk",
+            ]
+
+        print(" ".join(pdnsutilCmd))
         try:
             subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
 
         params = "1 0 50 AABBCCDDEEFF112233"
 
         if zone == "optout.example":
             params = "1 1 50 AABBCCDDEEFF112233"
 
-        pdnsutilCmd = [os.environ['PDNSUTIL'],
-                       '--config-dir=%s' % confdir,
-                       'set-nsec3',
-                       zone,
-                       params]
+        pdnsutilCmd = [os.environ["PDNSUTIL"], "--config-dir=%s" % confdir, "set-nsec3", zone, params]
 
-        print(' '.join(pdnsutilCmd))
+        print(" ".join(pdnsutilCmd))
         try:
             subprocess.check_output(pdnsutilCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
-            raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
+            raise AssertionError("%s failed (%d): %s" % (pdnsutilCmd, e.returncode, e.output))
index 1340014db4c0f2b9a1034d5906d0b61937761a34..de80d0a2f9dfa57b577cb9a99a32727216a0242c 100755 (executable)
@@ -4,29 +4,29 @@ import json, sys
 
 runs = json.load(sys.stdin)
 
-selectors = dict(s.split('=',1) for s in sys.argv[1:])
+selectors = dict(s.split("=", 1) for s in sys.argv[1:])
 
-selected=list()
+selected = list()
 
-names=set()
+names = set()
 
 for run in runs:
-       match = True
-       for k,v in selectors.iteritems():
-               # print k, v, run[k]
-               if run[k] != v:
-                       match = False
-                       break
+    match = True
+    for k, v in selectors.iteritems():
+        # print k, v, run[k]
+        if run[k] != v:
+            match = False
+            break
 
-       if match:
-               selected.append((run['tag'], run))
-               names.update(run)
+    if match:
+        selected.append((run["tag"], run))
+        names.update(run)
 
 selected.sort()
 
-names.discard('tag')
+names.discard("tag")
 
-fmt=''.join('%%%ds' % max(15, i+4) for i in [3]+map(len, sorted(names)))
-print(fmt % tuple(['tag']+sorted(names)))
+fmt = "".join("%%%ds" % max(15, i + 4) for i in [3] + map(len, sorted(names)))
+print(fmt % tuple(["tag"] + sorted(names)))
 for tag, stats in selected:
-       print(fmt % tuple([tag] + [stats.get(s) for s in sorted(names)]))
+    print(fmt % tuple([tag] + [stats.get(s) for s in sorted(names)]))
index c9e28db59ba1b825382de363b5476e778e39470d..09f4e4fe38002d3070b1945b256315afca7477bc 100755 (executable)
@@ -6,22 +6,22 @@ varnames = set()
 statnames = set()
 runs = list()
 
-for fname in glob.glob('testresults-*.xml'):
-       info = fname[12:-4].split('_')
-       tag = info.pop(0)
-       vars = dict(s.split(':') for s in info)
-       vars['tag'] = tag
-       varnames.update(vars.keys())
-       stats=dict()
-       with open(fname) as f:
-               for line in f:
-                       if line.startswith('&lt;'):
-                               sname = line.split(';')[4][:-3]
-                               sval = line.split(';')[8][:-3]
-                               stats[sname]=sval
-                               statnames.add(sname)
-       # print fname, vars, stats
-       runs.append(dict(vars.items()+stats.items()))
+for fname in glob.glob("testresults-*.xml"):
+    info = fname[12:-4].split("_")
+    tag = info.pop(0)
+    vars = dict(s.split(":") for s in info)
+    vars["tag"] = tag
+    varnames.update(vars.keys())
+    stats = dict()
+    with open(fname) as f:
+        for line in f:
+            if line.startswith("&lt;"):
+                sname = line.split(";")[4][:-3]
+                sval = line.split(";")[8][:-3]
+                stats[sname] = sval
+                statnames.add(sname)
+    # print fname, vars, stats
+    runs.append(dict(vars.items() + stats.items()))
 
 # print varnames
 # print statnames
index d3d4a149df5e640a72cba2003c5de0901f53db7f..00d51afc6087516e5229f21dce54d0e115bd3c24 100755 (executable)
@@ -3,42 +3,51 @@
 import socket
 import sys
 
+
 def ensure(data, offset, value):
-  if (data[offset:offset+len(value)] != value):
-    raise Exception("Mismatch at packet offset {0!s} {1!r} != {2!r}".format(offset,data[offset:offset+len(value)], value))
+    if data[offset : offset + len(value)] != value:
+        raise Exception(
+            "Mismatch at packet offset {0!s} {1!r} != {2!r}".format(offset, data[offset : offset + len(value)], value)
+        )
+
 
 def main(host, port):
-  s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+    msg = b"\xaa\x77\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x04tkey\x04unit\x04test\x00\x00\xf9\x00\xff\x04tkey\x04unit\x04test\x00\x00\xf9\x00\xff\x00\x00\x00\x00\x00\x22\x03bad\04algo\x00\x00\x00\x30\x39\x00\x00\x30\x39\x00\x03\x00\x00\x00\x04test\x00\x00"
 
-  msg = b"\xaa\x77\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x04tkey\x04unit\x04test\x00\x00\xf9\x00\xff\x04tkey\x04unit\x04test\x00\x00\xf9\x00\xff\x00\x00\x00\x00\x00\x22\x03bad\04algo\x00\x00\x00\x30\x39\x00\x00\x30\x39\x00\x03\x00\x00\x00\x04test\x00\x00"
+    s.sendto(msg, (host, port))
+    s.settimeout(2)
+    data, addr = s.recvfrom(512)
 
-  s.sendto(msg, (host, port))
-  s.settimeout(2)
-  data, addr = s.recvfrom(512)
+    # make sure the data validates
 
-  # make sure the data validates
+    # transaction id
+    ensure(data, 0, msg[0:2])
 
-  # transaction id
-  ensure(data, 0, msg[0:2])
+    # has one question, one answer
+    ensure(data, 4, b"\x00\x01")
+    ensure(data, 6, b"\x00\x01")
 
-  # has one question, one answer
-  ensure(data, 4, b"\x00\x01")
-  ensure(data, 6, b"\x00\x01")
+    # question is tkey.unit.test ANY TKEY?
+    ensure(data, 12, b"\x04tkey\x04unit\x04test\x00\x00\xf9\x00\xff")
+    # answer is called tkey.unit.test ANY TKEY (compressed it seems)
+    ensure(data, 32, b"\xc0\x0c\x00\xf9\x00\xff")
 
-  # question is tkey.unit.test ANY TKEY?
-  ensure(data, 12, b"\x04tkey\x04unit\x04test\x00\x00\xf9\x00\xff")
-  # answer is called tkey.unit.test ANY TKEY (compressed it seems)
-  ensure(data, 32, b"\xc0\x0c\x00\xf9\x00\xff")
+    # and then ensure we get an BADALG or error, at least.
+    if data[64:66] == "\x00\x00":
+        raise Exception(
+            "At packet offset {0!s}: expected {2!r}, got {1!r}".format(
+                offset, data[offset : offset + len(value)], value
+            )
+        )
 
-  # and then ensure we get an BADALG or error, at least.
-  if (data[64:66] == "\x00\x00"):
-    raise Exception("At packet offset {0!s}: expected {2!r}, got {1!r}".format(offset,data[offset:offset+len(value)], value))
+    print("Got expected TKEY response\n")
 
-  print("Got expected TKEY response\n")
 
-if (len(sys.argv) < 3):
-  print("Usage: tkey.py host port")
-  sys.exit(1)
+if len(sys.argv) < 3:
+    print("Usage: tkey.py host port")
+    sys.exit(1)
 
-if __name__ == '__main__':
-  main(sys.argv[1], int(sys.argv[2]))
+if __name__ == "__main__":
+    main(sys.argv[1], int(sys.argv[2]))
index 882c6de9229f5c9558c9475003340649e86655e5..b05455859b3a8565965a6df97cb3887a16f0e300 100644 (file)
--- a/tasks.py
+++ b/tasks.py
@@ -6,174 +6,168 @@ import requests
 from invoke import task
 from invoke.exceptions import Failure, UnexpectedExit
 
-auth_backend_ip_addr = os.getenv('AUTH_BACKEND_IP_ADDR', '127.0.0.1')
+auth_backend_ip_addr = os.getenv("AUTH_BACKEND_IP_ADDR", "127.0.0.1")
 
-clang_version = os.getenv('CLANG_VERSION', '13')
-repo_home = os.getenv('REPO_HOME', '.')
+clang_version = os.getenv("CLANG_VERSION", "13")
+repo_home = os.getenv("REPO_HOME", ".")
 
 all_build_deps = [
-    'ccache',
-    'libboost-all-dev',
-    'libluajit-5.1-dev',
-    'libsodium-dev',
-    'libssl-dev', # This will install libssl 1.1 on Debian 11 and libssl3 on Debian 12
-    'libsystemd-dev',
-    'libtool',
-    'make',
-    'pkg-config',
-    'python3-venv',
-    'systemd',
+    "ccache",
+    "libboost-all-dev",
+    "libluajit-5.1-dev",
+    "libsodium-dev",
+    "libssl-dev",  # This will install libssl 1.1 on Debian 11 and libssl3 on Debian 12
+    "libsystemd-dev",
+    "libtool",
+    "make",
+    "pkg-config",
+    "python3-venv",
+    "systemd",
 ]
-git_build_deps = [
-    'autoconf',
-    'automake',
-    'bison',
-    'bzip2',
-    'curl',
-    'flex',
-    'git',
-    'ragel'
-]
-auth_build_deps = [    # FIXME: perhaps we should be stealing these from the debian (Ubuntu) control file
-    'default-libmysqlclient-dev',
-    'libcdb-dev',
-    'libcurl4-openssl-dev',
-    'libgeoip-dev',
-    'libkrb5-dev',
-    'libldap2-dev',
-    'liblmdb-dev',
-    'libmaxminddb-dev',
-    'libp11-kit-dev',
-    'libpq-dev',
-    'libsqlite3-dev',
-    'libyaml-cpp-dev',
-    'libzmq3-dev',
-    'python3-venv',
-    'socat',
-    'sqlite3',
-    'unixodbc-dev',
-    'cmake',
+git_build_deps = ["autoconf", "automake", "bison", "bzip2", "curl", "flex", "git", "ragel"]
+auth_build_deps = [  # FIXME: perhaps we should be stealing these from the debian (Ubuntu) control file
+    "default-libmysqlclient-dev",
+    "libcdb-dev",
+    "libcurl4-openssl-dev",
+    "libgeoip-dev",
+    "libkrb5-dev",
+    "libldap2-dev",
+    "liblmdb-dev",
+    "libmaxminddb-dev",
+    "libp11-kit-dev",
+    "libpq-dev",
+    "libsqlite3-dev",
+    "libyaml-cpp-dev",
+    "libzmq3-dev",
+    "python3-venv",
+    "socat",
+    "sqlite3",
+    "unixodbc-dev",
+    "cmake",
 ]
 rec_build_deps = [
-    'libcap-dev',
-    'libfstrm-dev',
-    'libgnutls28-dev',
-    'libsnmp-dev',
+    "libcap-dev",
+    "libfstrm-dev",
+    "libgnutls28-dev",
+    "libsnmp-dev",
 ]
 rec_bulk_deps = [
-    'curl',
-    'bind9-dnsutils',
-    'libboost-all-dev',
-    'libcap2',
-    'libfstrm0',
-    'libluajit-5.1-2',
+    "curl",
+    "bind9-dnsutils",
+    "libboost-all-dev",
+    "libcap2",
+    "libfstrm0",
+    "libluajit-5.1-2",
     '"libsnmp[1-9]+"',
-    'libsodium23',
-    'libsystemd0',
-    'moreutils',
-    'pdns-tools',
-    'unzip',
+    "libsodium23",
+    "libsystemd0",
+    "moreutils",
+    "pdns-tools",
+    "unzip",
 ]
 rec_bulk_ubicloud_deps = [
-    'curl',
-    'bind9-dnsutils',
-    'libboost-context1.83.0',
-    'libboost-filesystem1.83.0',
-    'libcap2',
-    'libfstrm0',
-    'libluajit-5.1-2',
+    "curl",
+    "bind9-dnsutils",
+    "libboost-context1.83.0",
+    "libboost-filesystem1.83.0",
+    "libcap2",
+    "libfstrm0",
+    "libluajit-5.1-2",
     '"libsnmp[1-9]+"',
-    'libsodium23',
-    'libsystemd0',
-    'moreutils',
-    'pdns-tools',
-    'unzip',
+    "libsodium23",
+    "libsystemd0",
+    "moreutils",
+    "pdns-tools",
+    "unzip",
 ]
 dnsdist_build_deps = [
-    'libcap-dev',
-    'libcdb-dev',
-    'libedit-dev',
-    'libfstrm-dev',
-    'libgnutls28-dev',
-    'liblmdb-dev',
-    'libnghttp2-dev',
-    'libre2-dev',
-    'libsnmp-dev',
+    "libcap-dev",
+    "libcdb-dev",
+    "libedit-dev",
+    "libfstrm-dev",
+    "libgnutls28-dev",
+    "liblmdb-dev",
+    "libnghttp2-dev",
+    "libre2-dev",
+    "libsnmp-dev",
 ]
 dnsdist_xdp_build_deps = [
-    'libbpf-dev',
-    'libxdp-dev',
+    "libbpf-dev",
+    "libxdp-dev",
 ]
-auth_test_deps = [   # FIXME: we should be generating some of these from shlibdeps in build
-    'authbind',
-    'bc',
-    'bind9utils',
-    'curl',
-    'default-jre-headless',
-    'bind9-dnsutils',
-    'gawk',
-    'krb5-user',
-    'ldnsutils',
+auth_test_deps = [  # FIXME: we should be generating some of these from shlibdeps in build
+    "authbind",
+    "bc",
+    "bind9utils",
+    "curl",
+    "default-jre-headless",
+    "bind9-dnsutils",
+    "gawk",
+    "krb5-user",
+    "ldnsutils",
     '"libboost-serialization1.7[1-9]+"',
-    'libcdb1',
-    'libcurl4',
-    'libgeoip1',
-    'libkrb5-3',
+    "libcdb1",
+    "libcurl4",
+    "libgeoip1",
+    "libkrb5-3",
     '"libldap-2.[1-9]+"',
-    'liblmdb0',
-    'libluajit-5.1-2',
-    'libmaxminddb0',
-    'libnet-dns-perl',
-    'libp11-kit0',
-    'libpq5',
-    'libsodium23',
-    'libsqlite3-dev',
-    'libsystemd0',
+    "liblmdb0",
+    "libluajit-5.1-2",
+    "libmaxminddb0",
+    "libnet-dns-perl",
+    "libp11-kit0",
+    "libpq5",
+    "libsodium23",
+    "libsqlite3-dev",
+    "libsystemd0",
     '"libyaml-cpp0.[1-9]+"',
-    'libzmq3-dev',
-    'lmdb-utils',
-    'prometheus',
-    'python3-venv',
-    'socat',
-    'softhsm2',
-    'unbound-host',
-    'unixodbc',
-    'wget',
+    "libzmq3-dev",
+    "lmdb-utils",
+    "prometheus",
+    "python3-venv",
+    "socat",
+    "softhsm2",
+    "unbound-host",
+    "unixodbc",
+    "wget",
 ]
 doc_deps = [
-    'autoconf',
-    'automake',
-    'bison',
-    'curl',
-    'flex',
-    'g++',
-    'git',
-    'latexmk',
-    'libboost-all-dev',
-    'libedit-dev',
-    'libluajit-5.1-dev',
-    'libssl-dev',
-    'make',
-    'pkg-config',
-    'python3-venv',
-    'ragel',
-    'rsync',
+    "autoconf",
+    "automake",
+    "bison",
+    "curl",
+    "flex",
+    "g++",
+    "git",
+    "latexmk",
+    "libboost-all-dev",
+    "libedit-dev",
+    "libluajit-5.1-dev",
+    "libssl-dev",
+    "make",
+    "pkg-config",
+    "python3-venv",
+    "ragel",
+    "rsync",
 ]
 doc_deps_pdf = [
-    'texlive-binaries',
-    'texlive-formats-extra',
-    'texlive-latex-extra',
+    "texlive-binaries",
+    "texlive-formats-extra",
+    "texlive-latex-extra",
 ]
 
+
 @task
 def apt_fresh(c):
-    c.sudo('apt-get update')
-    c.sudo('apt-get -y --allow-downgrades dist-upgrade')
+    c.sudo("apt-get update")
+    c.sudo("apt-get -y --allow-downgrades dist-upgrade")
+
 
 @task
 def install_lld_linker_if_needed(c):
     if is_compiler_clang():
-        c.sudo(f'apt-get -y --no-install-recommends install lld-{clang_version}')
+        c.sudo(f"apt-get -y --no-install-recommends install lld-{clang_version}")
+
 
 @task
 def install_clang(c):
@@ -181,83 +175,106 @@ def install_clang(c):
     install clang and llvm
     """
     if int(clang_version) >= 14:
-        c.sudo(f'apt-get -y --no-install-recommends install clang-{clang_version} llvm-{clang_version} llvm-{clang_version}-dev libclang-rt-{clang_version}-dev')
+        c.sudo(
+            f"apt-get -y --no-install-recommends install clang-{clang_version} llvm-{clang_version} llvm-{clang_version}-dev libclang-rt-{clang_version}-dev"
+        )
     else:
-        c.sudo(f'apt-get -y --no-install-recommends install clang-{clang_version} llvm-{clang_version} llvm-{clang_version}-dev')
+        c.sudo(
+            f"apt-get -y --no-install-recommends install clang-{clang_version} llvm-{clang_version} llvm-{clang_version}-dev"
+        )
+
 
 @task
 def install_clang_tidy_tools(c):
-    c.sudo(f'apt-get -y --no-install-recommends install clang-tidy-{clang_version} clang-tools-{clang_version} bear python3-yaml')
+    c.sudo(
+        f"apt-get -y --no-install-recommends install clang-tidy-{clang_version} clang-tools-{clang_version} bear python3-yaml"
+    )
+
 
 @task
 def install_clang_runtime(c):
     # this gives us the symbolizer, for symbols in asan/ubsan traces
     # on Debian we need llvm-symbolizer-XX
-    #c.sudo(f'apt-get -y --no-install-recommends install llvm-symbolizer-{clang_version}')
+    # c.sudo(f'apt-get -y --no-install-recommends install llvm-symbolizer-{clang_version}')
     # on Ubuntu we need llvm-XX instead
-    c.sudo(f'apt-get -y --no-install-recommends install llvm-{clang_version}')
+    c.sudo(f"apt-get -y --no-install-recommends install llvm-{clang_version}")
+
 
 @task
 def ci_install_rust(c, repo):
-    with c.cd(f'{repo}/builder-support/helpers/'):
-        c.run('sudo sh install_rust.sh')
+    with c.cd(f"{repo}/builder-support/helpers/"):
+        c.run("sudo sh install_rust.sh")
+
 
 @task
 def install_doc_deps(c):
-    c.sudo('apt-get install -y ' + ' '.join(doc_deps))
+    c.sudo("apt-get install -y " + " ".join(doc_deps))
+
 
 @task
 def install_doc_deps_pdf(c):
-    c.sudo('apt-get install -y ' + ' '.join(doc_deps_pdf))
+    c.sudo("apt-get install -y " + " ".join(doc_deps_pdf))
+
 
 @task
 def install_auth_build_deps(c):
-    c.sudo('apt-get install -y --no-install-recommends ' + ' '.join(all_build_deps + git_build_deps + auth_build_deps))
+    c.sudo("apt-get install -y --no-install-recommends " + " ".join(all_build_deps + git_build_deps + auth_build_deps))
+
 
 def is_coverage_enabled():
-    sanitizers = os.getenv('SANITIZERS')
+    sanitizers = os.getenv("SANITIZERS")
     if sanitizers:
-        sanitizers = sanitizers.split('+')
-        if 'tsan' in sanitizers:
+        sanitizers = sanitizers.split("+")
+        if "tsan" in sanitizers:
             return False
-    return os.getenv('COVERAGE') == 'yes'
+    return os.getenv("COVERAGE") == "yes"
+
 
 def get_coverage(meson=False):
     if meson:
-        return '-Dclang-coverage-format=true' if is_coverage_enabled() else ''
-    return '--enable-coverage=clang' if is_coverage_enabled() else ''
+        return "-Dclang-coverage-format=true" if is_coverage_enabled() else ""
+    return "--enable-coverage=clang" if is_coverage_enabled() else ""
+
 
 @task
 def install_coverage_deps(c):
     if is_coverage_enabled():
-        c.sudo(f'apt-get install -y --no-install-recommends llvm-{clang_version}')
+        c.sudo(f"apt-get install -y --no-install-recommends llvm-{clang_version}")
+
 
 @task
 def generate_coverage_info(c, binary, product, outputDir):
     if is_coverage_enabled():
-        version = os.getenv('BUILDER_VERSION')
-        c.run(f'llvm-profdata-{clang_version} merge -sparse -o {outputDir}/temp.profdata /tmp/code-*.profraw')
-        c.run(f'llvm-cov-{clang_version} export --format=lcov --ignore-filename-regex=\'^/usr/\' --ignore-filename-regex=\'ext/\' -instr-profile={outputDir}/temp.profdata -object {binary} > {outputDir}/coverage.lcov')
-        c.run(f'{outputDir}/.github/scripts/normalize_paths_in_coverage.py {outputDir} {product} {version} {outputDir}/coverage.lcov {outputDir}/normalized_coverage.lcov 0')
-        c.run(f'mv {outputDir}/normalized_coverage.lcov {outputDir}/coverage.lcov')
+        version = os.getenv("BUILDER_VERSION")
+        c.run(f"llvm-profdata-{clang_version} merge -sparse -o {outputDir}/temp.profdata /tmp/code-*.profraw")
+        c.run(
+            f"llvm-cov-{clang_version} export --format=lcov --ignore-filename-regex='^/usr/' --ignore-filename-regex='ext/' -instr-profile={outputDir}/temp.profdata -object {binary} > {outputDir}/coverage.lcov"
+        )
+        c.run(
+            f"{outputDir}/.github/scripts/normalize_paths_in_coverage.py {outputDir} {product} {version} {outputDir}/coverage.lcov {outputDir}/normalized_coverage.lcov 0"
+        )
+        c.run(f"mv {outputDir}/normalized_coverage.lcov {outputDir}/coverage.lcov")
+
 
 def setup_authbind(c):
-    c.sudo('touch /etc/authbind/byport/53')
-    c.sudo('chmod 755 /etc/authbind/byport/53')
-    c.sudo('touch /etc/authbind/byport/!853')
-    c.sudo('chmod 755 /etc/authbind/byport/!853')
+    c.sudo("touch /etc/authbind/byport/53")
+    c.sudo("chmod 755 /etc/authbind/byport/53")
+    c.sudo("touch /etc/authbind/byport/!853")
+    c.sudo("chmod 755 /etc/authbind/byport/!853")
+
 
 # Builds and installs libfaketime from wolfcw/libfaketime (master)
 def build_and_install_libfaketime(c):
-    c.run(f'git clone https://github.com/wolfcw/libfaketime.git {repo_home}/libfaketime')
-    with c.cd(f'{repo_home}/libfaketime'):
-        c.run('git checkout master')
-        c.run('make && sudo make install')
+    c.run(f"git clone https://github.com/wolfcw/libfaketime.git {repo_home}/libfaketime")
+    with c.cd(f"{repo_home}/libfaketime"):
+        c.run("git checkout master")
+        c.run("make && sudo make install")
+
 
 auth_backend_test_deps = dict(
-    gsqlite3=['sqlite3'],
-    gmysql=['default-libmysqlclient-dev'],
-    gpgsql=['libpq-dev'],
+    gsqlite3=["sqlite3"],
+    gmysql=["default-libmysqlclient-dev"],
+    gpgsql=["libpq-dev"],
     lmdb=[],
     remote=[],
     bind=[],
@@ -265,67 +282,89 @@ auth_backend_test_deps = dict(
     lua2=[],
     tinydns=[],
     authpy=[],
-    godbc_sqlite3=['libsqliteodbc'],
-    godbc_mssql=['freetds-bin','tdsodbc'],
+    godbc_sqlite3=["libsqliteodbc"],
+    godbc_mssql=["freetds-bin", "tdsodbc"],
     ldap=[],
-    geoip_mmdb=[]
+    geoip_mmdb=[],
 )
 
-@task(help={'backend': 'Backend to install test deps for, e.g. gsqlite3; can be repeated'}, iterable=['backend'], optional=['backend'])
+
+@task(
+    help={"backend": "Backend to install test deps for, e.g. gsqlite3; can be repeated"},
+    iterable=["backend"],
+    optional=["backend"],
+)
 def install_auth_test_deps_only(c, backend):
-    extra=[]
+    extra = []
     for b in backend:
         extra.extend(auth_backend_test_deps[b])
-    c.sudo('apt-get update')
-    c.sudo('DEBIAN_FRONTEND=noninteractive apt-get -y install ' + ' '.join(extra+auth_test_deps))
+    c.sudo("apt-get update")
+    c.sudo("DEBIAN_FRONTEND=noninteractive apt-get -y install " + " ".join(extra + auth_test_deps))
     # install libfaketime manually
     build_and_install_libfaketime(c)
 
-@task(help={'backend': 'Backend to install test deps for, e.g. gsqlite3; can be repeated'}, iterable=['backend'], optional=['backend'])
-def install_auth_test_deps(c, backend): # FIXME: rename this, we do way more than apt-get
+
+@task(
+    help={"backend": "Backend to install test deps for, e.g. gsqlite3; can be repeated"},
+    iterable=["backend"],
+    optional=["backend"],
+)
+def install_auth_test_deps(c, backend):  # FIXME: rename this, we do way more than apt-get
     install_auth_test_deps_only(c, backend)
 
-    c.run('chmod +x /opt/pdns-auth/bin/* /opt/pdns-auth/sbin/*')
+    c.run("chmod +x /opt/pdns-auth/bin/* /opt/pdns-auth/sbin/*")
     # c.run('''if [ ! -e $HOME/bin/jdnssec-verifyzone ]; then
     #               wget https://github.com/dblacka/jdnssec-tools/releases/download/0.14/jdnssec-tools-0.14.tar.gz
     #               tar xfz jdnssec-tools-0.14.tar.gz -C $HOME
     #               rm jdnssec-tools-0.14.tar.gz
     #          fi
     #          echo 'export PATH=$HOME/jdnssec-tools-0.14/bin:$PATH' >> $BASH_ENV''')  # FIXME: why did this fail with no error?
-    c.run('touch regression-tests/tests/verify-dnssec-zone/allow-missing regression-tests.nobackend/rectify-axfr/allow-missing') # FIXME: can this go?
+    c.run(
+        "touch regression-tests/tests/verify-dnssec-zone/allow-missing regression-tests.nobackend/rectify-axfr/allow-missing"
+    )  # FIXME: can this go?
     # FIXME we may want to start a background recursor here to make ALIAS tests more robust
     setup_authbind(c)
 
+
 @task
-def install_rec_bulk_deps(c): # FIXME: rename this, we do way more than apt-get
-    c.sudo('apt-get --no-install-recommends -y install ' + ' '.join(rec_bulk_deps))
-    c.run('chmod +x /opt/pdns-recursor/bin/* /opt/pdns-recursor/sbin/*')
+def install_rec_bulk_deps(c):  # FIXME: rename this, we do way more than apt-get
+    c.sudo("apt-get --no-install-recommends -y install " + " ".join(rec_bulk_deps))
+    c.run("chmod +x /opt/pdns-recursor/bin/* /opt/pdns-recursor/sbin/*")
+
 
 @task
-def install_rec_bulk_ubicloud_deps(c): # FIXME: rename this, we do way more than apt-get
-    c.sudo('apt-get --no-install-recommends -y install ' + ' '.join(rec_bulk_ubicloud_deps))
-    c.run('chmod +x /opt/pdns-recursor/bin/* /opt/pdns-recursor/sbin/*')
+def install_rec_bulk_ubicloud_deps(c):  # FIXME: rename this, we do way more than apt-get
+    c.sudo("apt-get --no-install-recommends -y install " + " ".join(rec_bulk_ubicloud_deps))
+    c.run("chmod +x /opt/pdns-recursor/bin/* /opt/pdns-recursor/sbin/*")
+
 
 @task
-def install_rec_test_deps(c): # FIXME: rename this, we do way more than apt-get
-    c.sudo('apt-get --no-install-recommends install -y ' + ' '.join(rec_bulk_deps) + ' \
+def install_rec_test_deps(c):  # FIXME: rename this, we do way more than apt-get
+    c.sudo(
+        "apt-get --no-install-recommends install -y "
+        + " ".join(rec_bulk_deps)
+        + " \
               pdns-server pdns-backend-bind daemontools \
               jq lua-posix lua-socket bc authbind \
               python3-venv python3-dev default-libmysqlclient-dev libpq-dev \
-              protobuf-compiler snmpd prometheus')
-    c.run('chmod +x /opt/pdns-recursor/bin/* /opt/pdns-recursor/sbin/*')
+              protobuf-compiler snmpd prometheus"
+    )
+    c.run("chmod +x /opt/pdns-recursor/bin/* /opt/pdns-recursor/sbin/*")
 
     setup_authbind(c)
 
-    c.run('sed "s/agentxperms 0700 0755 recursor/agentxperms 0777 0755/g" regression-tests.recursor-dnssec/snmpd.conf | sudo tee /etc/snmp/snmpd.conf')
-    c.sudo('/etc/init.d/snmpd restart')
+    c.run(
+        'sed "s/agentxperms 0700 0755 recursor/agentxperms 0777 0755/g" regression-tests.recursor-dnssec/snmpd.conf | sudo tee /etc/snmp/snmpd.conf'
+    )
+    c.sudo("/etc/init.d/snmpd restart")
     time.sleep(5)
-    c.sudo('chmod 755 /var/agentx')
+    c.sudo("chmod 755 /var/agentx")
     # install libfaketime manually
     build_and_install_libfaketime(c)
 
-@task(optional=['skipXDP'])
-def install_dnsdist_test_deps(c, skipXDP=False): # FIXME: rename this, we do way more than apt-get
+
+@task(optional=["skipXDP"])
+def install_dnsdist_test_deps(c, skipXDP=False):  # FIXME: rename this, we do way more than apt-get
     deps = 'libluajit-5.1-2 \
             libboost-all-dev \
             libcap2 \
@@ -344,348 +383,409 @@ def install_dnsdist_test_deps(c, skipXDP=False): # FIXME: rename this, we do way
             protobuf-compiler \
             python3-venv snmpd prometheus'
     if not skipXDP:
-        deps = deps + '\
+        deps = (
+            deps
+            + "\
                libbpf1 \
-               libxdp1'
-
-    c.sudo(f'apt-get install -y {deps}')
-    c.run('sed "s/agentxperms 0700 0755 dnsdist/agentxperms 0777 0755/g" regression-tests.dnsdist/snmpd.conf | sudo tee /etc/snmp/snmpd.conf')
-    c.sudo('/etc/init.d/snmpd restart')
+               libxdp1"
+        )
+
+    c.sudo(f"apt-get install -y {deps}")
+    c.run(
+        'sed "s/agentxperms 0700 0755 dnsdist/agentxperms 0777 0755/g" regression-tests.dnsdist/snmpd.conf | sudo tee /etc/snmp/snmpd.conf'
+    )
+    c.sudo("/etc/init.d/snmpd restart")
     time.sleep(5)
-    c.sudo('chmod 755 /var/agentx')
+    c.sudo("chmod 755 /var/agentx")
+
 
 @task
 def install_rec_build_deps(c):
-    c.sudo('apt-get install -y --no-install-recommends ' +  ' '.join(all_build_deps + git_build_deps + rec_build_deps))
+    c.sudo("apt-get install -y --no-install-recommends " + " ".join(all_build_deps + git_build_deps + rec_build_deps))
 
-@task(optional=['skipXDP'])
+
+@task(optional=["skipXDP"])
 def install_dnsdist_build_deps(c, skipXDP=False):
-    c.sudo('apt-get install -y --no-install-recommends ' +  ' '.join(all_build_deps + git_build_deps + dnsdist_build_deps + (dnsdist_xdp_build_deps if not skipXDP else [])))
+    c.sudo(
+        "apt-get install -y --no-install-recommends "
+        + " ".join(
+            all_build_deps + git_build_deps + dnsdist_build_deps + (dnsdist_xdp_build_deps if not skipXDP else [])
+        )
+    )
+
 
 @task
 def ci_autoconf(c, meson=False):
     if not meson:
-        c.run('autoreconf -vfi')
+        c.run("autoreconf -vfi")
+
 
 @task
 def ci_docs_rec_generate(c):
-    c.run('python3 generate.py')
+    c.run("python3 generate.py")
+
 
 @task
 def ci_metrics_rec_generate(c):
-    c.run('python3 metrics.py')
+    c.run("python3 metrics.py")
+
 
 @task
 def ci_docs_dnsdist_generate(c):
-    c.run('python3 dnsdist-settings-documentation-generator.py .')
+    c.run("python3 dnsdist-settings-documentation-generator.py .")
+
 
 @task
 def ci_docs_build(c):
-    c.run('make -f Makefile.sphinx -C docs html')
+    c.run("make -f Makefile.sphinx -C docs html")
+
 
 @task
 def ci_docs_build_pdf(c):
-    c.run('make -f Makefile.sphinx -C docs latexpdf')
+    c.run("make -f Makefile.sphinx -C docs latexpdf")
+
 
 @task
 def ci_docs_upload_master(c, docs_host, pdf, username, product, directory=""):
-    rsync_cmd = " ".join([
-        "rsync",
-        "--checksum",
-        "--recursive",
-        "--verbose",
-        "--no-p",
-        "--chmod=g=rwX",
-        "--exclude '*~'",
-    ])
+    rsync_cmd = " ".join(
+        [
+            "rsync",
+            "--checksum",
+            "--recursive",
+            "--verbose",
+            "--no-p",
+            "--chmod=g=rwX",
+            "--exclude '*~'",
+        ]
+    )
     c.run(f"{rsync_cmd} --delete ./docs/_build/{product}-html-docs/ {username}@{docs_host}:{directory}")
 
+
 @task
 def ci_docs_add_ssh(c, ssh_key, host_key):
-    c.run('mkdir -m 700 -p ~/.ssh')
+    c.run("mkdir -m 700 -p ~/.ssh")
     c.run(f'echo "{ssh_key}" > ~/.ssh/id_ed25519')
-    c.run('chmod 600 ~/.ssh/id_ed25519')
+    c.run("chmod 600 ~/.ssh/id_ed25519")
     c.run(f'echo "{host_key}" > ~/.ssh/known_hosts')
 
 
 def get_sanitizers(meson=False):
-    sanitizers = os.getenv('SANITIZERS', '')
+    sanitizers = os.getenv("SANITIZERS", "")
     if meson:
-        subst = {
-            'tsan': 'thread',
-            'asan': 'address',
-            'ubsan': 'undefined'
-        }
-        meson_sanitizers = ''
-        sanitizers = sanitizers.split('+')
+        subst = {"tsan": "thread", "asan": "address", "ubsan": "undefined"}
+        meson_sanitizers = ""
+        sanitizers = sanitizers.split("+")
         for sanitizer in sanitizers:
             if sanitizer in subst:
-                if meson_sanitizers != '':
-                    meson_sanitizers = meson_sanitizers + ','
+                if meson_sanitizers != "":
+                    meson_sanitizers = meson_sanitizers + ","
                 meson_sanitizers = meson_sanitizers + subst[sanitizer]
             else:
                 meson_sanitizers = meson_sanitizers + sanitizer
 
-        return f'-D b_sanitize={meson_sanitizers}' if meson_sanitizers != '' else ''
-    if sanitizers != '':
-        sanitizers = sanitizers.split('+')
-        sanitizers = ['--enable-' + sanitizer for sanitizer in sanitizers]
-        sanitizers = ' '.join(sanitizers)
+        return f"-D b_sanitize={meson_sanitizers}" if meson_sanitizers != "" else ""
+    if sanitizers != "":
+        sanitizers = sanitizers.split("+")
+        sanitizers = ["--enable-" + sanitizer for sanitizer in sanitizers]
+        sanitizers = " ".join(sanitizers)
     return sanitizers
 
+
 def get_unit_tests(meson=False, auth=False):
-    if os.getenv('UNIT_TESTS') != 'yes':
-        return ''
+    if os.getenv("UNIT_TESTS") != "yes":
+        return ""
     if meson:
-        return '-D unit-tests=true -D unit-tests-backends=true' if auth else '-D unit-tests=true'
-    return '--enable-unit-tests --enable-backend-unit-tests' if auth else '--enable-unit-tests'
+        return "-D unit-tests=true -D unit-tests-backends=true" if auth else "-D unit-tests=true"
+    return "--enable-unit-tests --enable-backend-unit-tests" if auth else "--enable-unit-tests"
+
 
 def get_build_concurrency(default=8):
-    return os.getenv('CONCURRENCY', default)
+    return os.getenv("CONCURRENCY", default)
+
 
 def get_fuzzing_targets(meson=False):
     if meson:
-        return '-D fuzz-targets=true' if os.getenv('FUZZING_TARGETS') == 'yes' else ''
-    return '--enable-fuzz-targets' if os.getenv('FUZZING_TARGETS') == 'yes' else ''
+        return "-D fuzz-targets=true" if os.getenv("FUZZING_TARGETS") == "yes" else ""
+    return "--enable-fuzz-targets" if os.getenv("FUZZING_TARGETS") == "yes" else ""
+
 
 def is_compiler_clang():
-    compiler = os.getenv('COMPILER', 'clang')
-    return compiler == 'clang'
+    compiler = os.getenv("COMPILER", "clang")
+    return compiler == "clang"
+
 
 def get_c_compiler(versioned_clang=True):
-    compiler = f'clang' if is_compiler_clang() else 'gcc'
+    compiler = f"clang" if is_compiler_clang() else "gcc"
     if is_compiler_clang() and versioned_clang:
-        compiler = f'clang-{clang_version}'
+        compiler = f"clang-{clang_version}"
     return compiler
 
+
 def get_cxx_compiler(versioned_clang=True):
-    compiler = f'clang++' if is_compiler_clang() else 'g++'
+    compiler = f"clang++" if is_compiler_clang() else "g++"
     if is_compiler_clang() and versioned_clang:
-        compiler = f'clang++-{clang_version}'
+        compiler = f"clang++-{clang_version}"
     return compiler
 
+
 def get_optimizations():
-    optimizations = os.getenv('OPTIMIZATIONS', 'yes')
-    return '-O1' if optimizations == 'yes' else '-O0'
+    optimizations = os.getenv("OPTIMIZATIONS", "yes")
+    return "-O1" if optimizations == "yes" else "-O0"
+
 
 def get_protections():
-    if platform.machine() in ['aarch64', 'arm64']:
-        return "-fcf-protection=check",
-    return "-fcf-protection=full",
+    if platform.machine() in ["aarch64", "arm64"]:
+        return ("-fcf-protection=check",)
+    return ("-fcf-protection=full",)
 
 
 def get_cflags():
-    return " ".join([
-        get_optimizations(),
-        "-Werror=vla",
-        "-Werror=shadow",
-        "-Wformat=2",
-        "-Werror=format-security",
-        "-fstack-clash-protection",
-        "-fstack-protector-strong",
-        "-Werror=string-plus-int" if is_compiler_clang() else '',
-    ])
+    return " ".join(
+        [
+            get_optimizations(),
+            "-Werror=vla",
+            "-Werror=shadow",
+            "-Wformat=2",
+            "-Werror=format-security",
+            "-fstack-clash-protection",
+            "-fstack-protector-strong",
+            "-Werror=string-plus-int" if is_compiler_clang() else "",
+        ]
+    )
 
 
 def get_cxxflags():
-    return " ".join([
-        get_cflags(),
-        "-Wp,-D_GLIBCXX_ASSERTIONS",
-    ])
-
-
-def get_base_configure_cmd(additional_c_flags='', additional_cxx_flags='', additional_ld_flags='', enable_systemd=True, enable_sodium=True, out_of_tree_build=False):
+    return " ".join(
+        [
+            get_cflags(),
+            "-Wp,-D_GLIBCXX_ASSERTIONS",
+        ]
+    )
+
+
+def get_base_configure_cmd(
+    additional_c_flags="",
+    additional_cxx_flags="",
+    additional_ld_flags="",
+    enable_systemd=True,
+    enable_sodium=True,
+    out_of_tree_build=False,
+):
     cflags = " ".join([get_cflags(), additional_c_flags])
     cxxflags = " ".join([get_cxxflags(), additional_cxx_flags])
     ldflags = additional_ld_flags
-    return " ".join([
-        f'CFLAGS="{cflags}"',
-        f'CXXFLAGS="{cxxflags}"',
-        f'LDFLAGS="{ldflags}"',
-        './configure' if not out_of_tree_build else '../configure',
-        f"CC='{get_c_compiler()}'",
-        f"CXX='{get_cxx_compiler()}'",
-        "--enable-option-checking=fatal",
-        "--enable-systemd" if enable_systemd else '',
-        "--with-libsodium" if enable_sodium else '',
-        "--enable-fortify-source=auto",
-        "--enable-auto-var-init=pattern",
-        get_coverage(),
-        get_sanitizers()
-    ])
-
-def get_base_configure_cmd_meson(build_dir, additional_c_flags='', additional_cxx_flags='', enable_systemd=True, enable_sodium=True, src_dir=''):
+    return " ".join(
+        [
+            f'CFLAGS="{cflags}"',
+            f'CXXFLAGS="{cxxflags}"',
+            f'LDFLAGS="{ldflags}"',
+            "./configure" if not out_of_tree_build else "../configure",
+            f"CC='{get_c_compiler()}'",
+            f"CXX='{get_cxx_compiler()}'",
+            "--enable-option-checking=fatal",
+            "--enable-systemd" if enable_systemd else "",
+            "--with-libsodium" if enable_sodium else "",
+            "--enable-fortify-source=auto",
+            "--enable-auto-var-init=pattern",
+            get_coverage(),
+            get_sanitizers(),
+        ]
+    )
+
+
+def get_base_configure_cmd_meson(
+    build_dir, additional_c_flags="", additional_cxx_flags="", enable_systemd=True, enable_sodium=True, src_dir=""
+):
     cflags = " ".join([get_cflags(), additional_c_flags])
     cxxflags = " ".join([get_cxxflags(), additional_cxx_flags])
-    env = " ".join([
-        f'CFLAGS="{cflags}"',
-        f'CXXFLAGS="{cxxflags}"',
-        f"CC='{get_c_compiler()}'",
-        f"CXX='{get_cxx_compiler()}'"
-    ])
-    return " ".join([
-        f'{env} meson setup {build_dir} {src_dir}',
-        "-D systemd-service={}".format("enabled" if enable_systemd else "disabled"),
-        "-D signers-libsodium={}".format("enabled" if enable_sodium else "disabled"),
-        "-D hardening-fortify-source=auto",
-        "-D auto-var-init=pattern",
-        get_coverage(meson=True),
-        get_sanitizers(meson=True)
-    ])
+    env = " ".join(
+        [f'CFLAGS="{cflags}"', f'CXXFLAGS="{cxxflags}"', f"CC='{get_c_compiler()}'", f"CXX='{get_cxx_compiler()}'"]
+    )
+    return " ".join(
+        [
+            f"{env} meson setup {build_dir} {src_dir}",
+            "-D systemd-service={}".format("enabled" if enable_systemd else "disabled"),
+            "-D signers-libsodium={}".format("enabled" if enable_sodium else "disabled"),
+            "-D hardening-fortify-source=auto",
+            "-D auto-var-init=pattern",
+            get_coverage(meson=True),
+            get_sanitizers(meson=True),
+        ]
+    )
+
 
 def ci_auth_configure_autotools(c):
     unittests = get_unit_tests(auth=True)
     fuzz_targets = get_fuzzing_targets()
-    modules = " ".join([
-        "bind",
-        "geoip",
-        "gmysql",
-        "godbc",
-        "gpgsql",
-        "gsqlite3",
-        "ldap",
-        "lmdb",
-        "lua2",
-        "pipe",
-        "remote",
-        "tinydns",
-    ])
-    configure_cmd = " ".join([
-        get_base_configure_cmd(),
-        "LDFLAGS='-L/usr/local/lib -Wl,-rpath,/usr/local/lib'",
-        f"--with-modules='{modules}'",
-        "--enable-tools",
-        "--enable-dns-over-tls",
-        "--enable-experimental-pkcs11",
-        "--enable-experimental-gss-tsig",
-        "--enable-remotebackend-zeromq",
-        "--enable-verbose-logging",
-        "--with-lmdb=/usr",
-        "--prefix=/opt/pdns-auth",
-        "--enable-ixfrdist",
-        unittests,
-        fuzz_targets
-    ])
+    modules = " ".join(
+        [
+            "bind",
+            "geoip",
+            "gmysql",
+            "godbc",
+            "gpgsql",
+            "gsqlite3",
+            "ldap",
+            "lmdb",
+            "lua2",
+            "pipe",
+            "remote",
+            "tinydns",
+        ]
+    )
+    configure_cmd = " ".join(
+        [
+            get_base_configure_cmd(),
+            "LDFLAGS='-L/usr/local/lib -Wl,-rpath,/usr/local/lib'",
+            f"--with-modules='{modules}'",
+            "--enable-tools",
+            "--enable-dns-over-tls",
+            "--enable-experimental-pkcs11",
+            "--enable-experimental-gss-tsig",
+            "--enable-remotebackend-zeromq",
+            "--enable-verbose-logging",
+            "--with-lmdb=/usr",
+            "--prefix=/opt/pdns-auth",
+            "--enable-ixfrdist",
+            unittests,
+            fuzz_targets,
+        ]
+    )
     res = c.run(configure_cmd, warn=True)
     if res.exited != 0:
-        c.run('cat config.log')
+        c.run("cat config.log")
         raise UnexpectedExit(res)
 
-AUTH_CONFIGURE_MESON_ALL_BACKENDS_STATIC = " ".join([
-    "-D module-bind=static",
-    "-D module-geoip=static",
-    "-D module-gmysql=static",
-    "-D module-godbc=static",
-    "-D module-gpgsql=static",
-    "-D module-gsqlite3=static",
-    "-D module-ldap=static",
-    "-D module-lmdb=static",
-    "-D module-lua2=static",
-    "-D module-pipe=static",
-    "-D module-remote=static",
-    "-D module-remote-zeromq=true",
-    "-D module-tinydns=static"])
-
-AUTH_CONFIGURE_MESON_LEAST_BACKENDS_STATIC = " ".join([
-    "-D module-bind=static",
-    "-D module-gsqlite3=static",
-    "-D module-remote=static"])
-
-AUTH_CONFIGURE_MESON_TOOLS = " ".join([
-    "-D tools=true",
-    "-D tools-ixfrdist=true"])
-
-AUTH_CONFIGURE_MESON_FEATURES = " ".join([
-    "-D dns-over-tls=enabled",
-    "-D experimental-pkcs11=enabled",
-    "-D experimental-gss-tsig=enabled"])
-
-@task(help={
-    'features': 'What feature-set to build, one of "full" or "least". The former builds all backends, the latter only bind, gsqlite3 and remote',
-    'build_dir': 'Where Meson should configure into',
-    'clang': 'Use clang instead of GCC',
-    'ccache': 'Use ccache',
-    'tools': 'Build all tools (sdig, ixfrdist, etc.)',
-    'unit_tests': 'Enable unit tests',
-    'coverage': 'Create code coverage files',
-})
-def dev_auth_configure_meson(c, features, build_dir="build", clang=False, ccache=False, tools=True, unit_tests=False, coverage=False):
-    additional_ld_flags = ''
-    unittests=''
-    cc = 'gcc'
-    cxx = 'g++'
+
+AUTH_CONFIGURE_MESON_ALL_BACKENDS_STATIC = " ".join(
+    [
+        "-D module-bind=static",
+        "-D module-geoip=static",
+        "-D module-gmysql=static",
+        "-D module-godbc=static",
+        "-D module-gpgsql=static",
+        "-D module-gsqlite3=static",
+        "-D module-ldap=static",
+        "-D module-lmdb=static",
+        "-D module-lua2=static",
+        "-D module-pipe=static",
+        "-D module-remote=static",
+        "-D module-remote-zeromq=true",
+        "-D module-tinydns=static",
+    ]
+)
+
+AUTH_CONFIGURE_MESON_LEAST_BACKENDS_STATIC = " ".join(
+    ["-D module-bind=static", "-D module-gsqlite3=static", "-D module-remote=static"]
+)
+
+AUTH_CONFIGURE_MESON_TOOLS = " ".join(["-D tools=true", "-D tools-ixfrdist=true"])
+
+AUTH_CONFIGURE_MESON_FEATURES = " ".join(
+    ["-D dns-over-tls=enabled", "-D experimental-pkcs11=enabled", "-D experimental-gss-tsig=enabled"]
+)
+
+
+@task(
+    help={
+        "features": 'What feature-set to build, one of "full" or "least". The former builds all backends, the latter only bind, gsqlite3 and remote',
+        "build_dir": "Where Meson should configure into",
+        "clang": "Use clang instead of GCC",
+        "ccache": "Use ccache",
+        "tools": "Build all tools (sdig, ixfrdist, etc.)",
+        "unit_tests": "Enable unit tests",
+        "coverage": "Create code coverage files",
+    }
+)
+def dev_auth_configure_meson(
+    c, features, build_dir="build", clang=False, ccache=False, tools=True, unit_tests=False, coverage=False
+):
+    additional_ld_flags = ""
+    unittests = ""
+    cc = "gcc"
+    cxx = "g++"
     if clang:
-        additional_ld_flags += '-fuse-ld=lld '
-        cc = 'clang'
-        cxx = 'clang++'
+        additional_ld_flags += "-fuse-ld=lld "
+        cc = "clang"
+        cxx = "clang++"
 
-    os.environ['COMPILER'] = cc
+    os.environ["COMPILER"] = cc
 
     if ccache:
-        cc = f'ccache {cc}'
-        cxx = f'ccache {cxx}'
+        cc = f"ccache {cc}"
+        cxx = f"ccache {cxx}"
     if unit_tests:
-        unittests = '-D unit-tests=true'
+        unittests = "-D unit-tests=true"
 
     cflags = " ".join([get_cflags()])
     cxxflags = " ".join([get_cxxflags()])
 
     tools_opts = ""
     if tools:
-      tools_opts = AUTH_CONFIGURE_MESON_TOOLS
+        tools_opts = AUTH_CONFIGURE_MESON_TOOLS
 
     features_set = ""
-    if features == 'full':
-      features_set = AUTH_CONFIGURE_MESON_FEATURES
-      backend_opts = AUTH_CONFIGURE_MESON_ALL_BACKENDS_STATIC
-    elif features == 'least':
-      backend_opts = AUTH_CONFIGURE_MESON_LEAST_BACKENDS_STATIC
+    if features == "full":
+        features_set = AUTH_CONFIGURE_MESON_FEATURES
+        backend_opts = AUTH_CONFIGURE_MESON_ALL_BACKENDS_STATIC
+    elif features == "least":
+        backend_opts = AUTH_CONFIGURE_MESON_LEAST_BACKENDS_STATIC
     else:
         raise KeyError(f'features should be one of "full" or "least", not "{features}"')
 
     if coverage:
-        os.environ['COVERAGE'] = 'yes'
+        os.environ["COVERAGE"] = "yes"
 
     reconf_opt = "--reconfigure" if os.path.exists(build_dir) else ""
 
-    env = " ".join([
-        f"CC='{cc}'",
-        f"CXX='{cxx}'",
-        f'CFLAGS="{cflags}"',
-        f'LDFLAGS="{additional_ld_flags}"',
-        f'CXXFLAGS="{cxxflags}"',
-    ])
-    c.run(" ".join([
-        f'{env} meson setup {build_dir}',
-        reconf_opt,
-        features_set,
-        tools_opts,
-        backend_opts,
-        unittests,
-        "-D hardening-fortify-source=auto",
-        "-D auto-var-init=pattern",
-        get_coverage(meson=True),
-        get_sanitizers(meson=True)
-    ]))
+    env = " ".join(
+        [
+            f"CC='{cc}'",
+            f"CXX='{cxx}'",
+            f'CFLAGS="{cflags}"',
+            f'LDFLAGS="{additional_ld_flags}"',
+            f'CXXFLAGS="{cxxflags}"',
+        ]
+    )
+    c.run(
+        " ".join(
+            [
+                f"{env} meson setup {build_dir}",
+                reconf_opt,
+                features_set,
+                tools_opts,
+                backend_opts,
+                unittests,
+                "-D hardening-fortify-source=auto",
+                "-D auto-var-init=pattern",
+                get_coverage(meson=True),
+                get_sanitizers(meson=True),
+            ]
+        )
+    )
+
 
 def ci_auth_configure_meson(c, build_dir):
     unittests = get_unit_tests(meson=True, auth=True)
     fuzz_targets = get_fuzzing_targets(meson=True)
-    configure_cmd = " ".join([
-        "LDFLAGS='-L/usr/local/lib -Wl,-rpath,/usr/local/lib'",
-        get_base_configure_cmd_meson(build_dir),
-        "-D prefix=/opt/pdns-auth",
-        AUTH_CONFIGURE_MESON_FEATURES,
-        AUTH_CONFIGURE_MESON_ALL_BACKENDS_STATIC,
-        AUTH_CONFIGURE_MESON_TOOLS,
-        unittests,
-        fuzz_targets
-    ])
+    configure_cmd = " ".join(
+        [
+            "LDFLAGS='-L/usr/local/lib -Wl,-rpath,/usr/local/lib'",
+            get_base_configure_cmd_meson(build_dir),
+            "-D prefix=/opt/pdns-auth",
+            AUTH_CONFIGURE_MESON_FEATURES,
+            AUTH_CONFIGURE_MESON_ALL_BACKENDS_STATIC,
+            AUTH_CONFIGURE_MESON_TOOLS,
+            unittests,
+            fuzz_targets,
+        ]
+    )
     res = c.run(configure_cmd, warn=True)
     if res.exited != 0:
-        c.run(f'cat {build_dir}/meson-logs/meson-log.txt')
+        c.run(f"cat {build_dir}/meson-logs/meson-log.txt")
         raise UnexpectedExit(res)
 
+
 @task
 def ci_auth_configure(c, build_dir=None, meson=False):
     if meson:
@@ -694,222 +794,254 @@ def ci_auth_configure(c, build_dir=None, meson=False):
         ci_auth_configure_autotools(c)
         if build_dir:
             ci_make_distdir(c)
-            with c.cd(f'{build_dir}'):
+            with c.cd(f"{build_dir}"):
                 ci_auth_configure_autotools(c)
 
-REC_CONFIGURE_MESON_FEATURE_SET_FULL = " ".join([
-    "-D dns-over-tls=enabled",
-    "-D tls-libssl=enabled",
-    "-D tls-gnutls=enabled",
-    "-D nod=enabled",
-    "-D libcap=enabled",
-    "-D lua=luajit",
-    "-D snmp=enabled"])
-
-REC_CONFIGURE_MESON_FEATURE_SET_LEAST = " ".join([
-    "-D dnstap=disabled",
-    "-D dns-over-tls=disabled",
-    "-D tls-libssl=disabled",
-    "-D tls-gnutls=disabled",
-    "-D nod=disabled",
-    "-D systemd-service=disabled",
-    "-D lua=luajit",
-    "-D libcap=disabled",
-    "-D libcurl=disabled",
-    "-D signers-libsodium=disabled",
-    "-D snmp=disabled"])
+
+REC_CONFIGURE_MESON_FEATURE_SET_FULL = " ".join(
+    [
+        "-D dns-over-tls=enabled",
+        "-D tls-libssl=enabled",
+        "-D tls-gnutls=enabled",
+        "-D nod=enabled",
+        "-D libcap=enabled",
+        "-D lua=luajit",
+        "-D snmp=enabled",
+    ]
+)
+
+REC_CONFIGURE_MESON_FEATURE_SET_LEAST = " ".join(
+    [
+        "-D dnstap=disabled",
+        "-D dns-over-tls=disabled",
+        "-D tls-libssl=disabled",
+        "-D tls-gnutls=disabled",
+        "-D nod=disabled",
+        "-D systemd-service=disabled",
+        "-D lua=luajit",
+        "-D libcap=disabled",
+        "-D libcurl=disabled",
+        "-D signers-libsodium=disabled",
+        "-D snmp=disabled",
+    ]
+)
+
 
 @task
-def dev_rec_configure_meson(c, features, build_dir="build", clang=False, ccache=False, unit_tests=False, coverage=False):
-    additional_ld_flags = ''
-    unittests=''
-    cc = 'gcc'
-    cxx = 'g++'
+def dev_rec_configure_meson(
+    c, features, build_dir="build", clang=False, ccache=False, unit_tests=False, coverage=False
+):
+    additional_ld_flags = ""
+    unittests = ""
+    cc = "gcc"
+    cxx = "g++"
     if clang:
-        additional_ld_flags += '-fuse-ld=lld '
-        cc = 'clang'
-        cxx = 'clang++'
+        additional_ld_flags += "-fuse-ld=lld "
+        cc = "clang"
+        cxx = "clang++"
 
-    os.environ['COMPILER'] = cc
+    os.environ["COMPILER"] = cc
 
     if ccache:
-        cc = f'ccache {cc}'
-        cxx = f'ccache {cxx}'
+        cc = f"ccache {cc}"
+        cxx = f"ccache {cxx}"
     if unit_tests:
-        unittests = '-D unit-tests=true'
+        unittests = "-D unit-tests=true"
 
     cflags = " ".join([get_cflags()])
     cxxflags = " ".join([get_cxxflags()])
 
-    if features == 'full':
-      features_set = REC_CONFIGURE_MESON_FEATURE_SET_FULL
+    if features == "full":
+        features_set = REC_CONFIGURE_MESON_FEATURE_SET_FULL
     elif features == "least":
-      features_set = REC_CONFIGURE_MESON_FEATURE_SET_LEAST
+        features_set = REC_CONFIGURE_MESON_FEATURE_SET_LEAST
     else:
         raise KeyError(f'features should be one of "full", "least", not "{features}"')
 
     if coverage:
-        os.environ['COVERAGE'] = 'yes'
+        os.environ["COVERAGE"] = "yes"
 
     reconf_opt = "--reconfigure" if os.path.exists(build_dir) else ""
 
-    env = " ".join([
-        f"CC='{cc}'",
-        f"CXX='{cxx}'",
-        f'CFLAGS="{cflags}"',
-        f'LDFLAGS="{additional_ld_flags}"',
-        f'CXXFLAGS="{cxxflags}"',
-    ])
-    c.run(" ".join([
-        f'{env} meson setup {build_dir}',
-        reconf_opt,
-        features_set,
-        unittests,
-        "-D hardening-fortify-source=auto",
-        "-D auto-var-init=pattern",
-        get_coverage(meson=True),
-        get_sanitizers(meson=True)
-    ]))
+    env = " ".join(
+        [
+            f"CC='{cc}'",
+            f"CXX='{cxx}'",
+            f'CFLAGS="{cflags}"',
+            f'LDFLAGS="{additional_ld_flags}"',
+            f'CXXFLAGS="{cxxflags}"',
+        ]
+    )
+    c.run(
+        " ".join(
+            [
+                f"{env} meson setup {build_dir}",
+                reconf_opt,
+                features_set,
+                unittests,
+                "-D hardening-fortify-source=auto",
+                "-D auto-var-init=pattern",
+                get_coverage(meson=True),
+                get_sanitizers(meson=True),
+            ]
+        )
+    )
 
 
 def ci_rec_configure_meson(c, features, build_dir):
-    builder_version = os.getenv('BUILDER_VERSION')
-    dist_dir = '/tmp/rec-meson-dist-build'
-    c.run(f'meson setup {dist_dir} && meson dist -C {dist_dir} --no-tests')
-    with c.cd(f'{dist_dir}/meson-dist'):
-        c.run(f'tar xf pdns-recursor-{builder_version}.tar.xz')
-    src_dir = f'{dist_dir}/meson-dist/pdns-recursor-{builder_version}'
+    builder_version = os.getenv("BUILDER_VERSION")
+    dist_dir = "/tmp/rec-meson-dist-build"
+    c.run(f"meson setup {dist_dir} && meson dist -C {dist_dir} --no-tests")
+    with c.cd(f"{dist_dir}/meson-dist"):
+        c.run(f"tar xf pdns-recursor-{builder_version}.tar.xz")
+    src_dir = f"{dist_dir}/meson-dist/pdns-recursor-{builder_version}"
 
     unittests = get_unit_tests(meson=True, auth=False)
     if features == "full":
-        configure_cmd = " ".join([
-            "LDFLAGS='-L/usr/local/lib -Wl,-rpath,/usr/local/lib'",
-            get_base_configure_cmd_meson(build_dir, src_dir=src_dir),
-            "-D prefix=/opt/pdns-recursor",
-            unittests,
-            REC_CONFIGURE_MESON_FEATURE_SET_FULL
-        ])
+        configure_cmd = " ".join(
+            [
+                "LDFLAGS='-L/usr/local/lib -Wl,-rpath,/usr/local/lib'",
+                get_base_configure_cmd_meson(build_dir, src_dir=src_dir),
+                "-D prefix=/opt/pdns-recursor",
+                unittests,
+                REC_CONFIGURE_MESON_FEATURE_SET_FULL,
+            ]
+        )
     else:
-        configure_cmd = " ".join([
-            "LDFLAGS='-L/usr/local/lib -Wl,-rpath,/usr/local/lib'",
-            get_base_configure_cmd_meson(build_dir, src_dir=src_dir),
-            "-D prefix=/opt/pdns-recursor",
-            unittests,
-            REC_CONFIGURE_MESON_FEATURE_SET_LEAST
-        ])
+        configure_cmd = " ".join(
+            [
+                "LDFLAGS='-L/usr/local/lib -Wl,-rpath,/usr/local/lib'",
+                get_base_configure_cmd_meson(build_dir, src_dir=src_dir),
+                "-D prefix=/opt/pdns-recursor",
+                unittests,
+                REC_CONFIGURE_MESON_FEATURE_SET_LEAST,
+            ]
+        )
     res = c.run(configure_cmd, warn=True)
     if res.exited != 0:
-        c.run(f'cat {build_dir}/meson-logs/meson-log.txt')
+        c.run(f"cat {build_dir}/meson-logs/meson-log.txt")
         raise UnexpectedExit(res)
 
+
 def ci_rec_configure_autotools(c, features, build_dir=None):
     unittests = get_unit_tests()
     out_of_tree_build = build_dir is not None
-    if features == 'full':
-        configure_cmd = " ".join([
-            get_base_configure_cmd(out_of_tree_build=out_of_tree_build),
-            "--prefix=/opt/pdns-recursor",
-            "--enable-option-checking",
-            "--enable-verbose-logging",
-            "--enable-dns-over-tls",
-            "--enable-nod",
-            "--with-libcap",
-            "--with-lua=luajit",
-            "--with-net-snmp",
-            unittests,
-        ])
+    if features == "full":
+        configure_cmd = " ".join(
+            [
+                get_base_configure_cmd(out_of_tree_build=out_of_tree_build),
+                "--prefix=/opt/pdns-recursor",
+                "--enable-option-checking",
+                "--enable-verbose-logging",
+                "--enable-dns-over-tls",
+                "--enable-nod",
+                "--with-libcap",
+                "--with-lua=luajit",
+                "--with-net-snmp",
+                unittests,
+            ]
+        )
     else:
-        configure_cmd = " ".join([
-            get_base_configure_cmd(out_of_tree_build=out_of_tree_build),
-            "--prefix=/opt/pdns-recursor",
-            "--enable-option-checking",
-            "--enable-verbose-logging",
-            "--disable-dns-over-tls",
-            "--disable-dnstap",
-            "--disable-nod",
-            "--disable-systemd",
-            "--with-lua=luajit",
-            "--without-libcap",
-            "--without-libcurl",
-            "--without-libsodium",
-            "--without-net-snmp",
-            unittests,
-        ])
+        configure_cmd = " ".join(
+            [
+                get_base_configure_cmd(out_of_tree_build=out_of_tree_build),
+                "--prefix=/opt/pdns-recursor",
+                "--enable-option-checking",
+                "--enable-verbose-logging",
+                "--disable-dns-over-tls",
+                "--disable-dnstap",
+                "--disable-nod",
+                "--disable-systemd",
+                "--with-lua=luajit",
+                "--without-libcap",
+                "--without-libcurl",
+                "--without-libsodium",
+                "--without-net-snmp",
+                unittests,
+            ]
+        )
     res = c.run(configure_cmd, warn=True)
     if res.exited != 0:
-        c.run('cat config.log')
+        c.run("cat config.log")
         raise UnexpectedExit(res)
 
+
 @task
 def ci_rec_configure(c, features, build_dir=None, meson=False):
     if meson:
         ci_rec_configure_meson(c, features, build_dir)
     else:
         if build_dir:
-            c.run(f'mkdir -p {build_dir}')
-            with c.cd(f'{build_dir}'):
+            c.run(f"mkdir -p {build_dir}")
+            with c.cd(f"{build_dir}"):
                 ci_rec_configure_autotools(c, features, build_dir)
         else:
             ci_rec_configure_autotools(c, features)
 
-DNSDIST_CONFIGURE_CXXFLAGS_LEAST= " ".join([
-    '-DDISABLE_COMPLETION',
-    '-DDISABLE_DELAY_PIPE',
-    '-DDISABLE_DYNBLOCKS',
-    '-DDISABLE_PROMETHEUS',
-    '-DDISABLE_PROTOBUF',
-    '-DDISABLE_BUILTIN_HTML',
-    '-DDISABLE_CARBON',
-    '-DDISABLE_SECPOLL',
-    '-DDISABLE_DEPRECATED_DYNBLOCK',
-    '-DDISABLE_LUA_WEB_HANDLERS',
-    '-DDISABLE_NON_FFI_DQ_BINDINGS',
-    '-DDISABLE_POLICIES_BINDINGS',
-    '-DDISABLE_PACKETCACHE_BINDINGS',
-    '-DDISABLE_DOWNSTREAM_BINDINGS',
-    '-DDISABLE_COMBO_ADDR_BINDINGS',
-    '-DDISABLE_CLIENT_STATE_BINDINGS',
-    '-DDISABLE_QPS_LIMITER_BINDINGS',
-    '-DDISABLE_SUFFIX_MATCH_BINDINGS',
-    '-DDISABLE_NETMASK_BINDINGS',
-    '-DDISABLE_DNSNAME_BINDINGS',
-    '-DDISABLE_DNSHEADER_BINDINGS',
-    '-DDISABLE_RECVMMSG',
-    '-DDISABLE_WEB_CACHE_MANAGEMENT',
-    '-DDISABLE_WEB_CONFIG',
-    '-DDISABLE_RULES_ALTERING_QUERIES',
-    '-DDISABLE_ECS_ACTIONS',
-    '-DDISABLE_TOP_N_BINDINGS',
-    '-DDISABLE_OCSP_STAPLING',
-    '-DDISABLE_HASHED_CREDENTIALS',
-    '-DDISABLE_FALSE_SHARING_PADDING',
-    '-DDISABLE_NPN'])
+
+DNSDIST_CONFIGURE_CXXFLAGS_LEAST = " ".join(
+    [
+        "-DDISABLE_COMPLETION",
+        "-DDISABLE_DELAY_PIPE",
+        "-DDISABLE_DYNBLOCKS",
+        "-DDISABLE_PROMETHEUS",
+        "-DDISABLE_PROTOBUF",
+        "-DDISABLE_BUILTIN_HTML",
+        "-DDISABLE_CARBON",
+        "-DDISABLE_SECPOLL",
+        "-DDISABLE_DEPRECATED_DYNBLOCK",
+        "-DDISABLE_LUA_WEB_HANDLERS",
+        "-DDISABLE_NON_FFI_DQ_BINDINGS",
+        "-DDISABLE_POLICIES_BINDINGS",
+        "-DDISABLE_PACKETCACHE_BINDINGS",
+        "-DDISABLE_DOWNSTREAM_BINDINGS",
+        "-DDISABLE_COMBO_ADDR_BINDINGS",
+        "-DDISABLE_CLIENT_STATE_BINDINGS",
+        "-DDISABLE_QPS_LIMITER_BINDINGS",
+        "-DDISABLE_SUFFIX_MATCH_BINDINGS",
+        "-DDISABLE_NETMASK_BINDINGS",
+        "-DDISABLE_DNSNAME_BINDINGS",
+        "-DDISABLE_DNSHEADER_BINDINGS",
+        "-DDISABLE_RECVMMSG",
+        "-DDISABLE_WEB_CACHE_MANAGEMENT",
+        "-DDISABLE_WEB_CONFIG",
+        "-DDISABLE_RULES_ALTERING_QUERIES",
+        "-DDISABLE_ECS_ACTIONS",
+        "-DDISABLE_TOP_N_BINDINGS",
+        "-DDISABLE_OCSP_STAPLING",
+        "-DDISABLE_HASHED_CREDENTIALS",
+        "-DDISABLE_FALSE_SHARING_PADDING",
+        "-DDISABLE_NPN",
+    ]
+)
+
 
 @task
 def ci_dnsdist_configure(c, features, builder, build_dir):
-    additional_flags = ''
-    additional_ld_flags = ''
+    additional_flags = ""
+    additional_ld_flags = ""
     if is_compiler_clang():
-        additional_ld_flags += '-fuse-ld=lld '
+        additional_ld_flags += "-fuse-ld=lld "
 
-    if features == 'least':
+    if features == "least":
         additional_flags = DNSDIST_CONFIGURE_CXXFLAGS_LEAST
 
-    if builder == 'meson':
+    if builder == "meson":
         cmd = ci_dnsdist_configure_meson(c, features, additional_flags, additional_ld_flags, build_dir)
-        logfile = 'meson-logs/meson-log.txt'
+        logfile = "meson-logs/meson-log.txt"
     else:
         cmd = ci_dnsdist_configure_autotools(features, additional_flags, additional_ld_flags, build_dir)
-        logfile = 'config.log'
+        logfile = "config.log"
 
     res = c.run(cmd, warn=True)
     if res.exited != 0:
-        c.run(f'cat {logfile}')
+        c.run(f"cat {logfile}")
         raise UnexpectedExit(res)
 
+
 def ci_dnsdist_configure_autotools(features, additional_flags, additional_ld_flags, build_dir):
-    if features == 'full':
-      features_set = '--enable-dnstap \
+    if features == "full":
+        features_set = "--enable-dnstap \
                       --enable-dnscrypt \
                       --enable-dns-over-tls \
                       --enable-dns-over-https \
@@ -925,9 +1057,9 @@ def ci_dnsdist_configure_autotools(features, additional_flags, additional_ld_fla
                       --with-libcap \
                       --with-net-snmp \
                       --with-nghttp2 \
-                      --with-re2'
+                      --with-re2"
     else:
-      features_set = '--disable-dnstap \
+        features_set = "--disable-dnstap \
                       --disable-dnscrypt \
                       --disable-ipcipher \
                       --disable-ipcrypt2 \
@@ -940,177 +1072,212 @@ def ci_dnsdist_configure_autotools(features, additional_flags, additional_ld_fla
                       --without-lmdb \
                       --without-net-snmp \
                       --without-nghttp2 \
-                      --without-re2'
+                      --without-re2"
     unittests = get_unit_tests()
     fuzztargets = get_fuzzing_targets()
-    tools = f'''AR=llvm-ar-{clang_version} RANLIB=llvm-ranlib-{clang_version}''' if is_compiler_clang() else ''
-    out_of_tree_build = build_dir != ''
-    return " ".join([
-        tools,
-        get_base_configure_cmd(additional_c_flags='', additional_cxx_flags=additional_flags, additional_ld_flags=additional_ld_flags, enable_systemd=False, enable_sodium=False, out_of_tree_build=out_of_tree_build),
-        features_set,
-        unittests,
-        fuzztargets,
-        '--enable-lto=thin',
-        '--prefix=/opt/dnsdist'
-    ])
-
-DNSDIST_CONFIGURE_MESON_FEATURE_SET_FULL = " ".join([
-    '-D cdb=enabled',
-    '-D dnscrypt=enabled',
-    '-D dnstap=enabled',
-    '-D ebpf=enabled',
-    '-D ipcipher=enabled',
-    '-D ipcrypt2=enabled',
-    '-D libedit=enabled',
-    '-D libsodium=enabled',
-    '-D lmdb=enabled',
-    '-D nghttp2=enabled',
-    '-D re2=enabled',
-    '-D systemd-service=enabled',
-    '-D tls-gnutls=enabled',
-    '-D dns-over-https=enabled',
-    '-D dns-over-http3=enabled',
-    '-D dns-over-quic=enabled',
-    '-D dns-over-tls=enabled',
-    '-D reproducible=true',
-    '-D snmp=enabled',
-    '-D yaml=enabled'])
-
-DNSDIST_CONFIGURE_MESON_FEATURE_SET_LEAST = " ".join([
-    '-D cdb=disabled',
-    '-D dnscrypt=disabled',
-    '-D dnstap=disabled',
-    '-D ebpf=disabled',
-    '-D ipcipher=disabled',
-    '-D ipcrypt2=disabled',
-    '-D libedit=disabled',
-    '-D libsodium=disabled',
-    '-D lmdb=disabled',
-    '-D nghttp2=disabled',
-    '-D re2=disabled',
-    '-D systemd-service=disabled',
-    '-D tls-gnutls=disabled',
-    '-D dns-over-https=disabled',
-    '-D dns-over-http3=disabled',
-    '-D dns-over-quic=disabled',
-    '-D dns-over-tls=disabled',
-    '-D reproducible=false',
-    '-D snmp=disabled',
-    '-D yaml=disabled'])
+    tools = f"""AR=llvm-ar-{clang_version} RANLIB=llvm-ranlib-{clang_version}""" if is_compiler_clang() else ""
+    out_of_tree_build = build_dir != ""
+    return " ".join(
+        [
+            tools,
+            get_base_configure_cmd(
+                additional_c_flags="",
+                additional_cxx_flags=additional_flags,
+                additional_ld_flags=additional_ld_flags,
+                enable_systemd=False,
+                enable_sodium=False,
+                out_of_tree_build=out_of_tree_build,
+            ),
+            features_set,
+            unittests,
+            fuzztargets,
+            "--enable-lto=thin",
+            "--prefix=/opt/dnsdist",
+        ]
+    )
+
+
+DNSDIST_CONFIGURE_MESON_FEATURE_SET_FULL = " ".join(
+    [
+        "-D cdb=enabled",
+        "-D dnscrypt=enabled",
+        "-D dnstap=enabled",
+        "-D ebpf=enabled",
+        "-D ipcipher=enabled",
+        "-D ipcrypt2=enabled",
+        "-D libedit=enabled",
+        "-D libsodium=enabled",
+        "-D lmdb=enabled",
+        "-D nghttp2=enabled",
+        "-D re2=enabled",
+        "-D systemd-service=enabled",
+        "-D tls-gnutls=enabled",
+        "-D dns-over-https=enabled",
+        "-D dns-over-http3=enabled",
+        "-D dns-over-quic=enabled",
+        "-D dns-over-tls=enabled",
+        "-D reproducible=true",
+        "-D snmp=enabled",
+        "-D yaml=enabled",
+    ]
+)
+
+DNSDIST_CONFIGURE_MESON_FEATURE_SET_LEAST = " ".join(
+    [
+        "-D cdb=disabled",
+        "-D dnscrypt=disabled",
+        "-D dnstap=disabled",
+        "-D ebpf=disabled",
+        "-D ipcipher=disabled",
+        "-D ipcrypt2=disabled",
+        "-D libedit=disabled",
+        "-D libsodium=disabled",
+        "-D lmdb=disabled",
+        "-D nghttp2=disabled",
+        "-D re2=disabled",
+        "-D systemd-service=disabled",
+        "-D tls-gnutls=disabled",
+        "-D dns-over-https=disabled",
+        "-D dns-over-http3=disabled",
+        "-D dns-over-quic=disabled",
+        "-D dns-over-tls=disabled",
+        "-D reproducible=false",
+        "-D snmp=disabled",
+        "-D yaml=disabled",
+    ]
+)
+
 
 def ci_dnsdist_configure_meson(c, features, additional_flags, additional_ld_flags, build_dir):
-    if features == 'full':
-      features_set = DNSDIST_CONFIGURE_MESON_FEATURE_SET_FULL
+    if features == "full":
+        features_set = DNSDIST_CONFIGURE_MESON_FEATURE_SET_FULL
     else:
-      features_set = DNSDIST_CONFIGURE_MESON_FEATURE_SET_LEAST
+        features_set = DNSDIST_CONFIGURE_MESON_FEATURE_SET_LEAST
     unittests = get_unit_tests(meson=True)
     fuzztargets = get_fuzzing_targets(meson=True)
-    tools = f'''AR=llvm-ar-{clang_version} RANLIB=llvm-ranlib-{clang_version}''' if is_compiler_clang() else ''
+    tools = f"""AR=llvm-ar-{clang_version} RANLIB=llvm-ranlib-{clang_version}""" if is_compiler_clang() else ""
     cflags = " ".join([get_cflags()])
     cxxflags = " ".join([get_cxxflags(), additional_flags])
-    env = " ".join([
-        tools,
-        f'CFLAGS="{cflags}"',
-        f'LDFLAGS="{additional_ld_flags}"',
-        f'CXXFLAGS="{cxxflags}"',
-        f"CC='{get_c_compiler()}'",
-        f"CXX='{get_cxx_compiler()}'",
-    ])
-
-    builder_version = os.getenv('BUILDER_VERSION')
-    dist_dir = '/tmp/dnsdist-meson-dist-build'
-
-    c.run(f'. {repo_home}/.venv/bin/activate && meson setup {dist_dir} && meson dist -C {dist_dir} --no-tests')
-    with c.cd(f'{dist_dir}/meson-dist/'):
-        c.run(f'tar xf dnsdist-{builder_version}.tar.xz')
-
-    src_dir = f'{dist_dir}/meson-dist/dnsdist-{builder_version}'
-    return " ".join([
-        f'. {repo_home}/.venv/bin/activate && {env} meson setup {build_dir} {src_dir}',
-        features_set,
-        unittests,
-        fuzztargets,
-        "-D hardening-fortify-source=auto",
-        "-D auto-var-init=pattern",
-        get_coverage(meson=True),
-        get_sanitizers(meson=True)
-    ])
-
-@task(help={
-    'features': 'What feature-set to build, one of "full" or "least"',
-    'build_dir': 'Where Meson should configure into',
-    'clang': 'Use clang instead of GCC',
-    'ccache': 'Use ccache',
-    'unit_tests': 'Enable unit tests',
-    'coverage': 'Create code coverage files',
-})
-def dev_dnsdist_configure_meson(c, features, build_dir="build", clang=False, ccache=False, unit_tests=False, coverage=False):
-    '''
+    env = " ".join(
+        [
+            tools,
+            f'CFLAGS="{cflags}"',
+            f'LDFLAGS="{additional_ld_flags}"',
+            f'CXXFLAGS="{cxxflags}"',
+            f"CC='{get_c_compiler()}'",
+            f"CXX='{get_cxx_compiler()}'",
+        ]
+    )
+
+    builder_version = os.getenv("BUILDER_VERSION")
+    dist_dir = "/tmp/dnsdist-meson-dist-build"
+
+    c.run(f". {repo_home}/.venv/bin/activate && meson setup {dist_dir} && meson dist -C {dist_dir} --no-tests")
+    with c.cd(f"{dist_dir}/meson-dist/"):
+        c.run(f"tar xf dnsdist-{builder_version}.tar.xz")
+
+    src_dir = f"{dist_dir}/meson-dist/dnsdist-{builder_version}"
+    return " ".join(
+        [
+            f". {repo_home}/.venv/bin/activate && {env} meson setup {build_dir} {src_dir}",
+            features_set,
+            unittests,
+            fuzztargets,
+            "-D hardening-fortify-source=auto",
+            "-D auto-var-init=pattern",
+            get_coverage(meson=True),
+            get_sanitizers(meson=True),
+        ]
+    )
+
+
+@task(
+    help={
+        "features": 'What feature-set to build, one of "full" or "least"',
+        "build_dir": "Where Meson should configure into",
+        "clang": "Use clang instead of GCC",
+        "ccache": "Use ccache",
+        "unit_tests": "Enable unit tests",
+        "coverage": "Create code coverage files",
+    }
+)
+def dev_dnsdist_configure_meson(
+    c, features, build_dir="build", clang=False, ccache=False, unit_tests=False, coverage=False
+):
+    """
     Configures dnsdist using Meson.
-    '''
-    additional_ld_flags = ''
-    unittests=''
-    cc = 'gcc'
-    cxx = 'g++'
+    """
+    additional_ld_flags = ""
+    unittests = ""
+    cc = "gcc"
+    cxx = "g++"
     if clang:
-        additional_ld_flags += '-fuse-ld=lld '
-        cc = 'clang'
-        cxx = 'clang++'
+        additional_ld_flags += "-fuse-ld=lld "
+        cc = "clang"
+        cxx = "clang++"
 
-    os.environ['COMPILER'] = cc
+    os.environ["COMPILER"] = cc
 
     if ccache:
-        cc = f'ccache {cc}'
-        cxx = f'ccache {cxx}'
+        cc = f"ccache {cc}"
+        cxx = f"ccache {cxx}"
     if unit_tests:
-        unittests = '-D unit-tests=true'
-
+        unittests = "-D unit-tests=true"
 
     cflags = " ".join([get_cflags()])
     cxxflags = " ".join([get_cxxflags()])
 
-    if features == 'full':
-      features_set = DNSDIST_CONFIGURE_MESON_FEATURE_SET_FULL
+    if features == "full":
+        features_set = DNSDIST_CONFIGURE_MESON_FEATURE_SET_FULL
     elif features == "least":
-      features_set = DNSDIST_CONFIGURE_MESON_FEATURE_SET_LEAST
-      cxxflags = " ".join([cxxflags, DNSDIST_CONFIGURE_CXXFLAGS_LEAST])
+        features_set = DNSDIST_CONFIGURE_MESON_FEATURE_SET_LEAST
+        cxxflags = " ".join([cxxflags, DNSDIST_CONFIGURE_CXXFLAGS_LEAST])
     else:
         raise KeyError(f'features should be one of "full", "least", not "{features}"')
 
     if coverage:
-        os.environ['COVERAGE'] = 'yes'
+        os.environ["COVERAGE"] = "yes"
 
     reconf_opt = "--reconfigure" if os.path.exists(build_dir) else ""
 
-    env = " ".join([
-        f"CC='{cc}'",
-        f"CXX='{cxx}'",
-        f'CFLAGS="{cflags}"',
-        f'LDFLAGS="{additional_ld_flags}"',
-        f'CXXFLAGS="{cxxflags}"',
-    ])
-    c.run(" ".join([
-        f'{env} meson setup {build_dir}',
-        reconf_opt,
-        features_set,
-        unittests,
-        "-D hardening-fortify-source=auto",
-        "-D auto-var-init=pattern",
-        get_coverage(meson=True),
-        get_sanitizers(meson=True)
-    ]))
+    env = " ".join(
+        [
+            f"CC='{cc}'",
+            f"CXX='{cxx}'",
+            f'CFLAGS="{cflags}"',
+            f'LDFLAGS="{additional_ld_flags}"',
+            f'CXXFLAGS="{cxxflags}"',
+        ]
+    )
+    c.run(
+        " ".join(
+            [
+                f"{env} meson setup {build_dir}",
+                reconf_opt,
+                features_set,
+                unittests,
+                "-D hardening-fortify-source=auto",
+                "-D auto-var-init=pattern",
+                get_coverage(meson=True),
+                get_sanitizers(meson=True),
+            ]
+        )
+    )
+
 
 @task
 def ci_auth_make(c):
-    c.run(f'make -j{get_build_concurrency()} -k V=1')
+    c.run(f"make -j{get_build_concurrency()} -k V=1")
+
 
 @task
 def ci_auth_make_bear(c):
-    c.run(f'bear --append -- make -j{get_build_concurrency()} -k V=1')
+    c.run(f"bear --append -- make -j{get_build_concurrency()} -k V=1")
+
 
 def run_ninja(c):
-    c.run(f'ninja -j{get_build_concurrency()} --verbose')
+    c.run(f"ninja -j{get_build_concurrency()} --verbose")
+
 
 @task
 def ci_auth_build(c, meson=False):
@@ -1119,10 +1286,12 @@ def ci_auth_build(c, meson=False):
     else:
         ci_auth_make_bear(c)
 
+
 @task
 def ci_rec_make_bear(c):
     # Assumed to be running under ./pdns/recursordist/
-    c.run(f'bear --append -- make -j{get_build_concurrency()} -k V=1')
+    c.run(f"bear --append -- make -j{get_build_concurrency()} -k V=1")
+
 
 @task
 def ci_rec_build(c, meson=False):
@@ -1131,210 +1300,223 @@ def ci_rec_build(c, meson=False):
     else:
         ci_rec_make_bear(c)
 
+
 @task
 def ci_dnsdist_make(c):
-    c.run(f'make -j{get_build_concurrency(4)} -k V=1')
+    c.run(f"make -j{get_build_concurrency(4)} -k V=1")
+
 
 def ci_dnsdist_run_ninja(c):
-    c.run(f'. {repo_home}/.venv/bin/activate && ninja -j{get_build_concurrency(4)} --verbose')
+    c.run(f". {repo_home}/.venv/bin/activate && ninja -j{get_build_concurrency(4)} --verbose")
+
 
 @task
 def ci_dnsdist_make_bear(c, builder):
-    if builder == 'meson':
+    if builder == "meson":
         ci_dnsdist_run_ninja(c)
         return
 
     # Assumed to be running under ./pdns/dnsdistdist/
-    c.run(f'bear --append -- make -j{get_build_concurrency(4)} -k V=1')
+    c.run(f"bear --append -- make -j{get_build_concurrency(4)} -k V=1")
+
 
 @task
 def ci_auth_install_remotebackend_test_deps(c):
-    c.sudo('apt-get install -y socat')
+    c.sudo("apt-get install -y socat")
+
 
 @task
 def ci_auth_run_unit_tests(c, meson=False):
     if meson:
         suite_timeout_sec = 120
-        logfile = 'meson-logs/testlog.txt'
-        c.run(f'touch {repo_home}/regression-tests/tests/verify-dnssec-zone/allow-missing {repo_home}/regression-tests.nobackend/rectify-axfr/allow-missing') # FIXME: can this go?
-        res = c.run(f'meson test --verbose -t {suite_timeout_sec}', warn=True)
+        logfile = "meson-logs/testlog.txt"
+        c.run(
+            f"touch {repo_home}/regression-tests/tests/verify-dnssec-zone/allow-missing {repo_home}/regression-tests.nobackend/rectify-axfr/allow-missing"
+        )  # FIXME: can this go?
+        res = c.run(f"meson test --verbose -t {suite_timeout_sec}", warn=True)
     else:
-        logfile = 'pdns/test-suite.log'
-        res = c.run('make check', warn=True)
+        logfile = "pdns/test-suite.log"
+        res = c.run("make check", warn=True)
     if res.exited != 0:
-        c.run(f'cat {logfile}', warn=True)
-        c.run('cat ../modules/remotebackend/*.log', warn=True)
+        c.run(f"cat {logfile}", warn=True)
+        c.run("cat ../modules/remotebackend/*.log", warn=True)
         raise UnexpectedExit(res)
 
+
 @task
 def ci_rec_run_unit_tests(c, meson=False):
     if meson:
         suite_timeout_sec = 120
-        logfile = 'meson-logs/testlog.txt'
-        res = c.run(f'meson test --verbose -t {suite_timeout_sec}', warn=True)
+        logfile = "meson-logs/testlog.txt"
+        res = c.run(f"meson test --verbose -t {suite_timeout_sec}", warn=True)
     else:
-        logfile = 'test-suite.log'
-        res = c.run('make check', warn=True)
+        logfile = "test-suite.log"
+        res = c.run("make check", warn=True)
     if res.exited != 0:
-        c.run(f'cat {logfile}', warn=True)
+        c.run(f"cat {logfile}", warn=True)
         raise UnexpectedExit(res)
 
+
 @task
 def ci_dnsdist_run_unit_tests(c, builder):
-    if builder == 'meson':
+    if builder == "meson":
         suite_timeout_sec = 120
-        logfile = 'meson-logs/testlog.txt'
-        res = c.run(f'. {repo_home}/.venv/bin/activate && meson test --verbose -t {suite_timeout_sec}', warn=True)
+        logfile = "meson-logs/testlog.txt"
+        res = c.run(f". {repo_home}/.venv/bin/activate && meson test --verbose -t {suite_timeout_sec}", warn=True)
     else:
-        logfile = 'test-suite.log'
-        res = c.run('make check', warn=True)
+        logfile = "test-suite.log"
+        res = c.run("make check", warn=True)
     if res.exited != 0:
-      c.run(f'cat {logfile}', warn=True)
-      raise UnexpectedExit(res)
+        c.run(f"cat {logfile}", warn=True)
+        raise UnexpectedExit(res)
+
 
 @task
 def ci_make_distdir(c, meson=False):
     if not meson:
-        c.run('make distdir')
+        c.run("make distdir")
+
 
 @task
 def ci_auth_install(c, meson=False):
     if not meson:
-        c.run('make install') # FIXME: this builds auth docs - again
+        c.run("make install")  # FIXME: this builds auth docs - again
+
 
 @task
 def ci_rec_install(c, meson=False):
     if meson:
         c.sudo(f"bash -c 'source {repo_home}/.venv/bin/activate && meson install'")
     else:
-        c.run('make install')
+        c.run("make install")
+
 
 @task
 def ci_dnsdist_install(c, meson=False):
     if meson:
         c.sudo(f"bash -c 'source {repo_home}/.venv/bin/activate && meson install'")
     else:
-        c.run('make install')
+        c.run("make install")
+
 
 @task
 def add_auth_repo(c, dist_name, dist_release_name, pdns_repo_version):
-    c.sudo('apt-get install -y curl gnupg2')
-    if pdns_repo_version == 'master':
-        c.sudo('curl -s -o /etc/apt/trusted.gpg.d/pdns-repo.asc https://repo.powerdns.com/CBC8B383-pub.asc')
+    c.sudo("apt-get install -y curl gnupg2")
+    if pdns_repo_version == "master":
+        c.sudo("curl -s -o /etc/apt/trusted.gpg.d/pdns-repo.asc https://repo.powerdns.com/CBC8B383-pub.asc")
     else:
-        c.sudo('curl -s -o /etc/apt/trusted.gpg.d/pdns-repo.asc https://repo.powerdns.com/FD380FBB-pub.asc')
-    c.run(f"echo 'deb [arch=amd64] http://repo.powerdns.com/{dist_name} {dist_release_name}-auth-{pdns_repo_version} main' | sudo tee /etc/apt/sources.list.d/pdns.list")
+        c.sudo("curl -s -o /etc/apt/trusted.gpg.d/pdns-repo.asc https://repo.powerdns.com/FD380FBB-pub.asc")
+    c.run(
+        f"echo 'deb [arch=amd64] http://repo.powerdns.com/{dist_name} {dist_release_name}-auth-{pdns_repo_version} main' | sudo tee /etc/apt/sources.list.d/pdns.list"
+    )
     c.run("echo 'Package: pdns-*' | sudo tee /etc/apt/preferences.d/pdns")
     c.run("echo 'Pin: origin repo.powerdns.com' | sudo tee -a /etc/apt/preferences.d/pdns")
     c.run("echo 'Pin-Priority: 600' | sudo tee -a /etc/apt/preferences.d/pdns")
-    c.sudo('apt-get update')
+    c.sudo("apt-get update")
+
 
 @task
-def test_api(c, product, backend=''):
-    if product == 'recursor':
-        with c.cd('regression-tests.api'):
-            c.run(f'PDNSRECURSOR=/opt/pdns-recursor/sbin/pdns_recursor ./runtests recursor {backend}')
-    elif product == 'auth':
-        with c.cd('regression-tests.api'):
-            c.run(f'PDNSSERVER=/opt/pdns-auth/sbin/pdns_server PDNSUTIL=/opt/pdns-auth/bin/pdnsutil SDIG=/opt/pdns-auth/bin/sdig MYSQL_HOST={auth_backend_ip_addr} PGHOST={auth_backend_ip_addr} PGPORT=5432 ./runtests authoritative {backend}')
+def test_api(c, product, backend=""):
+    if product == "recursor":
+        with c.cd("regression-tests.api"):
+            c.run(f"PDNSRECURSOR=/opt/pdns-recursor/sbin/pdns_recursor ./runtests recursor {backend}")
+    elif product == "auth":
+        with c.cd("regression-tests.api"):
+            c.run(
+                f"PDNSSERVER=/opt/pdns-auth/sbin/pdns_server PDNSUTIL=/opt/pdns-auth/bin/pdnsutil SDIG=/opt/pdns-auth/bin/sdig MYSQL_HOST={auth_backend_ip_addr} PGHOST={auth_backend_ip_addr} PGPORT=5432 ./runtests authoritative {backend}"
+            )
     else:
-        raise Failure('unknown product')
+        raise Failure("unknown product")
+
 
 backend_regress_tests = dict(
-    bind = [
-        'bind-both',
-        'bind-dnssec-both',
-        'bind-dnssec-nsec3-both',
-        'bind-dnssec-nsec3-optout-both',
-        'bind-dnssec-nsec3-narrow',
-        'bind-dnssec-pkcs11'
-    ],
-    geoip = [
-        'geoip',
-        'geoip-nsec3-narrow'
+    bind=[
+        "bind-both",
+        "bind-dnssec-both",
+        "bind-dnssec-nsec3-both",
+        "bind-dnssec-nsec3-optout-both",
+        "bind-dnssec-nsec3-narrow",
+        "bind-dnssec-pkcs11",
     ],
-    lua2 = ['lua2', 'lua2-dnssec'],
-    tinydns = ['tinydns'],
-    remote = [
-        'remotebackend-pipe',
-        'remotebackend-unix',
-        'remotebackend-http',
-        'remotebackend-zeromq',
-        'remotebackend-pipe-dnssec',
-        'remotebackend-unix-dnssec',
-        'remotebackend-http-dnssec',
-        'remotebackend-zeromq-dnssec'
+    geoip=["geoip", "geoip-nsec3-narrow"],
+    lua2=["lua2", "lua2-dnssec"],
+    tinydns=["tinydns"],
+    remote=[
+        "remotebackend-pipe",
+        "remotebackend-unix",
+        "remotebackend-http",
+        "remotebackend-zeromq",
+        "remotebackend-pipe-dnssec",
+        "remotebackend-unix-dnssec",
+        "remotebackend-http-dnssec",
+        "remotebackend-zeromq-dnssec",
     ],
-    lmdb = [
-        'lmdb-nodnssec-both',
-        'lmdb-both',
-        'lmdb-nsec3-both',
-        'lmdb-nsec3-optout-both',
-        'lmdb-nsec3-narrow',
-        'lmdb-nodnssec-variant',
-        'lmdb-variant',
-        'lmdb-nsec3-variant',
-        'lmdb-nsec3-optout-variant',
-        'lmdb-nsec3-narrow-variant'
+    lmdb=[
+        "lmdb-nodnssec-both",
+        "lmdb-both",
+        "lmdb-nsec3-both",
+        "lmdb-nsec3-optout-both",
+        "lmdb-nsec3-narrow",
+        "lmdb-nodnssec-variant",
+        "lmdb-variant",
+        "lmdb-nsec3-variant",
+        "lmdb-nsec3-optout-variant",
+        "lmdb-nsec3-narrow-variant",
     ],
-    gmysql = [
-        'gmysql',
-        'gmysql-nodnssec-both',
-        'gmysql-nsec3-both',
-        'gmysql-nsec3-optout-both',
-        'gmysql-nsec3-narrow',
-        'gmysql_sp-both'
-    ],
-    gpgsql = [
-        'gpgsql',
-        'gpgsql-nodnssec-both',
-        'gpgsql-nsec3-both',
-        'gpgsql-nsec3-optout-both',
-        'gpgsql-nsec3-narrow',
-        'gpgsql_sp-both'
+    gmysql=[
+        "gmysql",
+        "gmysql-nodnssec-both",
+        "gmysql-nsec3-both",
+        "gmysql-nsec3-optout-both",
+        "gmysql-nsec3-narrow",
+        "gmysql_sp-both",
     ],
-    gsqlite3 = [
-        'gsqlite3',
-        'gsqlite3-nodnssec-both',
-        'gsqlite3-nsec3-both',
-        'gsqlite3-nsec3-optout-both',
-        'gsqlite3-nsec3-narrow'
+    gpgsql=[
+        "gpgsql",
+        "gpgsql-nodnssec-both",
+        "gpgsql-nsec3-both",
+        "gpgsql-nsec3-optout-both",
+        "gpgsql-nsec3-narrow",
+        "gpgsql_sp-both",
     ],
-    godbc_sqlite3 = ['godbc_sqlite3-nodnssec'],
-    godbc_mssql = [
-        'godbc_mssql',
-        'godbc_mssql-nodnssec',
-        'godbc_mssql-nsec3',
-        'godbc_mssql-nsec3-optout',
-        'godbc_mssql-nsec3-narrow'
+    gsqlite3=[
+        "gsqlite3",
+        "gsqlite3-nodnssec-both",
+        "gsqlite3-nsec3-both",
+        "gsqlite3-nsec3-optout-both",
+        "gsqlite3-nsec3-narrow",
     ],
-    ldap = [
-        'ldap-tree',
-        'ldap-simple',
-        'ldap-strict'
+    godbc_sqlite3=["godbc_sqlite3-nodnssec"],
+    godbc_mssql=[
+        "godbc_mssql",
+        "godbc_mssql-nodnssec",
+        "godbc_mssql-nsec3",
+        "godbc_mssql-nsec3-optout",
+        "godbc_mssql-nsec3-narrow",
     ],
-    geoip_mmdb = ['geoip'],
+    ldap=["ldap-tree", "ldap-simple", "ldap-strict"],
+    geoip_mmdb=["geoip"],
 )
 
 backend_rootzone_tests = dict(
-    geoip = False,
-    geoip_mmdb = False,
-    lua2 = False,
-    ldap = False,
-    tinydns = False,
-    remote = False,
-    bind = True,
-    lmdb = True,
-    gmysql = True,
-    gpgsql = True,
-    gsqlite3 = True,
-    godbc_sqlite3 = True,
-    godbc_mssql = True,
+    geoip=False,
+    geoip_mmdb=False,
+    lua2=False,
+    ldap=False,
+    tinydns=False,
+    remote=False,
+    bind=True,
+    lmdb=True,
+    gmysql=True,
+    gpgsql=True,
+    gsqlite3=True,
+    godbc_sqlite3=True,
+    godbc_mssql=True,
 )
 
 godbc_mssql_credentials = {"username": "sa", "password": "SAsa12%%-not-a-secret-password"}
 
-godbc_config = f'''
+godbc_config = f"""
 [pdns-mssql-docker]
 Driver=FreeTDS
 Trace=No
@@ -1357,188 +1539,224 @@ Database = pdns.sqlite3
 [pdns-sqlite3-2]
 Driver = SQLite3
 Database = pdns.sqlite32
-'''
+"""
+
 
 def setup_godbc_mssql(c):
     with open(os.path.expanduser("~/.odbc.ini"), "a") as f:
         f.write(godbc_config)
-    c.sudo('sh -c \'echo "Threading=1" | cat /usr/share/tdsodbc/odbcinst.ini - | tee -a /etc/odbcinst.ini\'')
+    c.sudo("sh -c 'echo \"Threading=1\" | cat /usr/share/tdsodbc/odbcinst.ini - | tee -a /etc/odbcinst.ini'")
     c.sudo('sed -i "s/libtdsodbc.so/\/usr\/lib\/x86_64-linux-gnu\/odbc\/libtdsodbc.so/g" /etc/odbcinst.ini')
-    c.run(f'echo "create database pdns" | isql -v pdns-mssql-docker-nodb {godbc_mssql_credentials["username"]} {godbc_mssql_credentials["password"]}')
+    c.run(
+        f'echo "create database pdns" | isql -v pdns-mssql-docker-nodb {godbc_mssql_credentials["username"]} {godbc_mssql_credentials["password"]}'
+    )
     # FIXME: Skip 8bit-txt-unescaped test
-    c.run('touch ${PWD}/regression-tests/tests/8bit-txt-unescaped/skip')
+    c.run("touch ${PWD}/regression-tests/tests/8bit-txt-unescaped/skip")
+
 
 def setup_godbc_sqlite3(c):
     with open(os.path.expanduser("~/.odbc.ini"), "a") as f:
         f.write(godbc_config)
     c.sudo('sed -i "s/libsqlite3odbc.so/\/usr\/lib\/x86_64-linux-gnu\/odbc\/libsqlite3odbc.so/g" /etc/odbcinst.ini')
 
+
 def setup_ldap_client(c):
-    c.sudo('DEBIAN_FRONTEND=noninteractive apt-get install -y ldap-utils')
-    c.sudo(f'sh -c \'echo "{auth_backend_ip_addr} ldapserver" | tee -a /etc/hosts\'')
+    c.sudo("DEBIAN_FRONTEND=noninteractive apt-get install -y ldap-utils")
+    c.sudo(f"sh -c 'echo \"{auth_backend_ip_addr} ldapserver\" | tee -a /etc/hosts'")
+
 
 def setup_softhsm(c):
     # Modify the location of the softhsm tokens and configuration directory.
     # Enables token generation by non-root users (runner)
-    c.run('mkdir -p /opt/pdns-auth/softhsm/tokens')
+    c.run("mkdir -p /opt/pdns-auth/softhsm/tokens")
     c.run('echo "directories.tokendir = /opt/pdns-auth/softhsm/tokens" > /opt/pdns-auth/softhsm/softhsm2.conf')
 
+
 @task
 def test_auth_backend(c, backend):
-    pdns_auth_env_vars = f'PDNS=/opt/pdns-auth/sbin/pdns_server PDNS2=/opt/pdns-auth/sbin/pdns_server SDIG=/opt/pdns-auth/bin/sdig NOTIFY=/opt/pdns-auth/bin/pdns_notify NSEC3DIG=/opt/pdns-auth/bin/nsec3dig SAXFR=/opt/pdns-auth/bin/saxfr ZONE2SQL=/opt/pdns-auth/bin/zone2sql ZONE2LDAP=/opt/pdns-auth/bin/zone2ldap ZONE2JSON=/opt/pdns-auth/bin/zone2json PDNSUTIL=/opt/pdns-auth/bin/pdnsutil PDNSCONTROL=/opt/pdns-auth/bin/pdns_control PDNSSERVER=/opt/pdns-auth/sbin/pdns_server SDIG=/opt/pdns-auth/bin/sdig GMYSQLHOST={auth_backend_ip_addr} GMYSQL2HOST={auth_backend_ip_addr} MYSQL_HOST={auth_backend_ip_addr} PGHOST={auth_backend_ip_addr} PGPORT=5432'
-    backend_env_vars = ''
+    pdns_auth_env_vars = f"PDNS=/opt/pdns-auth/sbin/pdns_server PDNS2=/opt/pdns-auth/sbin/pdns_server SDIG=/opt/pdns-auth/bin/sdig NOTIFY=/opt/pdns-auth/bin/pdns_notify NSEC3DIG=/opt/pdns-auth/bin/nsec3dig SAXFR=/opt/pdns-auth/bin/saxfr ZONE2SQL=/opt/pdns-auth/bin/zone2sql ZONE2LDAP=/opt/pdns-auth/bin/zone2ldap ZONE2JSON=/opt/pdns-auth/bin/zone2json PDNSUTIL=/opt/pdns-auth/bin/pdnsutil PDNSCONTROL=/opt/pdns-auth/bin/pdns_control PDNSSERVER=/opt/pdns-auth/sbin/pdns_server SDIG=/opt/pdns-auth/bin/sdig GMYSQLHOST={auth_backend_ip_addr} GMYSQL2HOST={auth_backend_ip_addr} MYSQL_HOST={auth_backend_ip_addr} PGHOST={auth_backend_ip_addr} PGPORT=5432"
+    backend_env_vars = ""
 
-    if backend == 'remote':
+    if backend == "remote":
         ci_auth_install_remotebackend_test_deps(c)
 
-    if backend == 'authpy':
-        c.sudo(f'sh -c \'echo "{auth_backend_ip_addr} kerberos-server" | tee -a /etc/hosts\'')
-        for auth_backend in ('bind', 'lmdb'):
-            with c.cd('regression-tests.auth-py'):
-                c.run(f'{pdns_auth_env_vars} AUTH_BACKEND={auth_backend} WITHKERBEROS=YES ./runtests')
+    if backend == "authpy":
+        c.sudo(f"sh -c 'echo \"{auth_backend_ip_addr} kerberos-server\" | tee -a /etc/hosts'")
+        for auth_backend in ("bind", "lmdb"):
+            with c.cd("regression-tests.auth-py"):
+                c.run(f"{pdns_auth_env_vars} AUTH_BACKEND={auth_backend} WITHKERBEROS=YES ./runtests")
         return
 
-    if backend == 'bind':
+    if backend == "bind":
         setup_softhsm(c)
-        backend_env_vars = 'SOFTHSM2_CONF=/opt/pdns-auth/softhsm/softhsm2.conf'
+        backend_env_vars = "SOFTHSM2_CONF=/opt/pdns-auth/softhsm/softhsm2.conf"
 
-    if backend == 'godbc_sqlite3':
+    if backend == "godbc_sqlite3":
         setup_godbc_sqlite3(c)
-        backend_env_vars = 'GODBC_SQLITE3_DSN=pdns-sqlite3-1'
+        backend_env_vars = "GODBC_SQLITE3_DSN=pdns-sqlite3-1"
 
-    if backend == 'godbc_mssql':
+    if backend == "godbc_mssql":
         setup_godbc_mssql(c)
-        backend_env_vars = f'GODBC_MSSQL_PASSWORD={godbc_mssql_credentials["password"]} GODBC_MSSQL_USERNAME={godbc_mssql_credentials["username"]} GODBC_MSSQL_DSN=pdns-mssql-docker GODBC_MSSQL2_PASSWORD={godbc_mssql_credentials["password"]} GODBC_MSSQL2_USERNAME={godbc_mssql_credentials["username"]} GODBC_MSSQL2_DSN=pdns-mssql-docker'
+        backend_env_vars = f"GODBC_MSSQL_PASSWORD={godbc_mssql_credentials['password']} GODBC_MSSQL_USERNAME={godbc_mssql_credentials['username']} GODBC_MSSQL_DSN=pdns-mssql-docker GODBC_MSSQL2_PASSWORD={godbc_mssql_credentials['password']} GODBC_MSSQL2_USERNAME={godbc_mssql_credentials['username']} GODBC_MSSQL2_DSN=pdns-mssql-docker"
 
-    if backend == 'ldap':
+    if backend == "ldap":
         setup_ldap_client(c)
 
-    if backend == 'geoip_mmdb':
-        backend_env_vars = 'geoipdatabase=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb'
+    if backend == "geoip_mmdb":
+        backend_env_vars = "geoipdatabase=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb"
 
-    with c.cd('regression-tests'):
-        if backend == 'lua2':
-            c.run('touch trustedkeys')  # avoid silly error during cleanup
+    with c.cd("regression-tests"):
+        if backend == "lua2":
+            c.run("touch trustedkeys")  # avoid silly error during cleanup
         for variant in backend_regress_tests[backend]:
-            c.run(f'{pdns_auth_env_vars} {backend_env_vars} ./start-test-stop 5300 {variant}')
+            c.run(f"{pdns_auth_env_vars} {backend_env_vars} ./start-test-stop 5300 {variant}")
 
     if backend_rootzone_tests[backend]:
-        with c.cd('regression-tests.rootzone'):
+        with c.cd("regression-tests.rootzone"):
             for variant in backend_regress_tests[backend]:
-                c.run(f'{pdns_auth_env_vars} {backend_env_vars} ./start-test-stop 5300 {variant}')
-
-    if backend == 'gsqlite3':
-        if os.getenv('SKIP_IPV6_TESTS'):
-            pdns_auth_env_vars += ' context=noipv6'
-        with c.cd('regression-tests.nobackend'):
-            c.run(f'{pdns_auth_env_vars} ./runtests')
-        c.run('/opt/pdns-auth/bin/pdnsutil test-algorithms')
+                c.run(f"{pdns_auth_env_vars} {backend_env_vars} ./start-test-stop 5300 {variant}")
+
+    if backend == "gsqlite3":
+        if os.getenv("SKIP_IPV6_TESTS"):
+            pdns_auth_env_vars += " context=noipv6"
+        with c.cd("regression-tests.nobackend"):
+            c.run(f"{pdns_auth_env_vars} ./runtests")
+        c.run("/opt/pdns-auth/bin/pdnsutil test-algorithms")
         return
 
+
 @task
 def test_ixfrdist(c):
-    with c.cd('regression-tests.ixfrdist'):
-        c.run('IXFRDISTBIN=/opt/pdns-auth/bin/ixfrdist ./runtests')
+    with c.cd("regression-tests.ixfrdist"):
+        c.run("IXFRDISTBIN=/opt/pdns-auth/bin/ixfrdist ./runtests")
+
 
-@task(optional=['skipXDP'])
+@task(optional=["skipXDP"])
 def test_dnsdist(c, skipXDP=False):
-    test_env_vars = 'ENABLE_SUDO_TESTS=1' if not skipXDP else ''
-    c.run('chmod +x /opt/dnsdist/bin/*')
-    c.run('ls -ald /var /var/agentx /var/agentx/master')
-    c.run('ls -al /var/agentx/master')
-    with c.cd('regression-tests.dnsdist'):
-        c.run(f'DNSDISTBIN=/opt/dnsdist/bin/dnsdist LD_LIBRARY_PATH=/opt/dnsdist/lib/ {test_env_vars} ./runtests')
+    test_env_vars = "ENABLE_SUDO_TESTS=1" if not skipXDP else ""
+    c.run("chmod +x /opt/dnsdist/bin/*")
+    c.run("ls -ald /var /var/agentx /var/agentx/master")
+    c.run("ls -al /var/agentx/master")
+    with c.cd("regression-tests.dnsdist"):
+        c.run(f"DNSDISTBIN=/opt/dnsdist/bin/dnsdist LD_LIBRARY_PATH=/opt/dnsdist/lib/ {test_env_vars} ./runtests")
+
 
 @task
 def test_regression_recursor(c):
-    c.run('/opt/pdns-recursor/sbin/pdns_recursor --version')
-    c.run('PDNSRECURSOR=/opt/pdns-recursor/sbin/pdns_recursor RECCONTROL=/opt/pdns-recursor/bin/rec_control ./build-scripts/test-recursor')
+    c.run("/opt/pdns-recursor/sbin/pdns_recursor --version")
+    c.run(
+        "PDNSRECURSOR=/opt/pdns-recursor/sbin/pdns_recursor RECCONTROL=/opt/pdns-recursor/bin/rec_control ./build-scripts/test-recursor"
+    )
+
 
 @task
 def test_bulk_recursor(c, size, threads, mthreads, shards, ipv6):
-    with c.cd('regression-tests'):
-        c.run('curl --no-progress-meter -LO https://umbrella-static.s3.dualstack.us-west-1.amazonaws.com/top-1m.csv.zip')
-        c.run('unzip top-1m.csv.zip -d .')
-        c.run('chmod +x /opt/pdns-recursor/bin/* /opt/pdns-recursor/sbin/*')
-        c.run(f'DNSBULKTEST=/usr/bin/dnsbulktest RECURSOR=/opt/pdns-recursor/sbin/pdns_recursor RECCONTROL=/opt/pdns-recursor/bin/rec_control IPv6={ipv6} THRESHOLD=95 TRACE=no ./recursor-test 5300 {size} {threads} {mthreads} {shards}')
+    with c.cd("regression-tests"):
+        c.run(
+            "curl --no-progress-meter -LO https://umbrella-static.s3.dualstack.us-west-1.amazonaws.com/top-1m.csv.zip"
+        )
+        c.run("unzip top-1m.csv.zip -d .")
+        c.run("chmod +x /opt/pdns-recursor/bin/* /opt/pdns-recursor/sbin/*")
+        c.run(
+            f"DNSBULKTEST=/usr/bin/dnsbulktest RECURSOR=/opt/pdns-recursor/sbin/pdns_recursor RECCONTROL=/opt/pdns-recursor/bin/rec_control IPv6={ipv6} THRESHOLD=95 TRACE=no ./recursor-test 5300 {size} {threads} {mthreads} {shards}"
+        )
+
 
 @task
 def install_swagger_tools(c):
-    c.run('sudo apt-get update && sudo apt-get install -y npm')
-    c.run('sudo mkdir -p /usr/local/lib/node_modules && sudo chmod 777 /usr/local/lib/node_modules')
-    c.run('npm install -g @stoplight/spectral-cli')
-    c.run('npm install -g api-spec-converter')
+    c.run("sudo apt-get update && sudo apt-get install -y npm")
+    c.run("sudo mkdir -p /usr/local/lib/node_modules && sudo chmod 777 /usr/local/lib/node_modules")
+    c.run("npm install -g @stoplight/spectral-cli")
+    c.run("npm install -g api-spec-converter")
+
 
 @task
 def swagger_syntax_check(c):
-    c.run('spectral lint --ruleset docs/http-api/swagger/spectral-ruleset.yaml --fail-severity error --display-only-failures docs/http-api/swagger/authoritative-api-swagger.yaml')
-    c.run('api-spec-converter docs/http-api/swagger/authoritative-api-swagger.yaml -f swagger_2 -t openapi_3 -s json -c')
+    c.run(
+        "spectral lint --ruleset docs/http-api/swagger/spectral-ruleset.yaml --fail-severity error --display-only-failures docs/http-api/swagger/authoritative-api-swagger.yaml"
+    )
+    c.run(
+        "api-spec-converter docs/http-api/swagger/authoritative-api-swagger.yaml -f swagger_2 -t openapi_3 -s json -c"
+    )
+
 
 @task
 def install_coverity_tools(c, project):
-    token = os.getenv('COVERITY_TOKEN')
-    c.run(f'curl -s https://scan.coverity.com/download/linux64 --data "token={token}&project={project}" | gunzip | sudo tar xvf /dev/stdin --strip-components=1 --no-same-owner -C /usr/local', hide=True)
+    token = os.getenv("COVERITY_TOKEN")
+    c.run(
+        f'curl -s https://scan.coverity.com/download/linux64 --data "token={token}&project={project}" | gunzip | sudo tar xvf /dev/stdin --strip-components=1 --no-same-owner -C /usr/local',
+        hide=True,
+    )
+
 
 @task
 def coverity_clang_configure(c):
-    c.sudo(f'/usr/local/bin/cov-configure --template --comptype clangcc --compiler clang++-{clang_version}')
+    c.sudo(f"/usr/local/bin/cov-configure --template --comptype clangcc --compiler clang++-{clang_version}")
+
 
 @task
 def coverity_make(c):
-    c.run('/usr/local/bin/cov-build --dir cov-int make -j8 -k')
+    c.run("/usr/local/bin/cov-build --dir cov-int make -j8 -k")
+
 
 @task
 def coverity_tarball(c, tarball):
-    c.run(f'tar caf {tarball} cov-int')
+    c.run(f"tar caf {tarball} cov-int")
+
 
 @task
 def coverity_upload(c, email, project, tarball):
-    token = os.getenv('COVERITY_TOKEN')
-    c.run(f'curl --form token={token} \
+    token = os.getenv("COVERITY_TOKEN")
+    c.run(
+        f'curl --form token={token} \
             --form email="{email}" \
             --form file=@{tarball} \
             --form version="$(./builder-support/gen-version)" \
             --form description="master build" \
-            https://scan.coverity.com/builds?project={project}', hide=True)
+            https://scan.coverity.com/builds?project={project}',
+        hide=True,
+    )
+
 
 @task
 def ci_build_and_install_quiche(c, repo):
-    with c.cd(f'{repo}/builder-support/helpers/'):
+    with c.cd(f"{repo}/builder-support/helpers/"):
         # be careful that rust needs to have been installed system-wide,
         # as the one installed in GitHub actions' Ubuntu images in /home/runner/.cargo/bin/cargo
         # is not in the path for the root user (and shouldn't be)
-        c.run(f'sudo {repo}/builder-support/helpers/install_quiche.sh')
+        c.run(f"sudo {repo}/builder-support/helpers/install_quiche.sh")
 
     # cannot use c.sudo() inside a cd() context, see https://github.com/pyinvoke/invoke/issues/687
-    for tentative in ['lib/x86_64-linux-gnu', 'lib/aarch64-linux-gnu', 'lib64', 'lib']:
-        tentative_libdir = f'/usr/{tentative}'
-        quiche_lib = f'{tentative_libdir}/libdnsdist-quiche.so'
+    for tentative in ["lib/x86_64-linux-gnu", "lib/aarch64-linux-gnu", "lib64", "lib"]:
+        tentative_libdir = f"/usr/{tentative}"
+        quiche_lib = f"{tentative_libdir}/libdnsdist-quiche.so"
         if not os.path.isfile(quiche_lib):
             continue
-        c.run(f'sudo mv {quiche_lib} /usr/lib/libquiche.so')
+        c.run(f"sudo mv {quiche_lib} /usr/lib/libquiche.so")
         c.run(f"sudo sed -i 's,^Libs:.*,Libs: -lquiche,g' {tentative_libdir}/pkgconfig/quiche.pc")
-        c.run('mkdir -p /opt/dnsdist/lib')
-        c.run('cp /usr/lib/libquiche.so /opt/dnsdist/lib/libquiche.so')
+        c.run("mkdir -p /opt/dnsdist/lib")
+        c.run("cp /usr/lib/libquiche.so /opt/dnsdist/lib/libquiche.so")
         break
 
+
 @task
 def test_install_package(c, product_name, distro_release, content_url, gpgkey_url, package_name, package_version):
-    distro, release = distro_release.split('-')[:2]
-    repo_domain = content_url.split('/')[2]
-    is_rpm = True if distro == 'centos' or distro == 'el' else False
+    distro, release = distro_release.split("-")[:2]
+    repo_domain = content_url.split("/")[2]
+    is_rpm = True if distro == "centos" or distro == "el" else False
 
     if is_rpm:
-        image_name = 'oraclelinux'
+        image_name = "oraclelinux"
     else:
         image_name = distro
         # pdns package is called pdns-server for debian/ubuntu
-        package_name = 'pdns-server' if package_name == 'pdns' else package_name
+        package_name = "pdns-server" if package_name == "pdns" else package_name
 
     # version of packages from master or not releases have a different order than the package name
-    parts = package_version.split('.')
+    parts = package_version.split(".")
     if len(parts) > 4:
-        if distro == 'el':
-            if 'master' in package_version:
+        if distro == "el":
+            if "master" in package_version:
                 package_version = f"{'.'.join(parts[:3])}.{parts[4]}.{parts[3]}.{'.'.join(parts[5:])}"
             else:
                 package_version = f"{'.'.join(parts[:3])}-{parts[4]}.{parts[3]}.{'.'.join(parts[5:])}"
@@ -1546,43 +1764,43 @@ def test_install_package(c, product_name, distro_release, content_url, gpgkey_ur
             package_version = f"{'.'.join(parts[:3])}+{parts[4]}.{parts[3]}.{'.'.join(parts[5:])}"
 
     # Add wildcards to work with and without releases
-    parts = package_version.split('-')
+    parts = package_version.split("-")
     if len(parts) > 1:
         package_version = f"{parts[0]}*{parts[1]}" if is_rpm else f"{parts[0]}~{parts[1]}"
 
-    dockerfile_rpm = f'''
+    dockerfile_rpm = f"""
 FROM {image_name}:{release}
 RUN curl -L {content_url}/repo-files/{distro}-{product_name}.repo -o /etc/yum.repos.d/{distro}-{product_name}.repo
 RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-{release}.noarch.rpm
 RUN yum install -y {package_name}-{package_version}*
-'''
-    dockerfile_deb = f'''
+"""
+    dockerfile_deb = f"""
 FROM {image_name}:{release}
 RUN apt update && apt install -y curl libluajit-5.1-dev adduser
 RUN install -d /etc/apt/keyrings && curl -L {gpgkey_url} -o /etc/apt/keyrings/{product_name}-pub.asc
 RUN echo "deb [signed-by=/etc/apt/keyrings/{product_name}-pub.asc] {content_url}/{distro} {release}-{product_name} main" | tee /etc/apt/sources.list.d/pdns.list
 RUN bash -c 'echo -e "Package: auth*\\nPin: origin {repo_domain}\\nPin-Priority: 600" | tee /etc/apt/preferences.d/{product_name}'
 RUN apt-get update && apt-get install -y {package_name}={package_version}*
-'''
+"""
     dockerfile = dockerfile_rpm if is_rpm else dockerfile_deb
-    with open('/tmp/Dockerfile', "w") as f:
+    with open("/tmp/Dockerfile", "w") as f:
         f.write(dockerfile)
 
-    c.run(f'docker build . -t test-build-{product_name}-{distro_release}:latest -f /tmp/Dockerfile')
+    c.run(f"docker build . -t test-build-{product_name}-{distro_release}:latest -f /tmp/Dockerfile")
+
 
 @task
 def github_more_diskspace(c):
-    c.run('df -h / /hostroot')
-    for path in ['/usr/local/lib/android',
-              '/usr/local/.ghcup',
-              '/usr/share/dotnet',
-              '/usr/share/swift']:
-              c.sudo(f'rm -rf {path} /hostroot{path}')
-    c.run('df -h / /hostroot')
+    c.run("df -h / /hostroot")
+    for path in ["/usr/local/lib/android", "/usr/local/.ghcup", "/usr/share/dotnet", "/usr/share/swift"]:
+        c.sudo(f"rm -rf {path} /hostroot{path}")
+    c.run("df -h / /hostroot")
+
 
 # this is run always
 def setup():
-    if '/usr/lib/ccache' not in os.environ['PATH']:
-        os.environ['PATH']='/usr/lib/ccache:'+os.environ['PATH']
+    if "/usr/lib/ccache" not in os.environ["PATH"]:
+        os.environ["PATH"] = "/usr/lib/ccache:" + os.environ["PATH"]
+
 
 setup()