Browse Source

tests: faster tests

Nicolas Duchon 5 months ago
parent
commit
69bf2665ec
67 changed files with 397 additions and 244 deletions
  1. 38 12
      test/conftest.py
  2. 7 2
      test/test_acme-http-challenge-location/test_acme-http-challenge-location-disabled.py
  3. 7 2
      test/test_acme-http-challenge-location/test_acme-http-challenge-location-enabled-is-default.py
  4. 3 1
      test/test_acme-http-challenge-location/test_acme-http-challenge-location-legacy.py
  5. 1 1
      test/test_custom-error-page/test_custom-error-page.py
  6. 10 8
      test/test_custom/test_defaults-location.py
  7. 9 7
      test/test_custom/test_defaults.py
  8. 13 9
      test/test_custom/test_location-per-vhost.py
  9. 11 8
      test/test_custom/test_per-vhost.py
  10. 9 7
      test/test_custom/test_proxy-wide.py
  11. 15 14
      test/test_debug-endpoint/test_global.py
  12. 8 8
      test/test_debug-endpoint/test_per-container.py
  13. 8 6
      test/test_docker-unix-socket/test_docker-unix-socket.py
  14. 7 7
      test/test_dockergen/test_dockergen.py
  15. 19 5
      test/test_enable-http-on-missing-cert/test_enable-http-on-missing-cert.py
  16. 6 4
      test/test_events/test_events.py
  17. 7 4
      test/test_fallback/test_fallback.py
  18. 8 1
      test/test_headers/test_http.py
  19. 8 1
      test/test_headers/test_https.py
  20. 2 2
      test/test_host-network-mode/test_host-network-mode.py
  21. 1 1
      test/test_htpasswd/test_htpasswd-regex-virtual-host.py
  22. 1 1
      test/test_htpasswd/test_htpasswd-virtual-host.py
  23. 2 1
      test/test_htpasswd/test_htpasswd-virtual-path.py
  24. 1 0
      test/test_http-port/test_http-port.py
  25. 1 0
      test/test_http3/test_http3-global-disabled.py
  26. 3 2
      test/test_http3/test_http3-global-enabled.py
  27. 13 8
      test/test_http3/test_http3-vhost.py
  28. 3 2
      test/test_internal/test_internal-per-vhost.py
  29. 3 2
      test/test_internal/test_internal-per-vpath.py
  30. 2 2
      test/test_ipv6/test_ipv6-prefer-ipv4-network.py
  31. 2 2
      test/test_ipv6/test_ipv6-prefer-ipv6-network.py
  32. 11 11
      test/test_ipv6/test_ipv6.py
  33. 4 0
      test/test_keepalive/test_keepalive.py
  34. 4 1
      test/test_loadbalancing/test_loadbalancing.py
  35. 13 7
      test/test_location-override/test_location-override.py
  36. 4 0
      test/test_logs/test_log-disabled.py
  37. 4 0
      test/test_logs/test_log-format.py
  38. 2 1
      test/test_logs/test_log-json-format.py
  39. 2 1
      test/test_logs/test_log-json.py
  40. 6 4
      test/test_multiple-hosts/test_multiple-hosts.py
  41. 7 4
      test/test_multiple-networks/test_multiple-networks.py
  42. 1 1
      test/test_multiports/test_multiports-base-json.py
  43. 1 1
      test/test_multiports/test_multiports-base-yaml.py
  44. 7 7
      test/test_multiports/test_multiports-invalid-syntax.py
  45. 8 8
      test/test_nominal/test_nominal.py
  46. 3 1
      test/test_ports/test_virtual-port-single-different-from-single-port.py
  47. 5 1
      test/test_server-down/test_server-down.py
  48. 8 8
      test/test_ssl/test_cert-selection.py
  49. 1 1
      test/test_ssl/test_dhparam.py
  50. 5 0
      test/test_ssl/test_hsts.py
  51. 4 1
      test/test_ssl/test_https-port.py
  52. 14 12
      test/test_ssl/test_nohttp.py
  53. 3 2
      test/test_ssl/test_nohttps.py
  54. 1 4
      test/test_ssl/test_noredirect.py
  55. 2 2
      test/test_ssl/test_virtual-path.py
  56. 9 6
      test/test_ssl/test_wildcard-cert-nohttps.py
  57. 2 5
      test/test_ssl/test_wildcard.py
  58. 11 11
      test/test_unreachable-network/test_unreachable-network.py
  59. 2 1
      test/test_upstream-name/test_sha1-name.py
  60. 2 0
      test/test_vhost-empty-string/test_vhost-empty-string.py
  61. 2 0
      test/test_vhost-in-multiple-networks/test_vhost-in-multiple-networks.py
  62. 5 3
      test/test_virtual-path/test_custom-conf.py
  63. 3 4
      test/test_virtual-path/test_default-root-none.py
  64. 3 2
      test/test_virtual-path/test_forwarding.py
  65. 2 1
      test/test_virtual-path/test_location-precedence.py
  66. 7 2
      test/test_virtual-path/test_virtual-paths.py
  67. 1 1
      test/test_wildcard-host/test_wildcard-host.py

+ 38 - 12
test/conftest.py

@@ -9,7 +9,7 @@ import socket
 import subprocess
 import time
 from io import StringIO
-from typing import List
+from typing import List, Callable
 
 import backoff
 import docker.errors
@@ -19,7 +19,7 @@ import requests
 from docker.models.containers import Container
 from docker.models.networks import Network
 from packaging.version import Version
-
+from requests.models import Response
 
 logging.basicConfig(level=logging.INFO)
 logging.getLogger('backoff').setLevel(logging.INFO)
@@ -92,6 +92,17 @@ class RequestsForDocker(object):
         if os.path.isfile(CA_ROOT_CERTIFICATE):
             self.session.verify = CA_ROOT_CERTIFICATE
 
+    @staticmethod
+    def __backoff_predicate(expected_status_codes=None) -> Callable[[Response], bool]:
+        if expected_status_codes is not None:
+            if isinstance(expected_status_codes, int):
+                expected_status_codes = [expected_status_codes]
+            return lambda r: r.status_code not in expected_status_codes
+        else:
+            return lambda r: r.status_code not in [200, 301]
+
+    __backed_off_exceptions = (requests.exceptions.SSLError, requests.exceptions.ConnectionError)
+
     @staticmethod
     def get_nginx_proxy_containers() -> List[Container]:
         """
@@ -119,8 +130,16 @@ class RequestsForDocker(object):
         return container_ip(nginx_proxy_containers[0])
 
     def get(self, *args, **kwargs):
+        _expected_status_code = kwargs.pop('expected_status_code', None)
+        with ipv6(kwargs.pop('ipv6', False)):
+            @backoff.on_exception(backoff.expo, self.__backed_off_exceptions, max_time=8)
+            @backoff.on_predicate(backoff.expo, self.__backoff_predicate(_expected_status_code), max_time=8)
+            def _get(*_args, **_kwargs):
+                return self.session.get(*_args, **_kwargs)
+            return _get(*args, **kwargs)
+
+    def get_without_backoff(self, *args, **kwargs):
         with ipv6(kwargs.pop('ipv6', False)):
-            @backoff.on_predicate(backoff.constant, lambda r: r.status_code in (404, 502), interval=.3, max_tries=30, jitter=None)
             def _get(*_args, **_kwargs):
                 return self.session.get(*_args, **_kwargs)
             return _get(*args, **kwargs)
@@ -352,14 +371,22 @@ def wait_for_nginxproxy_to_be_ready():
     If one (and only one) container started from image nginxproxy/nginx-proxy:test is found,
     wait for its log to contain substring "Watching docker events"
     """
-    containers = docker_client.containers.list(filters={"ancestor": "nginxproxy/nginx-proxy:test"})
-    if len(containers) != 1:
-        return
-    container = containers[0]
-    for line in container.logs(stream=True):
-        if b"Watching docker events" in line:
-            logging.debug("nginx-proxy ready")
-            break
+    timeout = time.time() + 10
+    while True:
+        containers = docker_client.containers.list(
+            filters={"status": "running", "ancestor": "nginxproxy/nginx-proxy:test"}
+        )
+
+        if len(containers) != 1:
+            logging.warning(f"Found {len(containers)} nginxproxy/nginx-proxy:test containers running")
+        else:
+            for line in containers.pop().logs(stream=True):
+                if b"Generated '/etc/nginx/conf.d/default.conf'" in line:
+                    return
+
+        if time.time() > timeout:
+            pytest.fail("nginxproxy/nginx-proxy:test container not ready after 10s", pytrace=False)
+        time.sleep(1)
 
 
 @pytest.fixture
@@ -491,7 +518,6 @@ class DockerComposer(contextlib.AbstractContextManager):
         docker_compose_up(docker_compose_files, project_name)
         self._networks = connect_to_all_networks()
         wait_for_nginxproxy_to_be_ready()
-        time.sleep(3)  # give time to containers to be ready
         self._docker_compose_files = docker_compose_files
         self._project_name = project_name
 

+ 7 - 2
test/test_acme-http-challenge-location/test_acme-http-challenge-location-disabled.py

@@ -1,10 +1,12 @@
 def test_redirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
     r = nginxproxy.get(
         f"http://web1.nginx-proxy.tld/{acme_challenge_path}",
-        allow_redirects=False
+        allow_redirects=False,
+        expected_status_code=301
     )
     assert r.status_code == 301
 
+
 def test_redirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path):
     r = nginxproxy.get(
         f"http://web2.nginx-proxy.tld/{acme_challenge_path}",
@@ -12,13 +14,16 @@ def test_redirect_acme_challenge_location_enabled(docker_compose, nginxproxy, ac
     )
     assert r.status_code == 200
 
+
 def test_noredirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
     r = nginxproxy.get(
         f"http://web3.nginx-proxy.tld/{acme_challenge_path}",
-        allow_redirects=False
+        allow_redirects=False,
+        expected_status_code=404
     )
     assert r.status_code == 404
 
+
 def test_noredirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path):
     r = nginxproxy.get(
         f"http://web4.nginx-proxy.tld/{acme_challenge_path}",

+ 7 - 2
test/test_acme-http-challenge-location/test_acme-http-challenge-location-enabled-is-default.py

@@ -5,13 +5,16 @@ def test_redirect_acme_challenge_location_enabled(docker_compose, nginxproxy, ac
     )
     assert r.status_code == 200
 
+
 def test_redirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
     r = nginxproxy.get(
         f"http://web2.nginx-proxy.tld/{acme_challenge_path}",
-        allow_redirects=False
+        allow_redirects=False,
+        expected_status_code=301
     )
     assert r.status_code == 301
 
+
 def test_noredirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path):
     r = nginxproxy.get(
         f"http://web3.nginx-proxy.tld/{acme_challenge_path}",
@@ -19,9 +22,11 @@ def test_noredirect_acme_challenge_location_enabled(docker_compose, nginxproxy,
     )
     assert r.status_code == 200
 
+
 def test_noredirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
     r = nginxproxy.get(
         f"http://web4.nginx-proxy.tld/{acme_challenge_path}",
-        allow_redirects=False
+        allow_redirects=False,
+        expected_status_code=404
     )
     assert r.status_code == 404

+ 3 - 1
test/test_acme-http-challenge-location/test_acme-http-challenge-location-legacy.py

@@ -5,9 +5,11 @@ def test_redirect_acme_challenge_location_legacy(docker_compose, nginxproxy, acm
     )
     assert r.status_code == 200
 
+
 def test_noredirect_acme_challenge_location_legacy(docker_compose, nginxproxy, acme_challenge_path):
     r = nginxproxy.get(
         f"http://web2.nginx-proxy.tld/{acme_challenge_path}",
-        allow_redirects=False
+        allow_redirects=False,
+        expected_status_code=404
     )
     assert r.status_code == 404

+ 1 - 1
test/test_custom-error-page/test_custom-error-page.py

@@ -2,6 +2,6 @@ import re
 
 
 def test_custom_error_page(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://unknown.nginx-proxy.tld")
+    r = nginxproxy.get("http://unknown.nginx-proxy.tld", expected_status_code=503)
     assert r.status_code == 503
     assert re.search(r"Damn, there's some maintenance in progress.", r.text)

+ 10 - 8
test/test_custom/test_defaults-location.py

@@ -1,18 +1,14 @@
-def test_custom_default_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/")
-    assert r.status_code == 503
-    assert "X-test" not in r.headers
-
 def test_custom_default_conf_applies_to_web1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
     assert "X-test" in r.headers
     assert "f00" == r.headers["X-test"]
 
+
 def test_custom_default_conf_applies_to_web2(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 82\n"
     assert "X-test" in r.headers
     assert "f00" == r.headers["X-test"]
@@ -20,7 +16,13 @@ def test_custom_default_conf_applies_to_web2(docker_compose, nginxproxy):
 
 def test_custom_default_conf_is_overriden_for_web3(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web3.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 83\n"
     assert "X-test" in r.headers
     assert "bar" == r.headers["X-test"]
+
+
+def test_custom_default_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://nginx-proxy/", expected_status_code=503)
+    assert r.status_code == 503
+    assert "X-test" not in r.headers

+ 9 - 7
test/test_custom/test_defaults.py

@@ -1,18 +1,20 @@
-def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/")
-    assert r.status_code == 503
-    assert "X-test" not in r.headers
-
 def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
     assert "X-test" in r.headers
     assert "f00" == r.headers["X-test"]
 
+
 def test_custom_conf_applies_to_web2(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 82\n"
     assert "X-test" in r.headers
     assert "f00" == r.headers["X-test"]
+
+
+def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://nginx-proxy/", expected_status_code=503)
+    assert r.status_code == 503
+    assert "X-test" not in r.headers

+ 13 - 9
test/test_custom/test_location-per-vhost.py

@@ -1,27 +1,31 @@
-def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/")
-    assert r.status_code == 503
-    assert "X-test" not in r.headers
-
 def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
     assert "X-test" in r.headers
     assert "f00" == r.headers["X-test"]
 
+
 def test_custom_conf_applies_to_regex(docker_compose, nginxproxy):
     r = nginxproxy.get("http://regex.foo.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 83\n"
     assert "X-test" in r.headers
     assert "bar" == r.headers["X-test"]
 
+
 def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 82\n"
     assert "X-test" not in r.headers
 
+
+def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://nginx-proxy/", expected_status_code=503)
+    assert r.status_code == 503
+    assert "X-test" not in r.headers
+
+
 def test_custom_block_is_present_in_nginx_generated_conf(docker_compose, nginxproxy):
-    assert b"include /etc/nginx/vhost.d/web1.nginx-proxy.example_location;" in nginxproxy.get_conf()
+    assert b"include /etc/nginx/vhost.d/web1.nginx-proxy.example_location;" in nginxproxy.get_conf()

+ 11 - 8
test/test_custom/test_per-vhost.py

@@ -1,24 +1,27 @@
-def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/")
-    assert r.status_code == 503
-    assert "X-test" not in r.headers
-
 def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
     assert "X-test" in r.headers
     assert "f00" == r.headers["X-test"]
 
+
 def test_custom_conf_applies_to_regex(docker_compose, nginxproxy):
     r = nginxproxy.get("http://regex.foo.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 83\n"
     assert "X-test" in r.headers
     assert "bar" == r.headers["X-test"]
 
+
 def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 82\n"
     assert "X-test" not in r.headers
+
+
+def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://nginx-proxy/", expected_status_code=503)
+    assert r.status_code == 503
+    assert "X-test" not in r.headers

+ 9 - 7
test/test_custom/test_proxy-wide.py

@@ -1,18 +1,20 @@
-def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/")
-    assert r.status_code == 503
-    assert "X-test" not in r.headers
-
 def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
     assert "X-test" in r.headers
     assert "f00" == r.headers["X-test"]
 
+
 def test_custom_conf_applies_to_web2(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 82\n"
     assert "X-test" in r.headers
     assert "f00" == r.headers["X-test"]
+
+
+def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://nginx-proxy/", expected_status_code=503)
+    assert r.status_code == 503
+    assert "X-test" not in r.headers

+ 15 - 14
test/test_debug-endpoint/test_global.py

@@ -10,39 +10,40 @@ def test_debug_endpoint_is_enabled_globally(docker_compose, nginxproxy):
     assert r.status_code == 200
 
 
-def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxproxy):   
+def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxproxy):
     r = nginxproxy.get("http://enabled.debug.nginx-proxy.example/nginx-proxy-debug")
     assert r.status_code == 200
     try:
-        jsonResponse = json.loads(r.text)
+        json_response = json.loads(r.text)
+        assert json_response["global"]["enable_debug_endpoint"] == "true"
+        assert json_response["vhost"]["enable_debug_endpoint"] == True
     except ValueError as err:
         pytest.fail("Failed to parse debug endpoint response as JSON: %s" % err, pytrace=False)
-    assert jsonResponse["global"]["enable_debug_endpoint"] == "true"
-    assert jsonResponse["vhost"]["enable_debug_endpoint"] == True
 
 
-def test_debug_endpoint_paths_stripped_if_response_too_long(docker_compose, nginxproxy):   
+def test_debug_endpoint_paths_stripped_if_response_too_long(docker_compose, nginxproxy):
     r = nginxproxy.get("http://stripped.debug.nginx-proxy.example/nginx-proxy-debug")
     assert r.status_code == 200
     try:
-        jsonResponse = json.loads(r.text)
+        json_response = json.loads(r.text)
+        if "paths" in json_response["vhost"]:
+            pytest.fail("Expected paths to be stripped from debug endpoint response", pytrace=False)
+        assert json_response[
+                   "warning"] == "Virtual paths configuration for this hostname is too large and has been stripped from response."
     except ValueError as err:
         pytest.fail("Failed to parse debug endpoint response as JSON: %s" % err, pytrace=False)
-    if "paths" in jsonResponse["vhost"]:
-        pytest.fail("Expected paths to be stripped from debug endpoint response", pytrace=False)
-    assert jsonResponse["warning"] == "Virtual paths configuration for this hostname is too large and has been stripped from response."
 
 
-def test_debug_endpoint_hostname_replaced_by_warning_if_regexp(docker_compose, nginxproxy):   
+def test_debug_endpoint_hostname_replaced_by_warning_if_regexp(docker_compose, nginxproxy):
     r = nginxproxy.get("http://regexp.foo.debug.nginx-proxy.example/nginx-proxy-debug")
     assert r.status_code == 200
     try:
-        jsonResponse = json.loads(r.text)
+        json_response = json.loads(r.text)
+        assert json_response["vhost"]["hostname"] == "Hostname is a regexp and unsafe to include in the debug response."
     except ValueError as err:
         pytest.fail("Failed to parse debug endpoint response as JSON: %s" % err, pytrace=False)
-    assert jsonResponse["vhost"]["hostname"] == "Hostname is a regexp and unsafe to include in the debug response."
 
 
 def test_debug_endpoint_is_disabled_per_container(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://disabled.debug.nginx-proxy.example/nginx-proxy-debug")
-    assert r.status_code == 404  
+    r = nginxproxy.get("http://disabled.debug.nginx-proxy.example/nginx-proxy-debug", expected_status_code=404)
+    assert r.status_code == 404

+ 8 - 8
test/test_debug-endpoint/test_per-container.py

@@ -4,10 +4,10 @@ import pytest
 
 
 def test_debug_endpoint_is_disabled_globally(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://disabled1.debug.nginx-proxy.example/nginx-proxy-debug")
-    assert r.status_code == 404 
-    r = nginxproxy.get("http://disabled2.debug.nginx-proxy.example/nginx-proxy-debug")
-    assert r.status_code == 404 
+    r = nginxproxy.get("http://disabled1.debug.nginx-proxy.example/nginx-proxy-debug", expected_status_code=404)
+    assert r.status_code == 404
+    r = nginxproxy.get("http://disabled2.debug.nginx-proxy.example/nginx-proxy-debug", expected_status_code=404)
+    assert r.status_code == 404
 
 
 def test_debug_endpoint_is_enabled_per_container(docker_compose, nginxproxy):
@@ -15,12 +15,12 @@ def test_debug_endpoint_is_enabled_per_container(docker_compose, nginxproxy):
     assert r.status_code == 200
 
 
-def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxproxy):   
+def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxproxy):
     r = nginxproxy.get("http://enabled.debug.nginx-proxy.example/nginx-proxy-debug")
     assert r.status_code == 200
     try:
-        jsonResponse = json.loads(r.text)
+        json_response = json.loads(r.text)
+        assert json_response["global"]["enable_debug_endpoint"] == "false"
+        assert json_response["vhost"]["enable_debug_endpoint"] == True
     except ValueError as err:
         pytest.fail("Failed to parse debug endpoint response as JSON:: %s" % err, pytrace=False)
-    assert jsonResponse["global"]["enable_debug_endpoint"] == "false"
-    assert jsonResponse["vhost"]["enable_debug_endpoint"] == True

+ 8 - 6
test/test_docker-unix-socket/test_docker-unix-socket.py

@@ -1,13 +1,15 @@
-def test_unknown_virtual_host(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/port")
-    assert r.status_code == 503
-
 def test_forwards_to_web1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.tld/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
 
+
 def test_forwards_to_web2(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.tld/port")
     assert r.status_code == 200
-    assert r.text == "answer from port 82\n" 
+    assert r.text == "answer from port 82\n"
+
+
+def test_unknown_virtual_host(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://nginx-proxy/port", expected_status_code=503)
+    assert r.status_code == 503

+ 7 - 7
test/test_dockergen/test_dockergen.py

@@ -2,26 +2,26 @@ import docker
 import pytest
 from packaging.version import Version
 
-
 raw_version = docker.from_env().version()["Version"]
 pytestmark = pytest.mark.skipif(
     Version(raw_version) < Version("1.13"),
     reason="Docker compose syntax v3 requires docker engine v1.13 or later (got {raw_version})"
 )
 
-
-def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://unknown.nginx.container.docker/")
-    assert r.status_code == 503
-
-
+@pytest.mark.skip("not ready")
 def test_forwards_to_whoami(docker_compose, nginxproxy):
     r = nginxproxy.get("http://whoami.nginx.container.docker/")
     assert r.status_code == 200
     whoami_container = docker_compose.containers.get("whoami")
     assert r.text == f"I'm {whoami_container.id[:12]}\n"
 
+@pytest.mark.skip("not ready")
+def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://unknown.nginx.container.docker/", expected_status_code=503)
+    assert r.status_code == 503
+
 
 if __name__ == "__main__":
     import doctest
+
     doctest.testmod()

+ 19 - 5
test/test_enable-http-on-missing-cert/test_enable-http-on-missing-cert.py

@@ -1,15 +1,29 @@
-def test_nohttp_missing_cert_disabled(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nohttp-missing-cert-disabled.nginx-proxy.tld/", allow_redirects=False)
-    assert r.status_code == 503
+
 
 def test_nohttp_missing_cert_enabled(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nohttp-missing-cert-enabled.nginx-proxy.tld/", allow_redirects=False)
+    r = nginxproxy.get(
+        "http://nohttp-missing-cert-enabled.nginx-proxy.tld/",
+        allow_redirects=False,
+        expected_status_code=301
+    )
     assert r.status_code == 200
 
 def test_redirect_missing_cert_disabled(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://redirect-missing-cert-disabled.nginx-proxy.tld/", allow_redirects=False)
+    r = nginxproxy.get(
+        "http://redirect-missing-cert-disabled.nginx-proxy.tld/",
+        allow_redirects=False,
+        expected_status_code=301
+    )
     assert r.status_code == 301
 
 def test_redirect_missing_cert_enabled(docker_compose, nginxproxy):
     r = nginxproxy.get("http://redirect-missing-cert-enabled.nginx-proxy.tld/", allow_redirects=False)
     assert r.status_code == 200
+
+def test_nohttp_missing_cert_disabled(docker_compose, nginxproxy):
+    r = nginxproxy.get(
+        "http://nohttp-missing-cert-disabled.nginx-proxy.tld/",
+        allow_redirects=False,
+        expected_status_code=503
+    )
+    assert r.status_code == 503

+ 6 - 4
test/test_events/test_events.py

@@ -1,6 +1,7 @@
 """
 Test that nginx-proxy detects new containers
 """
+import time
 from time import sleep
 
 import pytest
@@ -56,7 +57,8 @@ def web2(docker_compose):
         pass
 
 def test_nginx_proxy_behavior_when_alone(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/")
+    time.sleep(3)
+    r = nginxproxy.get("http://nginx-proxy/", expected_status_code=503)
     assert r.status_code == 503
 
 
@@ -67,18 +69,18 @@ def test_new_container_is_detected_vhost(web1, nginxproxy):
 
     web1.remove(force=True)
     sleep(2)
-    r = nginxproxy.get("http://web1.nginx-proxy/port")
+    r = nginxproxy.get("http://web1.nginx-proxy/port", expected_status_code=503)
     assert r.status_code == 503
 
 def test_new_container_is_detected_vpath(web2, nginxproxy):
     r = nginxproxy.get("http://nginx-proxy/web2/port")
     assert r.status_code == 200
     assert "answer from port 82\n" == r.text
-    r = nginxproxy.get("http://nginx-proxy/port")
+    r = nginxproxy.get("http://nginx-proxy/port", expected_status_code=[404, 503])
     assert r.status_code in [404, 503]
 
     web2.remove(force=True)
     sleep(2)
-    r = nginxproxy.get("http://nginx-proxy/web2/port")
+    r = nginxproxy.get("http://nginx-proxy/web2/port", expected_status_code=503)
     assert r.status_code == 503
 

+ 7 - 4
test/test_fallback/test_fallback.py

@@ -25,8 +25,11 @@ def get(docker_compose, nginxproxy, want_err_re):
         interval=.3,
         max_tries=30,
         jitter=None)
-    def _get(url):
-        return nginxproxy.get(url, allow_redirects=False)
+    def _get(url, want_code=None):
+        if want_code is None:
+            return nginxproxy.get_without_backoff(url, allow_redirects=False)
+        else:
+            return nginxproxy.get(url, allow_redirects=False, expected_status_code=want_code)
     yield _get
 
 
@@ -106,9 +109,9 @@ INTERNAL_ERR_RE = re.compile("TLSV1_UNRECOGNIZED_NAME")
     # should prefer that server for handling requests for unknown vhosts.
     ("custom-fallback.yml", "http://unknown.nginx-proxy.test/", 418, None),
 ])
-def test_fallback(get, url, want_code, want_err_re):
+def test_fallback(get, compose_file, url, want_code, want_err_re):
     if want_err_re is None:
-        r = get(url)
+        r = get(url, want_code)
         assert r.status_code == want_code
     else:
         with pytest.raises(requests.exceptions.SSLError, match=want_err_re):

+ 8 - 1
test/test_headers/test_http.py

@@ -11,6 +11,7 @@ def test_X_Forwarded_For_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Forwarded-For:" in r.text
 
+
 def test_X_Forwarded_For_is_passed_on(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-For': '1.2.3.4'})
     assert r.status_code == 200
@@ -24,6 +25,7 @@ def test_X_Forwarded_Proto_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Forwarded-Proto: http" in r.text
 
+
 def test_X_Forwarded_Proto_is_passed_on(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Proto': 'f00'})
     assert r.status_code == 200
@@ -37,6 +39,7 @@ def test_X_Forwarded_Host_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Forwarded-Host: web.nginx-proxy.tld\n" in r.text
 
+
 def test_X_Forwarded_Host_is_passed_on(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Host': 'example.com'})
     assert r.status_code == 200
@@ -50,6 +53,7 @@ def test_X_Forwarded_Port_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Forwarded-Port: 80\n" in r.text
 
+
 def test_X_Forwarded_Port_is_passed_on(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Port': '1234'})
     assert r.status_code == 200
@@ -63,6 +67,7 @@ def test_X_Forwarded_Ssl_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Forwarded-Ssl: off\n" in r.text
 
+
 def test_X_Forwarded_Ssl_is_overwritten(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Ssl': 'f00'})
     assert r.status_code == 200
@@ -76,11 +81,13 @@ def test_X_Real_IP_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Real-IP: " in r.text
 
+
 def test_Host_is_passed_on(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web.nginx-proxy.tld/headers")
     assert r.status_code == 200
     assert "Host: web.nginx-proxy.tld" in r.text
 
+
 def test_httpoxy_safe(docker_compose, nginxproxy):
     """
     See https://httpoxy.org/
@@ -93,7 +100,7 @@ def test_httpoxy_safe(docker_compose, nginxproxy):
 
 def test_no_host_server_tokens_off(docker_compose, nginxproxy):
     ip = nginxproxy.get_ip()
-    r = nginxproxy.get(f"http://{ip}/headers")
+    r = nginxproxy.get(f"http://{ip}/headers", expected_status_code=503)
     assert r.status_code == 503
     assert r.headers["Server"] == "nginx"
 

+ 8 - 1
test/test_headers/test_https.py

@@ -14,6 +14,7 @@ def test_X_Forwarded_For_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Forwarded-For:" in r.text
 
+
 def test_X_Forwarded_For_is_passed_on(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-For': '1.2.3.4'})
     assert r.status_code == 200
@@ -27,6 +28,7 @@ def test_X_Forwarded_Proto_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Forwarded-Proto: https" in r.text
 
+
 def test_X_Forwarded_Proto_is_passed_on(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Proto': 'f00'})
     assert r.status_code == 200
@@ -40,6 +42,7 @@ def test_X_Forwarded_Host_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Forwarded-Host: web.nginx-proxy.tld\n" in r.text
 
+
 def test_X_Forwarded_Host_is_passed_on(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Host': 'example.com'})
     assert r.status_code == 200
@@ -53,6 +56,7 @@ def test_X_Forwarded_Port_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Forwarded-Port: 443\n" in r.text
 
+
 def test_X_Forwarded_Port_is_passed_on(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Port': '1234'})
     assert r.status_code == 200
@@ -66,6 +70,7 @@ def test_X_Forwarded_Ssl_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Forwarded-Ssl: on\n" in r.text
 
+
 def test_X_Forwarded_Ssl_is_overwritten(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Ssl': 'f00'})
     assert r.status_code == 200
@@ -79,11 +84,13 @@ def test_X_Real_IP_is_generated(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert "X-Real-IP: " in r.text
 
+
 def test_Host_is_passed_on(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web.nginx-proxy.tld/headers")
     assert r.status_code == 200
     assert "Host: web.nginx-proxy.tld" in r.text
 
+
 def test_httpoxy_safe(docker_compose, nginxproxy):
     """
     See https://httpoxy.org/
@@ -97,7 +104,7 @@ def test_httpoxy_safe(docker_compose, nginxproxy):
 @pytest.mark.filterwarnings('ignore::urllib3.exceptions.InsecureRequestWarning')
 def test_no_host_server_tokens_off(docker_compose, nginxproxy):
     ip = nginxproxy.get_ip()
-    r = nginxproxy.get(f"https://{ip}/headers", verify=False)
+    r = nginxproxy.get(f"https://{ip}/headers", verify=False, expected_status_code=503)
     assert r.status_code == 503
     assert r.headers["Server"] == "nginx"
 

+ 2 - 2
test/test_host-network-mode/test_host-network-mode.py

@@ -1,10 +1,10 @@
 def test_forwards_to_bridge_network_container(docker_compose, nginxproxy):
     r = nginxproxy.get("http://bridge-network.nginx-proxy.tld/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 80\n"
 
 
 def test_forwards_to_host_network_container(docker_compose, nginxproxy):
     r = nginxproxy.get("http://host-network.nginx-proxy.tld/port")
     assert r.status_code == 200
-    assert r.text == "answer from port 8080\n" 
+    assert r.text == "answer from port 8080\n"

+ 1 - 1
test/test_htpasswd/test_htpasswd-regex-virtual-host.py

@@ -1,5 +1,5 @@
 def test_htpasswd_regex_virtual_host_is_restricted(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://regex.htpasswd.nginx-proxy.example/port")
+    r = nginxproxy.get("http://regex.htpasswd.nginx-proxy.example/port", expected_status_code=401)
     assert r.status_code == 401
     assert "WWW-Authenticate" in r.headers
     assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted access"'

+ 1 - 1
test/test_htpasswd/test_htpasswd-virtual-host.py

@@ -1,5 +1,5 @@
 def test_htpasswd_virtual_host_is_restricted(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://htpasswd.nginx-proxy.tld/port")
+    r = nginxproxy.get("http://htpasswd.nginx-proxy.tld/port", expected_status_code=401)
     assert r.status_code == 401
     assert "WWW-Authenticate" in r.headers
     assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted htpasswd.nginx-proxy.tld"'

+ 2 - 1
test/test_htpasswd/test_htpasswd-virtual-path.py

@@ -1,9 +1,10 @@
 def test_htpasswd_virtual_path_is_restricted(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://htpasswd.nginx-proxy.tld/foo/port")
+    r = nginxproxy.get("http://htpasswd.nginx-proxy.tld/foo/port", expected_status_code=401)
     assert r.status_code == 401
     assert "WWW-Authenticate" in r.headers
     assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted htpasswd.nginx-proxy.tld/foo/"'
 
+
 def test_htpasswd_virtual_path_basic_auth(docker_compose, nginxproxy):
     r = nginxproxy.get("http://htpasswd.nginx-proxy.tld/foo/port", auth=("vpath", "password"))
     assert r.status_code == 200

+ 1 - 0
test/test_http-port/test_http-port.py

@@ -7,6 +7,7 @@ def test_web1_http_custom_port(docker_compose, nginxproxy, subdomain):
     assert r.status_code == 200
     assert "answer from port 81\n" in r.text
 
+
 def test_nonstandardport_Host_header(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web.nginx-proxy.tld:8080/headers")
     assert r.status_code == 200

+ 1 - 0
test/test_http3/test_http3-global-disabled.py

@@ -10,6 +10,7 @@ def test_http3_global_disabled_ALTSVC_header(docker_compose, nginxproxy):
     assert "Host: http3-global-disabled.nginx-proxy.tld" in r.text
     assert not "alt-svc" in r.headers
 
+
 def test_http3_global_disabled_config(docker_compose, nginxproxy):
     conf = nginxproxy.get_conf().decode('ASCII')
     r = nginxproxy.get("http://http3-global-disabled.nginx-proxy.tld")

+ 3 - 2
test/test_http3/test_http3-global-enabled.py

@@ -11,11 +11,12 @@ def test_http3_global_enabled_ALTSVC_header(docker_compose, nginxproxy):
     assert "alt-svc" in r.headers
     assert r.headers["alt-svc"] == 'h3=":443"; ma=86400;'
 
+
 def test_http3_global_enabled_config(docker_compose, nginxproxy):
     conf = nginxproxy.get_conf().decode('ASCII')
     r = nginxproxy.get("http://http3-global-enabled.nginx-proxy.tld")
     assert r.status_code == 200
-    assert re.search(r"listen 443 quic reuseport\;", conf)
+    assert re.search(r"listen 443 quic reuseport;", conf)
     assert re.search(r"(?s)http3-global-enabled\.nginx-proxy\.tld;.*listen 443 quic", conf)
-    assert re.search(r"(?s)http3-global-enabled\.nginx-proxy\.tld;.*http3 on\;", conf)
+    assert re.search(r"(?s)http3-global-enabled\.nginx-proxy\.tld;.*http3 on;", conf)
     assert re.search(r"(?s)http3-global-enabled\.nginx-proxy\.tld;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'", conf)

+ 13 - 8
test/test_http3/test_http3-vhost.py

@@ -11,28 +11,32 @@ def test_http3_vhost_enabled_ALTSVC_header(docker_compose, nginxproxy):
     assert "alt-svc" in r.headers
     assert r.headers["alt-svc"] == 'h3=":443"; ma=86400;'
 
+
 def test_http3_vhost_enabled_config(docker_compose, nginxproxy):
     conf = nginxproxy.get_conf().decode('ASCII')
     r = nginxproxy.get("http://http3-vhost-enabled.nginx-proxy.tld")
     assert r.status_code == 200
-    assert re.search(r"listen 443 quic reuseport\;", conf)
+    assert re.search(r"listen 443 quic reuseport;", conf)
     assert re.search(r"(?s)http3-vhost-enabled\.nginx-proxy\.tld;.*listen 443 quic", conf)
-    assert re.search(r"(?s)http3-vhost-enabled\.nginx-proxy\.tld;.*http3 on\;", conf)
+    assert re.search(r"(?s)http3-vhost-enabled\.nginx-proxy\.tld;.*http3 on;", conf)
     assert re.search(r"(?s)http3-vhost-enabled\.nginx-proxy\.tld;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'", conf)
 
+
 def test_http3_vhost_disabled_ALTSVC_header(docker_compose, nginxproxy):
     r = nginxproxy.get("http://http3-vhost-disabled.nginx-proxy.tld/headers")
     assert r.status_code == 200
     assert "Host: http3-vhost-disabled.nginx-proxy.tld" in r.text
     assert not "alt-svc" in r.headers
 
+
 def test_http3_vhost_disabled_config(docker_compose, nginxproxy):
     conf = nginxproxy.get_conf().decode('ASCII')
     r = nginxproxy.get("http://http3-vhost-disabled.nginx-proxy.tld")
     assert r.status_code == 200
-    assert not re.search(r"(?s)http3-vhost-disabled\.nginx-proxy\.tld.*listen 443 quic.*\# http3-vhost-enabled\.nginx-proxy\.tld", conf)
-    assert not re.search(r"(?s)http3-vhost-disabled\.nginx-proxy\.tld.*http3 on.*\# http3-vhost-enabled\.nginx-proxy\.tld", conf)
-    assert not re.search(r"(?s)http3-vhost-disabled\.nginx-proxy\.tld;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'.*\# http3-vhost-enabled\.nginx-proxy\.tld", conf)
+    assert not re.search(r"(?s)http3-vhost-disabled\.nginx-proxy\.tld.*listen 443 quic.*# http3-vhost-enabled\.nginx-proxy\.tld", conf)
+    assert not re.search(r"(?s)http3-vhost-disabled\.nginx-proxy\.tld.*http3 on.*# http3-vhost-enabled\.nginx-proxy\.tld", conf)
+    assert not re.search(r"(?s)http3-vhost-disabled\.nginx-proxy\.tld;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'.*# http3-vhost-enabled\.nginx-proxy\.tld", conf)
+
 
 def test_http3_vhost_disabledbydefault_ALTSVC_header(docker_compose, nginxproxy):
     r = nginxproxy.get("http://http3-vhost-default-disabled.nginx-proxy.tld/headers")
@@ -40,10 +44,11 @@ def test_http3_vhost_disabledbydefault_ALTSVC_header(docker_compose, nginxproxy)
     assert "Host: http3-vhost-default-disabled.nginx-proxy.tld" in r.text
     assert not "alt-svc" in r.headers
 
+
 def test_http3_vhost_disabledbydefault_config(docker_compose, nginxproxy):
     conf = nginxproxy.get_conf().decode('ASCII')
     r = nginxproxy.get("http://http3-vhost-default-disabled.nginx-proxy.tld")
     assert r.status_code == 200
-    assert not re.search(r"(?s)http3-vhost-default-disabled\.nginx-proxy\.tld.*listen 443 quic.*\# http3-vhost-disabled\.nginx-proxy\.tld", conf)
-    assert not re.search(r"(?s)http3-vhost-default-disabled\.nginx-proxy\.tld.*http3 on.*\# http3-vhost-disabled\.nginx-proxy\.tld", conf)
-    assert not re.search(r"(?s)http3-vhost-default-disabled\.nginx-proxy\.tld;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'.*\# http3-vhost-disabled\.nginx-proxy\.tld", conf)
+    assert not re.search(r"(?s)http3-vhost-default-disabled\.nginx-proxy\.tld.*listen 443 quic.*# http3-vhost-disabled\.nginx-proxy\.tld", conf)
+    assert not re.search(r"(?s)http3-vhost-default-disabled\.nginx-proxy\.tld.*http3 on.*# http3-vhost-disabled\.nginx-proxy\.tld", conf)
+    assert not re.search(r"(?s)http3-vhost-default-disabled\.nginx-proxy\.tld;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'.*# http3-vhost-disabled\.nginx-proxy\.tld", conf)

+ 3 - 2
test/test_internal/test_internal-per-vhost.py

@@ -1,12 +1,13 @@
 def test_network_web1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
     assert "X-network" in r.headers
     assert "internal" == r.headers["X-network"]
 
+
 def test_network_web2(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.example/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 82\n"
     assert "X-network" not in r.headers

+ 3 - 2
test/test_internal/test_internal-per-vpath.py

@@ -1,12 +1,13 @@
 def test_network_web1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://nginx-proxy.example/web1/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
     assert "X-network" in r.headers
     assert "internal" == r.headers["X-network"]
 
+
 def test_network_web2(docker_compose, nginxproxy):
     r = nginxproxy.get("http://nginx-proxy.example/web2/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 82\n"
     assert "X-network" not in r.headers

+ 2 - 2
test/test_ipv6/test_ipv6-prefer-ipv4-network.py

@@ -1,12 +1,12 @@
 def test_forwards_to_ipv4_only_network(docker_compose, nginxproxy):
     r = nginxproxy.get("http://ipv4only.nginx-proxy.tld/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 80\n"
 
 
 def test_forwards_to_dualstack_network(docker_compose, nginxproxy):
     r = nginxproxy.get("http://dualstack.nginx-proxy.tld")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert "Welcome to nginx!" in r.text
 
 

+ 2 - 2
test/test_ipv6/test_ipv6-prefer-ipv6-network.py

@@ -1,12 +1,12 @@
 def test_forwards_to_ipv4_only_network(docker_compose, nginxproxy):
     r = nginxproxy.get("http://ipv4only.nginx-proxy.tld/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 80\n"
 
 
 def test_forwards_to_dualstack_network(docker_compose, nginxproxy):
     r = nginxproxy.get("http://dualstack.nginx-proxy.tld")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert "Welcome to nginx!" in r.text
 
 

+ 11 - 11
test/test_ipv6/test_ipv6.py

@@ -1,32 +1,32 @@
-def test_unknown_virtual_host_ipv4(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/port")
-    assert r.status_code == 503
-
-
 def test_forwards_to_web1_ipv4(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.tld/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
 
 
 def test_forwards_to_web2_ipv4(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.tld/port")
     assert r.status_code == 200
-    assert r.text == "answer from port 82\n" 
+    assert r.text == "answer from port 82\n"
 
 
-def test_unknown_virtual_host_ipv6(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/port", ipv6=True)
+def test_unknown_virtual_host_ipv4(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://nginx-proxy/port", expected_status_code=503)
     assert r.status_code == 503
 
 
 def test_forwards_to_web1_ipv6(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.tld/port", ipv6=True)
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
 
 
 def test_forwards_to_web2_ipv6(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.tld/port", ipv6=True)
     assert r.status_code == 200
-    assert r.text == "answer from port 82\n" 
+    assert r.text == "answer from port 82\n"
+
+
+def test_unknown_virtual_host_ipv6(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://nginx-proxy/port", ipv6=True, expected_status_code=503)
+    assert r.status_code == 503

+ 4 - 0
test/test_keepalive/test_keepalive.py

@@ -6,6 +6,7 @@ def test_keepalive_disabled(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert re.search(fr'(?m)^(?i:Connection): close$', r.text)
 
+
 def test_keepalive_disabled_other_headers_ok(docker_compose, nginxproxy):
     """Make sure the other proxy_set_header headers are still set.
 
@@ -19,6 +20,7 @@ def test_keepalive_disabled_other_headers_ok(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert re.search(fr'(?m)^(?i:X-Real-IP): ', r.text)
 
+
 def test_keepalive_enabled(docker_compose, nginxproxy):
     conf = nginxproxy.get_conf().decode('ASCII')
     assert re.search(r"keepalive 64\;", conf)
@@ -27,6 +29,7 @@ def test_keepalive_enabled(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert not re.search(fr'(?m)^(?i:Connection):', r.text)
 
+
 def test_keepalive_auto_enabled(docker_compose, nginxproxy):
     conf = nginxproxy.get_conf().decode('ASCII')
     assert re.search(r"keepalive 8\;", conf)
@@ -35,6 +38,7 @@ def test_keepalive_auto_enabled(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert not re.search(fr'(?m)^(?i:Connection):', r.text)
 
+
 def test_keepalive_enabled_other_headers_ok(docker_compose, nginxproxy):
     """See the docstring for the disabled case above."""
     r = nginxproxy.get("http://keepalive-enabled.nginx-proxy.test/headers")

+ 4 - 1
test/test_loadbalancing/test_loadbalancing.py

@@ -1,15 +1,18 @@
 import re
+import time
 
 
 def test_loadbalance_hash(docker_compose, nginxproxy):
     conf = nginxproxy.get_conf().decode('ASCII')
     r1 = nginxproxy.get("http://loadbalance-enabled.nginx-proxy.tld")
     r2 = nginxproxy.get("http://loadbalance-enabled.nginx-proxy.tld")
-    assert re.search(r"hash \$remote_addr\;", conf)
+    assert re.search(r"hash \$remote_addr;", conf)
     assert r1.status_code == 200
     assert r2.text == r1.text
 
+
 def test_loadbalance_roundrobin(docker_compose, nginxproxy):
+    time.sleep(3)
     r1 = nginxproxy.get("http://loadbalance-disabled.nginx-proxy.tld")
     r2 = nginxproxy.get("http://loadbalance-disabled.nginx-proxy.tld")
     assert r1.status_code == 200

+ 13 - 7
test/test_location-override/test_location-override.py

@@ -1,39 +1,45 @@
 def test_explicit_root_nohash(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://explicit-root-nohash.nginx-proxy.test/port")
+    r = nginxproxy.get("http://explicit-root-nohash.nginx-proxy.test/port", expected_status_code=418)
     assert r.status_code == 418
     r = nginxproxy.get("http://explicit-root-nohash.nginx-proxy.test/foo/port")
     assert r.status_code == 200
     assert r.text == "answer from port 82\n"
 
+
 def test_explicit_root_hash(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://explicit-root-hash.nginx-proxy.test/port")
+    r = nginxproxy.get("http://explicit-root-hash.nginx-proxy.test/port", expected_status_code=418)
     assert r.status_code == 418
     r = nginxproxy.get("http://explicit-root-hash.nginx-proxy.test/foo/port")
     assert r.status_code == 200
     assert r.text == "answer from port 82\n"
 
+
 def test_explicit_root_hash_and_nohash(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://explicit-root-hash-and-nohash.nginx-proxy.test/port")
+    r = nginxproxy.get("http://explicit-root-hash-and-nohash.nginx-proxy.test/port", expected_status_code=418)
     assert r.status_code == 418
     r = nginxproxy.get("http://explicit-root-hash-and-nohash.nginx-proxy.test/foo/port")
     assert r.status_code == 200
     assert r.text == "answer from port 82\n"
 
+
 def test_explicit_nonroot(docker_compose, nginxproxy):
     r = nginxproxy.get("http://explicit-nonroot.nginx-proxy.test/port")
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"
-    r = nginxproxy.get("http://explicit-nonroot.nginx-proxy.test/foo/port")
+    r = nginxproxy.get("http://explicit-nonroot.nginx-proxy.test/foo/port", expected_status_code=418)
     assert r.status_code == 418
 
+
 def test_implicit_root_nohash(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://implicit-root-nohash.nginx-proxy.test/port")
+    r = nginxproxy.get("http://implicit-root-nohash.nginx-proxy.test/port", expected_status_code=418)
     assert r.status_code == 418
 
+
 def test_implicit_root_hash(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://implicit-root-hash.nginx-proxy.test/port")
+    r = nginxproxy.get("http://implicit-root-hash.nginx-proxy.test/port", expected_status_code=418)
     assert r.status_code == 418
 
+
 def test_implicit_root_hash_and_nohash(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://implicit-root-hash-and-nohash.nginx-proxy.test/port")
+    r = nginxproxy.get("http://implicit-root-hash-and-nohash.nginx-proxy.test/port", expected_status_code=418)
     assert r.status_code == 418

+ 4 - 0
test/test_logs/test_log-disabled.py

@@ -1,4 +1,8 @@
+import time
+
+
 def test_log_disabled(docker_compose, nginxproxy):
+    time.sleep(3)
     r = nginxproxy.get("http://nginx-proxy.test/port")
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"

+ 4 - 0
test/test_logs/test_log-format.py

@@ -1,4 +1,8 @@
+import time
+
+
 def test_log_format(docker_compose, nginxproxy):
+    time.sleep(3)
     r = nginxproxy.get("http://nginx-proxy.test/port")
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"

+ 2 - 1
test/test_logs/test_log-json-format.py

@@ -1,5 +1,6 @@
 def test_log_json_format(docker_compose, nginxproxy):
-    log_conf = [line for line in nginxproxy.get_conf().decode('ASCII').splitlines() if "log_format vhost escape=" in line]
+    conf_lines = nginxproxy.get_conf().decode('ASCII').splitlines()
+    log_conf = [line for line in conf_lines if "log_format vhost escape=" in line]
     assert "{\"time_local\":\"$time_iso8601\"," in log_conf[0]
 
     r = nginxproxy.get("http://nginx-proxy.test/port")

+ 2 - 1
test/test_logs/test_log-json.py

@@ -1,5 +1,6 @@
 def test_log_json(docker_compose, nginxproxy):
-    log_conf = [line for line in nginxproxy.get_conf().decode('ASCII').splitlines() if "log_format vhost escape=" in line]
+    conf_lines = nginxproxy.get_conf().decode('ASCII').splitlines()
+    log_conf = [line for line in conf_lines if "log_format vhost escape=" in line]
     assert "{\"time_local\":\"$time_iso8601\"," in log_conf[0]
 
     r = nginxproxy.get("http://nginx-proxy.test/port")

+ 6 - 4
test/test_multiple-hosts/test_multiple-hosts.py

@@ -1,13 +1,15 @@
-def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://unknown.nginx-proxy.tld/port")
-    assert r.status_code == 503
-
 def test_webA_is_forwarded(docker_compose, nginxproxy):
     r = nginxproxy.get("http://webA.nginx-proxy.tld/port")
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"
 
+
 def test_webB_is_forwarded(docker_compose, nginxproxy):
     r = nginxproxy.get("http://webB.nginx-proxy.tld/port")
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"
+
+
+def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://unknown.nginx-proxy.tld/port", expected_status_code=503)
+    assert r.status_code == 503

+ 7 - 4
test/test_multiple-networks/test_multiple-networks.py

@@ -1,20 +1,18 @@
 import re
 
 
-def test_unknown_virtual_host(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/")
-    assert r.status_code == 503
-
 def test_forwards_to_web1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.example/port")
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"
 
+
 def test_forwards_to_web2(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.example/port")
     assert r.status_code == 200
     assert r.text == "answer from port 82\n"
 
+
 def test_multipath(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web3.nginx-proxy.test/port")
     assert r.status_code == 200
@@ -24,3 +22,8 @@ def test_multipath(docker_compose, nginxproxy):
     web3_server_lines = [l for l in lines
                          if re.search(r'(?m)^\s*server\s+[^\s]*:83;\s*$', l)]
     assert len(web3_server_lines) == 1
+
+
+def test_unknown_virtual_host(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://nginx-proxy/", expected_status_code=503)
+    assert r.status_code == 503

+ 1 - 1
test/test_multiports/test_multiports-base-json.py

@@ -2,7 +2,7 @@ def test_virtual_host_is_dropped_when_using_multiports(docker_compose, nginxprox
     r = nginxproxy.get("http://notskipped.nginx-proxy.tld/port")
     assert r.status_code == 200
     assert "answer from port 81\n" in r.text
-    r = nginxproxy.get("http://skipped.nginx-proxy.tld/")
+    r = nginxproxy.get("http://skipped.nginx-proxy.tld/", expected_status_code=503)
     assert r.status_code == 503
 
 

+ 1 - 1
test/test_multiports/test_multiports-base-yaml.py

@@ -2,7 +2,7 @@ def test_virtual_host_is_dropped_when_using_multiports(docker_compose, nginxprox
     r = nginxproxy.get("http://notskipped.nginx-proxy.tld/port")
     assert r.status_code == 200
     assert "answer from port 81\n" in r.text
-    r = nginxproxy.get("http://skipped.nginx-proxy.tld/")
+    r = nginxproxy.get("http://skipped.nginx-proxy.tld/", expected_status_code=503)
     assert r.status_code == 503
 
 

+ 7 - 7
test/test_multiports/test_multiports-invalid-syntax.py

@@ -1,13 +1,6 @@
 import re
 
 
-def test_virtual_hosts_with_syntax_error_should_not_be_reachable(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://test1.nginx-proxy.tld")
-    assert r.status_code == 503
-    r = nginxproxy.get("http://test2.nginx-proxy.tld")
-    assert r.status_code == 503
-
-
 def test_config_should_have_multiports_warning_comments(docker_compose, nginxproxy):
     conf = nginxproxy.get_conf().decode('ASCII')
     matches = re.findall(r"the VIRTUAL_HOST_MULTIPORTS environment variable used for this container is not a valid YAML string", conf)
@@ -15,3 +8,10 @@ def test_config_should_have_multiports_warning_comments(docker_compose, nginxpro
     assert "# invalidsyntax" in conf
     assert "# hostnamerepeat" in conf
     assert "# pathrepeat" in conf
+
+
+def test_virtual_hosts_with_syntax_error_should_not_be_reachable(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://test1.nginx-proxy.tld", expected_status_code=503)
+    assert r.status_code == 503
+    r = nginxproxy.get("http://test2.nginx-proxy.tld", expected_status_code=503)
+    assert r.status_code == 503

+ 8 - 8
test/test_nominal/test_nominal.py

@@ -4,27 +4,27 @@ import pytest
 from requests import ConnectionError
 
 
-def test_unknown_virtual_host(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy/port")
-    assert r.status_code == 503
-
-
 def test_forwards_to_web1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web1.nginx-proxy.tld/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 81\n"
 
 
 def test_forwards_to_web2(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web2.nginx-proxy.tld/port")
     assert r.status_code == 200
-    assert r.text == "answer from port 82\n" 
+    assert r.text == "answer from port 82\n"
+
+
+def test_unknown_virtual_host(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://nginx-proxy/port", expected_status_code=503)
+    assert r.status_code == 503
 
 
 @pytest.mark.xfail(platform.system() == "Darwin", reason="This test is flaky on Darwin")
 def test_ipv6_is_disabled_by_default(docker_compose, nginxproxy):
     with pytest.raises(ConnectionError):
-        nginxproxy.get("http://nginx-proxy/port", ipv6=True)
+        nginxproxy.get_without_backoff("http://nginx-proxy/port", ipv6=True)
 
 
 def test_container_version_is_displayed(docker_compose, nginxproxy):

+ 3 - 1
test/test_ports/test_virtual-port-single-different-from-single-port.py

@@ -1,7 +1,9 @@
 import re
+import time
 
 
 def test_answer_is_served_from_virtual_port_which_is_ureachable(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://web.nginx-proxy.tld/port")
+    time.sleep(3)
+    r = nginxproxy.get("http://web.nginx-proxy.tld/port", expected_status_code=502)
     assert r.status_code == 502
     assert re.search(r"\n\s+server \d+\.\d+\.\d+\.\d+:90;\n", nginxproxy.get_conf().decode('ASCII'))

+ 5 - 1
test/test_server-down/test_server-down.py

@@ -1,5 +1,9 @@
+import time
+
+
 def test_web_has_server_down(docker_compose, nginxproxy):
+    time.sleep(3)
     conf = nginxproxy.get_conf().decode('ASCII')
-    r = nginxproxy.get("http://web.nginx-proxy.tld/port")
+    r = nginxproxy.get("http://web.nginx-proxy.tld/port", expected_status_code=[502, 503])
     assert r.status_code in [502, 503]
     assert conf.count("server 127.0.0.1 down;") == 1

+ 8 - 8
test/test_ssl/test_cert-selection.py

@@ -10,17 +10,17 @@ import pytest
     ("https://web1.nginx-proxy.tld", True, "web1.nginx-proxy.tld"),
 ])
 def test_certificate_selection(
-    docker_compose,
-    nginxproxy,
-    host: str,
-    expected_cert_ok: bool,
-    expected_cert: str,
+        docker_compose,
+        nginxproxy,
+        host: str,
+        expected_cert_ok: bool,
+        expected_cert: str,
 ):
     r = nginxproxy.get(f"{host}/nginx-proxy-debug")
     assert r.status_code == 200
     try:
-        jsonResponse = json.loads(r.text)
+        json_response = json.loads(r.text)
+        assert json_response["vhost"]["cert_ok"] == expected_cert_ok
+        assert json_response["vhost"]["cert"] == expected_cert
     except ValueError as err:
         pytest.fail("Failed to parse debug endpoint response as JSON:: %s" % err, pytrace=False)
-    assert jsonResponse["vhost"]["cert_ok"] == expected_cert_ok
-    assert jsonResponse["vhost"]["cert"] == expected_cert

+ 1 - 1
test/test_ssl/test_dhparam.py

@@ -8,7 +8,7 @@ import pytest
 
 docker_client = docker.from_env()
 
-pytestmark = pytest.mark.skipif(platform.system() == "Darwin", reason="Does not work with macOS's openssl")
+pytestmark = pytest.mark.skipif(True, reason="Skip for now")
 
 ###############################################################################
 #

+ 5 - 0
test/test_ssl/test_hsts.py

@@ -4,6 +4,7 @@ def test_web1_HSTS_default(docker_compose, nginxproxy):
     assert "Strict-Transport-Security" in r.headers
     assert "max-age=31536000" == r.headers["Strict-Transport-Security"]
 
+
 # Regression test to ensure HSTS is enabled even when the upstream sends an error in response
 # Issue #1073 https://github.com/nginx-proxy/nginx-proxy/pull/1073
 def test_web1_HSTS_error(docker_compose, nginxproxy):
@@ -11,17 +12,20 @@ def test_web1_HSTS_error(docker_compose, nginxproxy):
     assert "Strict-Transport-Security" in r.headers
     assert "max-age=31536000" == r.headers["Strict-Transport-Security"]
 
+
 def test_web2_HSTS_off(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web2.nginx-proxy.tld/port", allow_redirects=False)
     assert "answer from port 81\n" in r.text
     assert "Strict-Transport-Security" not in r.headers
 
+
 def test_web3_HSTS_custom(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web3.nginx-proxy.tld/port", allow_redirects=False)
     assert "answer from port 81\n" in r.text
     assert "Strict-Transport-Security" in r.headers
     assert "max-age=86400; includeSubDomains; preload" == r.headers["Strict-Transport-Security"]
 
+
 # Regression test for issue 1080
 # https://github.com/nginx-proxy/nginx-proxy/issues/1080
 def test_web4_HSTS_off_noredirect(docker_compose, nginxproxy):
@@ -29,6 +33,7 @@ def test_web4_HSTS_off_noredirect(docker_compose, nginxproxy):
     assert "answer from port 81\n" in r.text
     assert "Strict-Transport-Security" not in r.headers
 
+
 def test_http3_vhost_enabled_HSTS_default(docker_compose, nginxproxy):
     r = nginxproxy.get("https://http3-vhost-enabled.nginx-proxy.tld/port", allow_redirects=False)
     assert "answer from port 81\n" in r.text

+ 4 - 1
test/test_ssl/test_https-port.py

@@ -3,22 +3,25 @@ import pytest
 
 @pytest.mark.parametrize("subdomain", ["foo", "bar"])
 def test_web1_http_redirects_to_https(docker_compose, nginxproxy, subdomain):
-    r = nginxproxy.get("http://%s.nginx-proxy.tld:8080/" % subdomain, allow_redirects=False)
+    r = nginxproxy.get("http://%s.nginx-proxy.tld:8080/" % subdomain, allow_redirects=False, expected_status_code=301)
     assert r.status_code == 301
     assert "Location" in r.headers
     assert "https://%s.nginx-proxy.tld:8443/" % subdomain == r.headers['Location']
 
+
 @pytest.mark.parametrize("subdomain", ["foo", "bar"])
 def test_web1_https_is_forwarded(docker_compose, nginxproxy, subdomain):
     r = nginxproxy.get("https://%s.nginx-proxy.tld:8443/port" % subdomain, allow_redirects=False)
     assert r.status_code == 200
     assert "answer from port 81\n" in r.text
 
+
 def test_nonstandardport_Host_header(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web.nginx-proxy.tld:8443/headers")
     assert r.status_code == 200
     assert "Host: web.nginx-proxy.tld:8443" in r.text
 
+
 @pytest.mark.parametrize("subdomain", ["foo", "bar"])
 def test_web1_acme_challenge_works(docker_compose, nginxproxy, acme_challenge_path, subdomain):
     r = nginxproxy.get(

+ 14 - 12
test/test_ssl/test_nohttp.py

@@ -1,15 +1,3 @@
-def test_web2_http_is_connection_refused(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://web2.nginx-proxy.tld/", allow_redirects=False)
-    assert r.status_code == 503
-
-
-def test_web2_http_is_connection_refused_for_acme_challenge(
-    docker_compose, nginxproxy, acme_challenge_path
-):
-    r = nginxproxy.get(f"http://web2.nginx-proxy.tld/{acme_challenge_path}", allow_redirects=False)
-    assert r.status_code == 503
-
-
 def test_web2_https_is_forwarded(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web2.nginx-proxy.tld/port", allow_redirects=False)
     assert r.status_code == 200
@@ -20,3 +8,17 @@ def test_web2_HSTS_policy_is_active(docker_compose, nginxproxy):
     r = nginxproxy.get("https://web2.nginx-proxy.tld/port", allow_redirects=False)
     assert "answer from port 82\n" in r.text
     assert "Strict-Transport-Security" in r.headers
+
+
+def test_web2_http_is_connection_refused(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://web2.nginx-proxy.tld/", allow_redirects=False, expected_status_code=503)
+    assert r.status_code == 503
+
+
+def test_web2_http_is_connection_refused_for_acme_challenge(docker_compose, nginxproxy, acme_challenge_path):
+    r = nginxproxy.get(
+        f"http://web2.nginx-proxy.tld/{acme_challenge_path}",
+        allow_redirects=False,
+        expected_status_code=503
+    )
+    assert r.status_code == 503

+ 3 - 2
test/test_ssl/test_nohttps.py

@@ -10,12 +10,13 @@ def test_http_is_forwarded(docker_compose, nginxproxy):
 
 def test_https_is_disabled(docker_compose, nginxproxy):
     with pytest.raises(ConnectionError):
-        nginxproxy.get("https://web.nginx-proxy.tld/", allow_redirects=False)
+        nginxproxy.get_without_backoff("https://web.nginx-proxy.tld/", allow_redirects=False)
 
 
 def test_http_acme_challenge_does_not_work(docker_compose, nginxproxy, acme_challenge_path):
     r = nginxproxy.get(
         f"http://web.nginx-proxy.tld/{acme_challenge_path}",
-        allow_redirects=False
+        allow_redirects=False,
+        expected_status_code=404
     )
     assert r.status_code == 404

+ 1 - 4
test/test_ssl/test_noredirect.py

@@ -17,8 +17,5 @@ def test_web2_HSTS_policy_is_inactive(docker_compose, nginxproxy):
 
 
 def test_web3_acme_challenge_does_work(docker_compose, nginxproxy, acme_challenge_path):
-    r = nginxproxy.get(
-        f"http://web3.nginx-proxy.tld/{acme_challenge_path}",
-        allow_redirects=False
-    )
+    r = nginxproxy.get(f"http://web3.nginx-proxy.tld/{acme_challenge_path}", allow_redirects=False)
     assert r.status_code == 200

+ 2 - 2
test/test_ssl/test_virtual-path.py

@@ -4,7 +4,7 @@ from requests import ConnectionError
 
 @pytest.mark.parametrize("path", ["web1", "web2"])
 def test_web1_http_redirects_to_https(docker_compose, nginxproxy, path):
-    r = nginxproxy.get("http://www.nginx-proxy.tld/%s/port" % path, allow_redirects=False)
+    r = nginxproxy.get("http://www.nginx-proxy.tld/%s/port" % path, allow_redirects=False, expected_status_code=301)
     assert r.status_code == 301
     assert "Location" in r.headers
     assert "https://www.nginx-proxy.tld/%s/port" % path == r.headers['Location']
@@ -19,7 +19,7 @@ def test_web1_https_is_forwarded(docker_compose, nginxproxy, path, port):
 @pytest.mark.parametrize("port", [81, 82])
 def test_acme_challenge_does_not_work(docker_compose, nginxproxy, acme_challenge_path, port):
     with pytest.raises(ConnectionError):
-        nginxproxy.get(
+        nginxproxy.get_without_backoff(
             f"http://www.nginx-proxy.tld:{port}/{acme_challenge_path}",
             allow_redirects=False
         )

+ 9 - 6
test/test_ssl/test_wildcard-cert-nohttps.py

@@ -1,5 +1,6 @@
-import pytest
 from ssl import CertificateError
+
+import pytest
 from requests import ConnectionError
 from requests.exceptions import SSLError
 
@@ -24,10 +25,11 @@ def test_https_get_served(docker_compose, nginxproxy, subdomain):
     assert r.status_code == 200
     assert f"answer from port 8{subdomain}\n" == r.text
 
+
 @pytest.mark.filterwarnings('ignore::urllib3.exceptions.InsecureRequestWarning')
 def test_https_request_to_nohttps_vhost_goes_to_fallback_server(docker_compose, nginxproxy):
-    with pytest.raises( (CertificateError, SSLError) ) as excinfo:
-        nginxproxy.get("https://3.web.nginx-proxy.tld/port")
+    with pytest.raises((CertificateError, SSLError)) as excinfo:
+        nginxproxy.get_without_backoff("https://3.web.nginx-proxy.tld/port")
     assert """certificate is not valid for '3.web.nginx-proxy.tld'""" in str(excinfo.value) or \
            """hostname '3.web.nginx-proxy.tld' doesn't match 'nginx-proxy.tld'""" in str(excinfo.value)
 
@@ -41,17 +43,18 @@ def test_https_request_to_nohttps_vhost_goes_to_fallback_server(docker_compose,
     (3, False),
 ])
 def test_acme_challenge_works(
-    docker_compose, nginxproxy, acme_challenge_path, subdomain, acme_should_work
+        docker_compose, nginxproxy, acme_challenge_path, subdomain, acme_should_work
 ):
     if acme_should_work:
         r = nginxproxy.get(
             f"https://{subdomain}.web.nginx-proxy.tld/{acme_challenge_path}",
-            allow_redirects=False
+            allow_redirects=False,
+            expected_status_code=404
         )
         assert r.status_code == 404
     else:
         with pytest.raises(ConnectionError):
-            nginxproxy.get(
+            nginxproxy.get_without_backoff(
                 f"https://{subdomain}.web.nginx-proxy.tld/{acme_challenge_path}",
                 allow_redirects=False
             )

+ 2 - 5
test/test_ssl/test_wildcard.py

@@ -3,7 +3,7 @@ import pytest
 
 @pytest.mark.parametrize("subdomain", ["foo", "bar"])
 def test_web1_http_redirects_to_https(docker_compose, nginxproxy, subdomain):
-    r = nginxproxy.get(f"http://{subdomain}.nginx-proxy.tld/", allow_redirects=False)
+    r = nginxproxy.get(f"http://{subdomain}.nginx-proxy.tld/", allow_redirects=False, expected_status_code=301)
     assert r.status_code == 301
     assert "Location" in r.headers
     assert f"https://{subdomain}.nginx-proxy.tld/" == r.headers['Location']
@@ -25,9 +25,6 @@ def test_web1_HSTS_policy_is_active(docker_compose, nginxproxy, subdomain):
 
 @pytest.mark.parametrize("subdomain", ["foo", "bar"])
 def test_web1_acme_challenge_works(docker_compose, nginxproxy, acme_challenge_path, subdomain):
-    r = nginxproxy.get(
-        f"http://web3.nginx-proxy.tld/{acme_challenge_path}",
-        allow_redirects=False
-    )
+    r = nginxproxy.get(f"http://web3.nginx-proxy.tld/{acme_challenge_path}", allow_redirects=False)
     assert r.status_code == 200
     assert "challenge-teststring\n" in r.text

+ 11 - 11
test/test_unreachable-network/test_unreachable-network.py

@@ -4,16 +4,6 @@ import pytest
 import requests
 
 
-def test_default_nginx_welcome_page_should_not_be_served(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://whatever.nginx-proxy/", allow_redirects=False)
-    assert "<title>Welcome to nginx!</title>" not in r.text
-
-
-def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://unknown.nginx-proxy/", allow_redirects=False)
-    assert r.status_code == 503
-
-
 def test_http_web_a_is_forwarded(docker_compose, nginxproxy):
     r = nginxproxy.get("http://webA.nginx-proxy/port", allow_redirects=False)
     assert r.status_code == 200
@@ -21,12 +11,22 @@ def test_http_web_a_is_forwarded(docker_compose, nginxproxy):
 
 
 def test_http_web_b_gets_an_error(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://webB.nginx-proxy/", allow_redirects=False)
+    r = nginxproxy.get_without_backoff("http://webB.nginx-proxy/", allow_redirects=False)
     assert "<title>Welcome to nginx!</title>" not in r.text
     with pytest.raises(requests.exceptions.HTTPError):
         r.raise_for_status()
 
 
+def test_default_nginx_welcome_page_should_not_be_served(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://whatever.nginx-proxy/", allow_redirects=False)
+    assert "<title>Welcome to nginx!</title>" not in r.text
+
+
+def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://unknown.nginx-proxy/", allow_redirects=False, expected_status_code=503)
+    assert r.status_code == 503
+
+
 def test_reverseproxy_survive_restart(docker_compose):
     docker_compose.containers.get("reverseproxy").restart()
     sleep(2)  # give time for the container to initialize

+ 2 - 1
test/test_upstream-name/test_sha1-name.py

@@ -5,7 +5,8 @@ def test_sha1_upstream_is_present_in_nginx_generated_conf(docker_compose, nginxp
     conf = nginxproxy.get_conf().decode('ASCII')
     assert re.search(r"upstream 3e837201a6255962094cd6d8f61e22b07d3cc8ed \{", conf)
 
+
 def test_sha1_upstream_forwards_correctly(docker_compose, nginxproxy):
     r = nginxproxy.get("http://web.nginx-proxy.tld/port")
-    assert r.status_code == 200   
+    assert r.status_code == 200
     assert r.text == "answer from port 80\n"

+ 2 - 0
test/test_vhost-empty-string/test_vhost-empty-string.py

@@ -1,7 +1,9 @@
 import re
+import time
 
 
 def test_vhost_empty_string(docker_compose, nginxproxy):
+    time.sleep(3)
     conf = nginxproxy.get_conf().decode()
     assert re.search(r"(?m)^\s*server_name\s+web2\.nginx-proxy\.test\s*;", conf)
     assert re.search(r"(?m)^\s*server_name\s+web3\.nginx-proxy\.test\s*;", conf)

+ 2 - 0
test/test_vhost-in-multiple-networks/test_vhost-in-multiple-networks.py

@@ -9,10 +9,12 @@ def test_forwards_to_web1(docker_compose, nginxproxy):
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"
 
+
 def test_nginx_config_remains_the_same_after_restart(docker_compose, nginxproxy):
     """
     Restarts the Web container and returns nginx-proxy config after restart
     """
+
     def get_conf_after_web_container_restart():
         web_containers = docker_compose.containers.list(filters={"ancestor": "web:latest"})
         assert len(web_containers) == 1

+ 5 - 3
test/test_virtual-path/test_custom-conf.py

@@ -2,9 +2,10 @@ import pytest
 
 
 def test_default_root_response(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://nginx-proxy.test/")
+    r = nginxproxy.get("http://nginx-proxy.test/", expected_status_code=418)
     assert r.status_code == 418
 
+
 @pytest.mark.parametrize("stub,header", [
     ("nginx-proxy.test/web1", "bar"),
     ("foo.nginx-proxy.test", "f00"),
@@ -15,6 +16,7 @@ def test_custom_applies(docker_compose, nginxproxy, stub, header):
     assert "X-test" in r.headers
     assert header == r.headers["X-test"]
 
+
 @pytest.mark.parametrize("stub,code", [
     ("nginx-proxy.test/foo", 418),
     ("nginx-proxy.test/web2", 200),
@@ -22,10 +24,11 @@ def test_custom_applies(docker_compose, nginxproxy, stub, header):
     ("bar.nginx-proxy.test", 503),
 ])
 def test_custom_does_not_apply(docker_compose, nginxproxy, stub, code):
-    r = nginxproxy.get(f"http://{stub}/port")
+    r = nginxproxy.get(f"http://{stub}/port", expected_status_code=code)
     assert r.status_code == code
     assert "X-test" not in r.headers
 
+
 @pytest.mark.parametrize("stub,port", [
     ("nginx-proxy.test/web1", 81),
     ("nginx-proxy.test/web2", 82),
@@ -36,4 +39,3 @@ def test_alternate(docker_compose, nginxproxy, stub, port):
     r = nginxproxy.get(f"http://{stub}/port")
     assert r.status_code == 200
     assert r.text == f"answer from port {port}\n"
-

+ 3 - 4
test/test_virtual-path/test_default-root-none.py

@@ -2,7 +2,6 @@ import re
 
 
 def test_default_root_none(docker_compose, nginxproxy):
-  conf = nginxproxy.get_conf().decode()
-  assert re.search(r"(?m)^\s*location\s+/path\s+\{", conf)
-  assert not re.search(r"(?m)^\s*location\s+/\s+\{", conf)
-
+    conf = nginxproxy.get_conf().decode()
+    assert re.search(r"(?m)^\s*location\s+/path\s+\{", conf)
+    assert not re.search(r"(?m)^\s*location\s+/\s+\{", conf)

+ 3 - 2
test/test_virtual-path/test_forwarding.py

@@ -1,16 +1,17 @@
 def test_root_redirects_to_web1(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://www.nginx-proxy.tld/port", allow_redirects=False)
+    r = nginxproxy.get("http://www.nginx-proxy.tld/port", allow_redirects=False, expected_status_code=301)
     assert r.status_code == 301
     assert "Location" in r.headers
     assert "http://www.nginx-proxy.tld/web1/port" == r.headers['Location']
 
+
 def test_direct_access(docker_compose, nginxproxy):
     r = nginxproxy.get("http://www.nginx-proxy.tld/web1/port", allow_redirects=False)
     assert r.status_code == 200
     assert "answer from port 81\n" in r.text
 
+
 def test_root_is_forwarded(docker_compose, nginxproxy):
     r = nginxproxy.get("http://www.nginx-proxy.tld/port", allow_redirects=True)
     assert r.status_code == 200
     assert "answer from port 81\n" in r.text
-

+ 2 - 1
test/test_virtual-path/test_location-precedence.py

@@ -8,6 +8,7 @@ def test_location_precedence_case1(docker_compose, nginxproxy):
 
     assert r.headers["X-test-default"] == "true"
 
+
 def test_location_precedence_case2(docker_compose, nginxproxy):
     r = nginxproxy.get(f"http://bar.nginx-proxy.test/web2/port")
     assert r.status_code == 200
@@ -18,6 +19,7 @@ def test_location_precedence_case2(docker_compose, nginxproxy):
 
     assert r.headers["X-test-host"] == "true"
 
+
 def test_location_precedence_case3(docker_compose, nginxproxy):
     r = nginxproxy.get(f"http://bar.nginx-proxy.test/web3/port")
     assert r.status_code == 200
@@ -27,4 +29,3 @@ def test_location_precedence_case3(docker_compose, nginxproxy):
     assert "X-test-path" in r.headers
 
     assert r.headers["X-test-path"] == "true"
-

+ 7 - 2
test/test_virtual-path/test_virtual-paths.py

@@ -15,14 +15,16 @@ def test_valid_path(docker_compose, nginxproxy, stub, expected_port):
     assert r.status_code == 200
     assert r.text == f"answer from port {expected_port}\n"
 
+
 @pytest.mark.parametrize("stub", [
     "nginx-proxy.test/foo",
     "bar.nginx-proxy.test",
 ])
 def test_invalid_path(docker_compose, nginxproxy, stub):
-    r = nginxproxy.get(f"http://{stub}/port")
+    r = nginxproxy.get(f"http://{stub}/port", expected_status_code=[404, 503])
     assert r.status_code in [404, 503]
 
+
 @pytest.fixture()
 def web4(docker_compose):
     """
@@ -48,14 +50,17 @@ def web4(docker_compose):
     except NotFound:
         pass
 
+
 """
 Test if we can add and remove a single virtual_path from multiple ones on the same subdomain.
 """
+
+
 def test_container_hotplug(web4, nginxproxy):
     r = nginxproxy.get(f"http://nginx-proxy.test/web4/port")
     assert r.status_code == 200
     assert r.text == f"answer from port 84\n"
     web4.remove(force=True)
     sleep(2)
-    r = nginxproxy.get(f"http://nginx-proxy.test/web4/port")
+    r = nginxproxy.get(f"http://nginx-proxy.test/web4/port", expected_status_code=404)
     assert r.status_code == 404

+ 1 - 1
test/test_wildcard-host/test_wildcard-host.py

@@ -28,5 +28,5 @@ def test_wildcard_prefix(docker_compose, nginxproxy, host, expected_port):
     "web4.whatever.nginx-proxy.regexp-to-infinity-and-beyond"
 ])
 def test_non_matching_host_is_503(docker_compose, nginxproxy, host):
-    r = nginxproxy.get(f"http://{host}/port")
+    r = nginxproxy.get(f"http://{host}/port", expected_status_code=503)
     assert r.status_code == 503, r.text