Browse Source

Merge pull request #2570 from nginx-proxy/test/refactor-darwin

tests: factor out base nginx-proxy config and enable local testing on macOS / Darwin
Nicolas Duchon 5 months ago
parent
commit
691724c81f
100 changed files with 520 additions and 524 deletions
  1. 38 7
      test/README.md
  2. 9 0
      test/compose.base.yml
  3. 118 58
      test/conftest.py
  4. 6 0
      test/test_acme-http-challenge-location/compose.base.override.yml
  5. 4 9
      test/test_acme-http-challenge-location/test_acme-http-challenge-location-disabled.yml
  6. 0 7
      test/test_acme-http-challenge-location/test_acme-http-challenge-location-enabled-is-default.yml
  7. 4 9
      test/test_acme-http-challenge-location/test_acme-http-challenge-location-legacy.yml
  8. 2 3
      test/test_custom-error-page/test_custom-error-page.yml
  9. 2 3
      test/test_custom/test_defaults-location.yml
  10. 1 2
      test/test_custom/test_defaults.yml
  11. 2 3
      test/test_custom/test_location-per-vhost.yml
  12. 2 3
      test/test_custom/test_per-vhost.yml
  13. 1 2
      test/test_custom/test_proxy-wide.yml
  14. 0 3
      test/test_debug-endpoint/test_global.yml
  15. 0 5
      test/test_debug-endpoint/test_per-container.yml
  16. 4 9
      test/test_default-host/test_default-host.yml
  17. 6 7
      test/test_docker-unix-socket/test_docker-unix-socket.yml
  18. 9 5
      test/test_dockergen/test_dockergen.base.yml
  19. 1 5
      test/test_enable-http-on-missing-cert/test_enable-http-on-missing-cert.yml
  20. 0 6
      test/test_events/test_events.yml
  21. 9 0
      test/test_fallback/test_fallback.data/compose.base.yml
  22. 2 3
      test/test_fallback/test_fallback.data/custom-fallback.yml
  23. 2 3
      test/test_fallback/test_fallback.data/nodefault.yml
  24. 2 3
      test/test_fallback/test_fallback.data/nohttp-on-app.yml
  25. 2 3
      test/test_fallback/test_fallback.data/nohttp-with-missing-cert.yml
  26. 2 3
      test/test_fallback/test_fallback.data/nohttp.yml
  27. 1 4
      test/test_fallback/test_fallback.data/nohttps-on-app.yml
  28. 1 4
      test/test_fallback/test_fallback.data/nohttps.yml
  29. 2 3
      test/test_fallback/test_fallback.data/untrusteddefault.yml
  30. 2 3
      test/test_fallback/test_fallback.data/withdefault.yml
  31. 13 13
      test/test_fallback/test_fallback.py
  32. 70 0
      test/test_headers/certs/default.crt
  33. 27 0
      test/test_headers/certs/default.key
  34. 0 5
      test/test_headers/test_http.yml
  35. 5 11
      test/test_headers/test_https.yml
  36. 5 8
      test/test_host-network-mode/test_host-network-mode.yml
  37. 3 0
      test/test_host-network-mode/test_proxy-host-network-mode.py
  38. 5 8
      test/test_host-network-mode/test_proxy-host-network-mode.yml
  39. 5 0
      test/test_htpasswd/compose.base.override.yml
  40. 0 7
      test/test_htpasswd/test_htpasswd-regex-virtual-host.yml
  41. 0 7
      test/test_htpasswd/test_htpasswd-virtual-host.yml
  42. 0 7
      test/test_htpasswd/test_htpasswd-virtual-path.yml
  43. 6 7
      test/test_http-port/test_http-port.yml
  44. 4 7
      test/test_http2/test_http2-global-disabled.yml
  45. 4 7
      test/test_http3/test_http3-global-disabled.yml
  46. 4 7
      test/test_http3/test_http3-global-enabled.yml
  47. 4 5
      test/test_http3/test_http3-vhost.yml
  48. 5 0
      test/test_internal/compose.base.override.yml
  49. 0 6
      test/test_internal/test_internal-per-vhost.yml
  50. 0 5
      test/test_internal/test_internal-per-vpath.yml
  51. 8 10
      test/test_ipv6/test_ipv6-prefer-ipv4-network.yml
  52. 10 12
      test/test_ipv6/test_ipv6-prefer-ipv6-network.yml
  53. 10 0
      test/test_ipv6/test_ipv6.py
  54. 6 8
      test/test_ipv6/test_ipv6.yml
  55. 5 7
      test/test_keepalive/test_keepalive.yml
  56. 0 5
      test/test_loadbalancing/test_loadbalancing.yml
  57. 2 3
      test/test_location-override/test_location-override.yml
  58. 1 1
      test/test_logs/test_log-disabled.py
  59. 4 8
      test/test_logs/test_log-disabled.yml
  60. 1 1
      test/test_logs/test_log-format.py
  61. 4 8
      test/test_logs/test_log-format.yml
  62. 1 1
      test/test_logs/test_log-json-format.py
  63. 4 8
      test/test_logs/test_log-json-format.yml
  64. 1 1
      test/test_logs/test_log-json.py
  65. 4 8
      test/test_logs/test_log-json.yml
  66. 0 5
      test/test_multiple-hosts/test_multiple-hosts.yml
  67. 0 3
      test/test_multiple-networks/test_multiple-networks.yml
  68. 0 5
      test/test_multiports/test_multiports-base-json.yml
  69. 0 5
      test/test_multiports/test_multiports-base-yaml.yml
  70. 0 5
      test/test_multiports/test_multiports-invalid-syntax.yml
  71. 0 5
      test/test_multiports/test_multiports-merge.yml
  72. 6 0
      test/test_nominal/test_nominal.py
  73. 4 7
      test/test_nominal/test_nominal.yml
  74. 0 5
      test/test_ports/test_default-80.yml
  75. 0 5
      test/test_ports/test_single-port-not-80.yml
  76. 0 5
      test/test_ports/test_virtual-port-single-different-from-single-port.yml
  77. 0 5
      test/test_ports/test_virtual-port.yml
  78. 2 2
      test/test_raw-ip-vhost/test_raw-ip-vhost.py
  79. 10 12
      test/test_raw-ip-vhost/test_raw-ip-vhost.yml
  80. 0 5
      test/test_server-down/test_load-balancing.yml
  81. 0 5
      test/test_server-down/test_no-server-down.yml
  82. 0 5
      test/test_server-down/test_server-down.yml
  83. 0 0
      test/test_ssl/certs_wildcard_nohttps/default.crt
  84. 0 0
      test/test_ssl/certs_wildcard_nohttps/default.key
  85. 0 0
      test/test_ssl/certs_wildcard_nohttps/web.nginx-proxy.tld.crt
  86. 0 0
      test/test_ssl/certs_wildcard_nohttps/web.nginx-proxy.tld.key
  87. 6 0
      test/test_ssl/compose.base.override.yml
  88. 10 11
      test/test_ssl/test_cert-selection.yml
  89. 4 0
      test/test_ssl/test_dhparam.base.yml
  90. 6 1
      test/test_ssl/test_dhparam.py
  91. 0 6
      test/test_ssl/test_hsts.yml
  92. 8 10
      test/test_ssl/test_https-port.yml
  93. 0 7
      test/test_ssl/test_nohttp.yml
  94. 0 6
      test/test_ssl/test_nohttps.yml
  95. 0 7
      test/test_ssl/test_noredirect.yml
  96. 0 7
      test/test_ssl/test_virtual-path.yml
  97. 0 0
      test/test_ssl/test_wildcard-cert-nohttps.py
  98. 9 6
      test/test_ssl/test_wildcard-cert-nohttps.yml
  99. 0 7
      test/test_ssl/test_wildcard.yml
  100. 0 6
      test/test_ssl/wildcard_cert_and_nohttps/README.md

+ 38 - 7
test/README.md

@@ -57,13 +57,39 @@ This test suite uses [pytest](http://doc.pytest.org/en/latest/). The [conftest.p
 
 ### docker_compose fixture
 
-When using the `docker_compose` fixture in a test, pytest will try to find a yml file named after your test module filename. For instance, if your test module is `test_example.py`, then the `docker_compose` fixture will try to load a `test_example.yml` [docker compose file](https://docs.docker.com/compose/compose-file/).
+When using the `docker_compose` fixture in a test, pytest will try to start the [Docker Compose](https://docs.docker.com/compose/) services corresponding to the current test module, based on the test module filename.
 
-Once the docker compose file found, the fixture will remove all containers, run `docker compose up`, and finally your test will be executed.
+By default, if your test module file is `test/test_subdir/test_example.py`, then the `docker_compose` fixture will try to load the following files, [merging them](https://docs.docker.com/reference/compose-file/merge/) in this order:
 
-The fixture will run the _docker compose_ command with the `-f` option to load the given compose file. So you can test your docker compose file syntax by running it yourself with:
+1. `test/compose.base.yml`
+2. `test/test_subdir/compose.base.override.yml` (if it exists)
+3. `test/test_subdir/test_example.yml`
 
-    docker compose -f test_example.yml up -d
+The fixture will run the _docker compose_ command with the `-f` option to load the given compose files. So you can test your docker compose file syntax by running it yourself with:
+
+    docker compose -f test/compose.base.yml -f test/test_subdir/test_example.yml up -d
+
+The first file contains the base configuration of the nginx-proxy container common to most tests:
+
+```yaml
+services:
+  nginx-proxy:
+    image: nginxproxy/nginx-proxy:test
+    container_name: nginx-proxy
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+    ports:
+      - "80:80"
+      - "443:443"
+```
+
+The second optional file allow you to override this base configuration for all test modules in a subfolder.
+
+The third file contains the services and overrides specific to a given test module.
+
+This automatic merge can be bypassed by using a file named `test_example.base.yml` (instead of `test_example.yml`). When this file exist, it will be the only one used by the test and no merge with other compose files will automatically occur.
+
+The `docker_compose` fixture also set the `PYTEST_MODULE_PATH` environment variable to the absolute path of the current test module directory, so it can be used to mount files or directory relatives to the current test.
 
 In the case you are running pytest from within a docker container, the `docker_compose` fixture will make sure the container running pytest is attached to all docker networks. That way, your test will be able to reach any of them.
 
@@ -71,7 +97,10 @@ In your tests, you can use the `docker_compose` variable to query and command th
 
 Also this fixture alters the way the python interpreter resolves domain names to IP addresses in the following ways:
 
-Any domain name containing the substring `nginx-proxy` will resolve to the IP address of the container that was created from the `nginxproxy/nginx-proxy:test` image. So all the following domain names will resolve to the nginx-proxy container in tests:
+Any domain name containing the substring `nginx-proxy` will resolve to `127.0.0.1` if the tests are executed on a Darwin (macOS) system, otherwise the IP address of the container that was created from the `nginxproxy/nginx-proxy:test` image.
+
+So, in tests, all the following domain names will resolve to either localhost or the nginx-proxy container's IP:
+
 - `nginx-proxy`
 - `nginx-proxy.com`
 - `www.nginx-proxy.com`
@@ -80,14 +109,16 @@ Any domain name containing the substring `nginx-proxy` will resolve to the IP ad
 - `whatever.nginx-proxyooooooo`
 - ...
 
-Any domain name ending with `XXX.container.docker` will resolve to the IP address of the XXX container.
+Any domain name ending with `XXX.container.docker` will resolve to `127.0.0.1` if the tests are executed on a Darwin (macOS) system, otherwise the IP address of the container named `XXX`.
+
+So, on a non-Darwin system:
+
 - `web1.container.docker` will resolve to the IP address of the `web1` container
 - `f00.web1.container.docker` will resolve to the IP address of the `web1` container
 - `anything.whatever.web2.container.docker` will resolve to the IP address of the `web2` container
 
 Otherwise, domain names are resoved as usual using your system DNS resolver.
 
-
 ### nginxproxy fixture
 
 The `nginxproxy` fixture will provide you with a replacement for the python [requests](https://pypi.python.org/pypi/requests/) module. This replacement will just repeat up to 30 times a requests if it receives the HTTP error 404 or 502. This error occurs when you try to send queries to nginx-proxy too early after the container creation.

+ 9 - 0
test/compose.base.yml

@@ -0,0 +1,9 @@
+services:
+  nginx-proxy:
+    image: nginxproxy/nginx-proxy:test
+    container_name: nginx-proxy
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+    ports:
+      - "80:80"
+      - "443:443"

+ 118 - 58
test/conftest.py

@@ -1,11 +1,14 @@
 import contextlib
 import logging
 import os
+import pathlib
+import platform
 import re
 import shlex
 import socket
 import subprocess
 import time
+from io import StringIO
 from typing import Iterator, List, Optional
 
 import backoff
@@ -20,12 +23,13 @@ from packaging.version import Version
 from requests import Response
 from urllib3.util.connection import HAS_IPV6
 
+
 logging.basicConfig(level=logging.INFO)
 logging.getLogger('backoff').setLevel(logging.INFO)
 logging.getLogger('DNS').setLevel(logging.DEBUG)
 logging.getLogger('requests.packages.urllib3.connectionpool').setLevel(logging.WARN)
 
-CA_ROOT_CERTIFICATE = os.path.join(os.path.dirname(__file__), 'certs/ca-root.crt')
+CA_ROOT_CERTIFICATE = pathlib.Path(__file__).parent.joinpath("certs/ca-root.crt")
 PYTEST_RUNNING_IN_CONTAINER = os.environ.get('PYTEST_RUNNING_IN_CONTAINER') == "1"
 FORCE_CONTAINER_IPV6 = False  # ugly global state to consider containers' IPv6 address instead of IPv4
 
@@ -71,8 +75,8 @@ class RequestsForDocker:
     """
     def __init__(self):
         self.session = requests.Session()
-        if os.path.isfile(CA_ROOT_CERTIFICATE):
-            self.session.verify = CA_ROOT_CERTIFICATE
+        if CA_ROOT_CERTIFICATE.is_file():
+            self.session.verify = CA_ROOT_CERTIFICATE.as_posix()
 
     @staticmethod
     def get_nginx_proxy_container() -> Container:
@@ -217,8 +221,8 @@ def nginx_proxy_dns_resolver(domain_name: str) -> Optional[str]:
 
 def docker_container_dns_resolver(domain_name: str) -> Optional[str]:
     """
-    if domain name is of the form "XXX.container.docker" or "anything.XXX.container.docker", return the ip address of the docker container
-    named XXX.
+    if domain name is of the form "XXX.container.docker" or "anything.XXX.container.docker",
+    return the ip address of the docker container named XXX.
 
     :return: IP or None
     """
@@ -248,7 +252,10 @@ def monkey_patch_urllib_dns_resolver():
     """
     Alter the behavior of the urllib DNS resolver so that any domain name
     containing substring 'nginx-proxy' will resolve to the IP address
-    of the container created from image 'nginxproxy/nginx-proxy:test'.
+    of the container created from image 'nginxproxy/nginx-proxy:test',
+    or to 127.0.0.1 on Darwin.
+
+    see https://docs.docker.com/desktop/features/networking/#i-want-to-connect-to-a-container-from-the-host
     """
     prv_getaddrinfo = socket.getaddrinfo
     dns_cache = {}
@@ -262,7 +269,12 @@ def monkey_patch_urllib_dns_resolver():
             pytest.skip("This system does not support IPv6")
 
         # custom DNS resolvers
-        ip = nginx_proxy_dns_resolver(args[0])
+        ip = None
+        # Docker Desktop can't route traffic directly to Linux containers.
+        if platform.system() == "Darwin":
+            ip = "127.0.0.1"
+        if ip is None:
+            ip = nginx_proxy_dns_resolver(args[0])
         if ip is None:
             ip = docker_container_dns_resolver(args[0])
         if ip is not None:
@@ -298,20 +310,40 @@ def get_nginx_conf_from_container(container: Container) -> bytes:
         return conffile.read()
 
 
-def docker_compose_up(compose_file: str):
-    logging.info(f'{DOCKER_COMPOSE} -f {compose_file} up -d')
+def __prepare_and_execute_compose_cmd(compose_files: List[str], project_name: str, cmd: str):
+    """
+    Prepare and execute the Docker Compose command with the provided compose files and project name.
+    """
+    compose_cmd = StringIO()
+    compose_cmd.write(DOCKER_COMPOSE)
+    compose_cmd.write(f" --project-name {project_name}")
+    for compose_file in compose_files:
+        compose_cmd.write(f" --file {compose_file}")
+    compose_cmd.write(f" {cmd}")
+
+    logging.info(compose_cmd.getvalue())
     try:
-        subprocess.check_output(shlex.split(f'{DOCKER_COMPOSE} -f {compose_file} up -d'), stderr=subprocess.STDOUT)
+        subprocess.check_output(shlex.split(compose_cmd.getvalue()), stderr=subprocess.STDOUT)
     except subprocess.CalledProcessError as e:
-        pytest.fail(f"Error while running '{DOCKER_COMPOSE} -f {compose_file} up -d':\n{e.output}", pytrace=False)
+        pytest.fail(f"Error while running '{compose_cmd.getvalue()}':\n{e.output}", pytrace=False)
 
 
-def docker_compose_down(compose_file: str):
-    logging.info(f'{DOCKER_COMPOSE} -f {compose_file} down -v')
-    try:
-        subprocess.check_output(shlex.split(f'{DOCKER_COMPOSE} -f {compose_file} down -v'), stderr=subprocess.STDOUT)
-    except subprocess.CalledProcessError as e:
-        pytest.fail(f"Error while running '{DOCKER_COMPOSE} -f {compose_file} down -v':\n{e.output}", pytrace=False)
+def docker_compose_up(compose_files: List[str], project_name: str):
+    """
+    Execute compose up --detach with the provided compose files and project name.
+    """
+    if compose_files is None or len(compose_files) == 0:
+        pytest.fail(f"No compose file passed to docker_compose_up", pytrace=False)
+    __prepare_and_execute_compose_cmd(compose_files, project_name, cmd="up --detach")
+
+
+def docker_compose_down(compose_files: List[str], project_name: str):
+    """
+    Execute compose down --volumes with the provided compose files and project name.
+    """
+    if compose_files is None or len(compose_files) == 0:
+        pytest.fail(f"No compose file passed to docker_compose_up", pytrace=False)
+    __prepare_and_execute_compose_cmd(compose_files, project_name, cmd="down --volumes")
 
 
 def wait_for_nginxproxy_to_be_ready():
@@ -330,35 +362,47 @@ def wait_for_nginxproxy_to_be_ready():
 
 
 @pytest.fixture
-def docker_compose_file(request: FixtureRequest) -> Iterator[Optional[str]]:
-    """Fixture naming the docker compose file to consider.
+def docker_compose_files(request: FixtureRequest) -> List[str]:
+    """Fixture returning the docker compose files to consider:
+
+    If a YAML file exists with the same name as the test module (with the `.py` extension
+    replaced with `.base.yml`, ie `test_foo.py`-> `test_foo.base.yml`) and in the same
+    directory as the test module, use only that file.
 
-    If a YAML file exists with the same name as the test module (with the `.py` extension replaced
-    with `.yml` or `.yaml`), use that.  Otherwise, use `docker-compose.yml` in the same directory
-    as the test module.
+    Otherwise, merge the following files in this order:
+
+    - the `compose.base.yml` file in the parent `test` directory.
+    - if present in the same directory as the test module, the `compose.base.override.yml` file.
+    - the YAML file named after the current test module (ie `test_foo.py`-> `test_foo.yml`)
 
     Tests can override this fixture to specify a custom location.
     """
-    test_module_dir = os.path.dirname(request.module.__file__)
-    yml_file = os.path.join(test_module_dir, f"{request.module.__name__}.yml")
-    yaml_file = os.path.join(test_module_dir, f"{request.module.__name__}.yaml")
-    default_file = os.path.join(test_module_dir, 'docker-compose.yml')
+    compose_files: List[str] = []
+    test_module_path = pathlib.Path(request.module.__file__).parent
 
-    docker_compose_file = None
+    module_base_file = test_module_path.joinpath(f"{request.module.__name__}.base.yml")
+    if module_base_file.is_file():
+        return [module_base_file.as_posix()]
 
-    if os.path.isfile(yml_file):
-        docker_compose_file = yml_file
-    elif os.path.isfile(yaml_file):
-        docker_compose_file = yaml_file
-    elif os.path.isfile(default_file):
-        docker_compose_file = default_file
+    global_base_file = test_module_path.parent.joinpath("compose.base.yml")
+    if global_base_file.is_file():
+        compose_files.append(global_base_file.as_posix())
 
-    if docker_compose_file is None:
-        logging.error("Could not find any docker compose file named either '{0}.yml', '{0}.yaml' or 'docker-compose.yml'".format(request.module.__name__))
-    else:
-        logging.debug(f"using docker compose file {docker_compose_file}")
+    module_base_override_file = test_module_path.joinpath("compose.base.override.yml")
+    if module_base_override_file.is_file():
+        compose_files.append(module_base_override_file.as_posix())
+
+    module_compose_file = test_module_path.joinpath(f"{request.module.__name__}.yml")
+    if module_compose_file.is_file():
+        compose_files.append(module_compose_file.as_posix())
 
-    yield docker_compose_file
+    if not module_base_file.is_file() and not module_compose_file.is_file():
+        logging.error(
+            f"Could not find any docker compose file named '{module_base_file.name}' or '{module_compose_file.name}'"
+        )
+
+    logging.debug(f"using docker compose files {compose_files}")
+    return compose_files
 
 
 def connect_to_network(network: Network) -> Optional[Network]:
@@ -428,30 +472,33 @@ def connect_to_all_networks() -> List[Network]:
 class DockerComposer(contextlib.AbstractContextManager):
     def __init__(self):
         self._networks = None
-        self._docker_compose_file = None
+        self._docker_compose_files = None
+        self._project_name = None
 
     def __exit__(self, *exc_info):
         self._down()
 
     def _down(self):
-        if self._docker_compose_file is None:
+        if self._docker_compose_files is None:
             return
         for network in self._networks:
             disconnect_from_network(network)
-        docker_compose_down(self._docker_compose_file)
+        docker_compose_down(self._docker_compose_files, self._project_name)
         self._docker_compose_file = None
+        self._project_name = None
 
-    def compose(self, docker_compose_file: Optional[str]):
-        if docker_compose_file == self._docker_compose_file:
+    def compose(self, docker_compose_files: List[str], project_name: str):
+        if docker_compose_files == self._docker_compose_files and project_name == self._project_name:
             return
         self._down()
-        if docker_compose_file is None:
+        if docker_compose_files is None or project_name is None:
             return
-        docker_compose_up(docker_compose_file)
+        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_file = docker_compose_file
+        self._docker_compose_files = docker_compose_files
+        self._project_name = project_name
 
 
 ###############################################################################
@@ -462,14 +509,14 @@ class DockerComposer(contextlib.AbstractContextManager):
 
 
 @pytest.fixture(scope="module")
-def docker_composer() ->  Iterator[DockerComposer]:
+def docker_composer() -> Iterator[DockerComposer]:
     with DockerComposer() as d:
         yield d
 
 
 @pytest.fixture
-def ca_root_certificate() -> Iterator[str]:
-    yield CA_ROOT_CERTIFICATE
+def ca_root_certificate() -> str:
+    return CA_ROOT_CERTIFICATE.as_posix()
 
 
 @pytest.fixture
@@ -480,16 +527,29 @@ def monkey_patched_dns():
 
 
 @pytest.fixture
-def docker_compose(monkey_patched_dns, docker_composer, docker_compose_file) -> Iterator[DockerClient]:
-    """Ensures containers described in a docker compose file are started.
+def docker_compose(
+        request: FixtureRequest,
+        monkeypatch,
+        monkey_patched_dns,
+        docker_composer,
+        docker_compose_files
+) -> Iterator[DockerClient]:
+    """
+    Ensures containers necessary for the test module are started in a compose project,
+    and set the environment variable `PYTEST_MODULE_PATH` to the test module's parent folder.
 
-    A custom docker compose file name can be specified by overriding the `docker_compose_file`
-    fixture.
+    A list of custom docker compose files path can be specified by overriding
+    the `docker_compose_file` fixture.
 
-    Also, in the case where pytest is running from a docker container, this fixture makes sure
-    our container will be attached to all the docker networks.
+    Also, in the case where pytest is running from a docker container, this fixture
+    makes sure our container will be attached to all the docker networks.
     """
-    docker_composer.compose(docker_compose_file)
+    pytest_module_path = pathlib.Path(request.module.__file__).parent
+    monkeypatch.setenv("PYTEST_MODULE_PATH", pytest_module_path.as_posix())
+
+    project_name = request.module.__name__
+    docker_composer.compose(docker_compose_files, project_name)
+
     yield docker_client
 
 
@@ -511,11 +571,11 @@ def nginxproxy() -> Iterator[RequestsForDocker]:
 
 
 @pytest.fixture
-def acme_challenge_path() -> Iterator[str]:
+def acme_challenge_path() -> str:
     """
     Provides fake Let's Encrypt ACME challenge path used in certain tests
     """
-    yield ".well-known/acme-challenge/test-filename"
+    return ".well-known/acme-challenge/test-filename"
 
 ###############################################################################
 #

+ 6 - 0
test/test_acme-http-challenge-location/compose.base.override.yml

@@ -0,0 +1,6 @@
+services:
+  nginx-proxy:
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+      - ${PYTEST_MODULE_PATH}/certs:/etc/nginx/certs:ro
+      - ${PYTEST_MODULE_PATH}/acme_root:/usr/share/nginx/html:ro

+ 4 - 9
test/test_acme-http-challenge-location/test_acme-http-challenge-location-disabled.yml

@@ -1,4 +1,8 @@
 services:
+  nginx-proxy:
+    environment:
+      ACME_HTTP_CHALLENGE_LOCATION: "false"
+
   web1:
     image: web
     expose:
@@ -34,12 +38,3 @@ services:
       VIRTUAL_HOST: "web4.nginx-proxy.tld"
       HTTPS_METHOD: noredirect
       ACME_HTTP_CHALLENGE_LOCATION: "true"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    environment:
-      ACME_HTTP_CHALLENGE_LOCATION: "false"
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs:/etc/nginx/certs:ro
-      - ./acme_root:/usr/share/nginx/html:ro

+ 0 - 7
test/test_acme-http-challenge-location/test_acme-http-challenge-location-enabled-is-default.yml

@@ -34,10 +34,3 @@ services:
       VIRTUAL_HOST: "web4.nginx-proxy.tld"
       HTTPS_METHOD: noredirect
       ACME_HTTP_CHALLENGE_LOCATION: "false"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs:/etc/nginx/certs:ro
-      - ./acme_root:/usr/share/nginx/html:ro

+ 4 - 9
test/test_acme-http-challenge-location/test_acme-http-challenge-location-legacy.yml

@@ -1,4 +1,8 @@
 services:
+  nginx-proxy:
+    environment:
+      ACME_HTTP_CHALLENGE_LOCATION: "legacy"
+
   web1:
     image: web
     expose:
@@ -15,12 +19,3 @@ services:
       WEB_PORTS: "82"
       VIRTUAL_HOST: "web2.nginx-proxy.tld"
       HTTPS_METHOD: noredirect
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    environment:
-      ACME_HTTP_CHALLENGE_LOCATION: "legacy"
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs:/etc/nginx/certs:ro
-      - ./acme_root:/usr/share/nginx/html:ro

+ 2 - 3
test/test_custom-error-page/test_custom-error-page.yml

@@ -1,6 +1,5 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
+  nginx-proxy:
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./50x.html:/usr/share/nginx/html/errors/50x.html:ro
+      - ${PYTEST_MODULE_PATH}/50x.html:/usr/share/nginx/html/errors/50x.html:ro

+ 2 - 3
test/test_custom/test_defaults-location.yml

@@ -1,10 +1,9 @@
 services:
   nginx-proxy:
-    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/default_location:ro
-      - ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.example_location:ro
+      - ${PYTEST_MODULE_PATH}/my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/default_location:ro
+      - ${PYTEST_MODULE_PATH}/my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.example_location:ro
 
   web1:
     image: web

+ 1 - 2
test/test_custom/test_defaults.yml

@@ -1,9 +1,8 @@
 services:
   nginx-proxy:
-    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./my_custom_proxy_settings_f00.conf:/etc/nginx/proxy.conf:ro
+      - ${PYTEST_MODULE_PATH}/my_custom_proxy_settings_f00.conf:/etc/nginx/proxy.conf:ro
 
   web1:
     image: web

+ 2 - 3
test/test_custom/test_location-per-vhost.yml

@@ -1,10 +1,9 @@
 services:
   nginx-proxy:
-    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example_location:ro
-      - ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/561032515ede3ab3a015edfb244608b72409c430_location:ro
+      - ${PYTEST_MODULE_PATH}/my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example_location:ro
+      - ${PYTEST_MODULE_PATH}/my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/561032515ede3ab3a015edfb244608b72409c430_location:ro
 
   web1:
     image: web

+ 2 - 3
test/test_custom/test_per-vhost.yml

@@ -1,10 +1,9 @@
 services:
   nginx-proxy:
-    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example:ro
-      - ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/561032515ede3ab3a015edfb244608b72409c430:ro
+      - ${PYTEST_MODULE_PATH}/my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example:ro
+      - ${PYTEST_MODULE_PATH}/my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/561032515ede3ab3a015edfb244608b72409c430:ro
 
   web1:
     image: web

+ 1 - 2
test/test_custom/test_proxy-wide.yml

@@ -1,9 +1,8 @@
 services:
   nginx-proxy:
-    image: nginxproxy/nginx-proxy:test
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./my_custom_proxy_settings_f00.conf:/etc/nginx/conf.d/my_custom_proxy_settings_f00.conf:ro
+      - ${PYTEST_MODULE_PATH}/my_custom_proxy_settings_f00.conf:/etc/nginx/conf.d/my_custom_proxy_settings_f00.conf:ro
 
   web1:
     image: web

+ 0 - 3
test/test_debug-endpoint/test_global.yml

@@ -1,8 +1,5 @@
 services:
   nginx-proxy:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
     environment:
       DEBUG_ENDPOINT: "true"
 

+ 0 - 5
test/test_debug-endpoint/test_per-container.yml

@@ -1,9 +1,4 @@
 services:
-  nginx-proxy:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-
   debug_disabled1:
     image: web
     expose:

+ 4 - 9
test/test_default-host/test_default-host.yml

@@ -1,5 +1,8 @@
 services:
-  # GIVEN a webserver with VIRTUAL_HOST set to web1.tld
+  nginx-proxy:
+    environment:
+      DEFAULT_HOST: web1.tld
+
   web1:
     image: web
     expose:
@@ -7,11 +10,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: web1.tld
-
-  # WHEN nginx-proxy runs with DEFAULT_HOST set to web1.tld
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      DEFAULT_HOST: web1.tld

+ 6 - 7
test/test_docker-unix-socket/test_docker-unix-socket.yml

@@ -1,4 +1,10 @@
 services:
+  nginx-proxy:
+    volumes:
+      - /var/run/docker.sock:/f00.sock:ro
+    environment:
+      DOCKER_HOST: unix:///f00.sock
+
   web1:
     image: web
     expose:
@@ -14,10 +20,3 @@ services:
     environment:
       WEB_PORTS: "82"
       VIRTUAL_HOST: web2.nginx-proxy.tld
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/f00.sock:ro
-    environment:
-      DOCKER_HOST: unix:///f00.sock

+ 9 - 5
test/test_dockergen/test_dockergen.yml → test/test_dockergen/test_dockergen.base.yml

@@ -1,11 +1,18 @@
+volumes:
+  nginx_conf:
+
+
 services:
-  nginx:
+  nginx-proxy-nginx:
     image: nginx
     container_name: nginx
     volumes:
       - nginx_conf:/etc/nginx/conf.d:ro
+    ports:
+      - "80:80"
+      - "443:443"
 
-  dockergen:
+  nginx-proxy-dockergen:
     image: nginxproxy/docker-gen
     command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
     volumes:
@@ -21,6 +28,3 @@ services:
     environment:
       WEB_PORTS: "80"
       VIRTUAL_HOST: whoami.nginx.container.docker
-
-volumes:
-  nginx_conf:

+ 1 - 5
test/test_enable-http-on-missing-cert/test_enable-http-on-missing-cert.yml

@@ -1,9 +1,5 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./withdefault.certs:/etc/nginx/certs:ro
+  nginx-proxy:
     environment:
       ENABLE_HTTP_ON_MISSING_CERT: "false"
 

+ 0 - 6
test/test_events/test_events.yml

@@ -1,9 +1,3 @@
 networks:
   default:
     name: test_events-net
-
-services:
-  nginxproxy:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 9 - 0
test/test_fallback/test_fallback.data/compose.base.yml

@@ -0,0 +1,9 @@
+services:
+  nginx-proxy:
+    image: nginxproxy/nginx-proxy:test
+    container_name: nginx-proxy
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+    ports:
+      - "80:80"
+      - "443:443"

+ 2 - 3
test/test_fallback/test_fallback.data/custom-fallback.yml

@@ -1,9 +1,8 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
+  nginx-proxy:
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./custom-fallback.conf:/etc/nginx/conf.d/zzz-custom-fallback.conf:ro
+      - ${PYTEST_MODULE_PATH}/test_fallback.data/custom-fallback.conf:/etc/nginx/conf.d/zzz-custom-fallback.conf:ro
 
   http-only:
     image: web

+ 2 - 3
test/test_fallback/test_fallback.data/nodefault.yml

@@ -1,9 +1,8 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
+  nginx-proxy:
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./nodefault.certs:/etc/nginx/certs:ro
+      - ${PYTEST_MODULE_PATH}/test_fallback.data/nodefault.certs:/etc/nginx/certs:ro
 
   https-and-http:
     image: web

+ 2 - 3
test/test_fallback/test_fallback.data/nohttp-on-app.yml

@@ -1,9 +1,8 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
+  nginx-proxy:
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./withdefault.certs:/etc/nginx/certs:ro
+      - ${PYTEST_MODULE_PATH}/test_fallback.data/withdefault.certs:/etc/nginx/certs:ro
     environment:
       HTTPS_METHOD: redirect
 

+ 2 - 3
test/test_fallback/test_fallback.data/nohttp-with-missing-cert.yml

@@ -1,9 +1,8 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
+  nginx-proxy:
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./withdefault.certs:/etc/nginx/certs:ro
+      - ${PYTEST_MODULE_PATH}/test_fallback.data/withdefault.certs:/etc/nginx/certs:ro
     environment:
       HTTPS_METHOD: nohttp
 

+ 2 - 3
test/test_fallback/test_fallback.data/nohttp.yml

@@ -1,9 +1,8 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
+  nginx-proxy:
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./withdefault.certs:/etc/nginx/certs:ro
+      - ${PYTEST_MODULE_PATH}/test_fallback.data/withdefault.certs:/etc/nginx/certs:ro
     environment:
       HTTPS_METHOD: nohttp
 

+ 1 - 4
test/test_fallback/test_fallback.data/nohttps-on-app.yml

@@ -1,8 +1,5 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
+  nginx-proxy:
     environment:
       HTTPS_METHOD: redirect
 

+ 1 - 4
test/test_fallback/test_fallback.data/nohttps.yml

@@ -1,8 +1,5 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
+  nginx-proxy:
     environment:
       HTTPS_METHOD: nohttps
 

+ 2 - 3
test/test_fallback/test_fallback.data/untrusteddefault.yml

@@ -1,9 +1,8 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
+  nginx-proxy:
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./withdefault.certs:/etc/nginx/certs:ro
+      - ${PYTEST_MODULE_PATH}/test_fallback.data/withdefault.certs:/etc/nginx/certs:ro
     environment:
       TRUST_DEFAULT_CERT: "false"
 

+ 2 - 3
test/test_fallback/test_fallback.data/withdefault.yml

@@ -1,9 +1,8 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
+  nginx-proxy:
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./withdefault.certs:/etc/nginx/certs:ro
+      - ${PYTEST_MODULE_PATH}/test_fallback.data/withdefault.certs:/etc/nginx/certs:ro
 
   https-and-http:
     image: web

+ 13 - 13
test/test_fallback/test_fallback.py

@@ -1,32 +1,32 @@
-import os.path
+import pathlib
 import re
+from typing import List, Callable
 
 import backoff
 import pytest
 import requests
+from requests import Response
 
 
 @pytest.fixture
-def data_dir():
-    return f"{os.path.splitext(__file__)[0]}.data"
+def docker_compose_files(compose_file) -> List[str]:
+    data_dir = pathlib.Path(__file__).parent.joinpath("test_fallback.data")
+    return [
+        data_dir.joinpath("compose.base.yml"),
+        data_dir.joinpath(compose_file).as_posix()
+    ]
 
 
 @pytest.fixture
-def docker_compose_file(data_dir, compose_file):
-    return os.path.join(data_dir, compose_file)
-
-
-@pytest.fixture
-def get(docker_compose, nginxproxy, want_err_re):
-
+def get(docker_compose, nginxproxy, want_err_re: re.Pattern[str]) -> Callable[[str], Response]:
     @backoff.on_exception(
         backoff.constant,
         requests.exceptions.SSLError,
-        giveup=lambda e: want_err_re and want_err_re.search(str(e)),
+        giveup=lambda e: want_err_re and bool(want_err_re.search(str(e))),
         interval=.3,
         max_tries=30,
         jitter=None)
-    def _get(url):
+    def _get(url) -> Response:
         return nginxproxy.get(url, allow_redirects=False)
 
     return _get
@@ -108,7 +108,7 @@ 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)
         assert r.status_code == want_code

+ 70 - 0
test/test_headers/certs/default.crt

@@ -0,0 +1,70 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 4096 (0x1000)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
+        Validity
+            Not Before: Jan 13 03:06:39 2017 GMT
+            Not After : May 31 03:06:39 2044 GMT
+        Subject: CN=web.nginx-proxy.tld
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:95:56:c7:0d:48:a5:2b:3c:65:49:3f:26:e1:38:
+                    2b:61:30:56:e4:92:d7:63:e0:eb:ad:ac:f9:33:9b:
+                    b2:31:f1:39:13:0b:e5:43:7b:c5:bd:8a:85:c8:d9:
+                    3d:d8:ac:71:ba:16:e7:81:96:b2:ab:ae:c6:c0:bd:
+                    be:a7:d1:96:8f:b2:9b:df:ba:f9:4d:a1:3b:7e:21:
+                    4a:cd:b6:45:f9:6d:79:50:bf:24:8f:c1:6b:c1:09:
+                    19:5b:62:cb:96:e8:04:14:20:e8:d4:16:62:6a:f2:
+                    37:c1:96:e2:9d:53:05:0b:52:1d:e7:68:92:db:8b:
+                    36:68:cd:8d:5b:02:ff:12:f0:ac:5d:0c:c4:e0:7a:
+                    55:a2:49:60:9f:ff:47:1f:52:73:55:4d:d4:f2:d1:
+                    62:a2:f4:50:9d:c9:f6:f1:43:b3:dc:57:e1:31:76:
+                    b4:e0:a4:69:7e:f2:6d:34:ae:b9:8d:74:26:7b:d9:
+                    f6:07:00:ef:4b:36:61:b3:ef:7a:a1:36:3a:b6:d0:
+                    9e:f8:b8:a9:0d:4c:30:a2:ed:eb:ab:6b:eb:2e:e2:
+                    0b:28:be:f7:04:b1:e9:e0:84:d6:5d:31:77:7c:dc:
+                    d2:1f:d4:1d:71:6f:6f:6c:6d:1b:bf:31:e2:5b:c3:
+                    52:d0:14:fc:8b:fb:45:ea:41:ec:ca:c7:3b:67:12:
+                    c4:df
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Alternative Name: 
+                DNS:web.nginx-proxy.tld
+    Signature Algorithm: sha256WithRSAEncryption
+         4e:48:7d:81:66:ba:2f:50:3d:24:42:61:3f:1f:de:cf:ec:1b:
+         1b:bd:0a:67:b6:62:c8:79:9d:31:a0:fd:a9:61:ce:ff:69:bf:
+         0e:f4:f7:e6:15:2b:b0:f0:e4:f2:f4:d2:8f:74:02:b1:1e:4a:
+         a8:6f:26:0a:77:32:29:cf:dc:b5:61:82:3e:58:47:61:92:f0:
+         0c:20:25:f8:41:4d:34:09:44:bc:39:9e:aa:82:06:83:13:8b:
+         1e:2c:3d:cf:cd:1a:f7:77:39:38:e0:a3:a7:f3:09:da:02:8d:
+         73:75:38:b4:dd:24:a7:f9:03:db:98:c6:88:54:87:dc:e0:65:
+         4c:95:c5:39:9c:00:30:dc:f0:d3:2c:19:ca:f1:f4:6c:c6:d9:
+         b5:c4:4a:c7:bc:a1:2e:88:7b:b5:33:d0:ff:fb:48:5e:3e:29:
+         fa:58:e5:03:de:d8:17:de:ed:96:fc:7e:1f:fe:98:f6:be:99:
+         38:87:51:c0:d3:b7:9a:0f:26:92:e5:53:1b:d6:25:4c:ac:48:
+         f3:29:fc:74:64:9d:07:6a:25:57:24:aa:a7:70:fa:8f:6c:a7:
+         2b:b7:9d:81:46:10:32:93:b9:45:6d:0f:16:18:b2:21:1f:f3:
+         30:24:62:3f:e1:6c:07:1d:71:28:cb:4c:bb:f5:39:05:f9:b2:
+         5b:a0:05:1b
+-----BEGIN CERTIFICATE-----
+MIIC+zCCAeOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
+bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
+ZDAeFw0xNzAxMTMwMzA2MzlaFw00NDA1MzEwMzA2MzlaMB4xHDAaBgNVBAMME3dl
+Yi5uZ2lueC1wcm94eS50bGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCVVscNSKUrPGVJPybhOCthMFbkktdj4OutrPkzm7Ix8TkTC+VDe8W9ioXI2T3Y
+rHG6FueBlrKrrsbAvb6n0ZaPspvfuvlNoTt+IUrNtkX5bXlQvySPwWvBCRlbYsuW
+6AQUIOjUFmJq8jfBluKdUwULUh3naJLbizZozY1bAv8S8KxdDMTgelWiSWCf/0cf
+UnNVTdTy0WKi9FCdyfbxQ7PcV+ExdrTgpGl+8m00rrmNdCZ72fYHAO9LNmGz73qh
+Njq20J74uKkNTDCi7eura+su4gsovvcEsenghNZdMXd83NIf1B1xb29sbRu/MeJb
+w1LQFPyL+0XqQezKxztnEsTfAgMBAAGjIjAgMB4GA1UdEQQXMBWCE3dlYi5uZ2lu
+eC1wcm94eS50bGQwDQYJKoZIhvcNAQELBQADggEBAE5IfYFmui9QPSRCYT8f3s/s
+Gxu9Cme2Ysh5nTGg/alhzv9pvw709+YVK7Dw5PL00o90ArEeSqhvJgp3MinP3LVh
+gj5YR2GS8AwgJfhBTTQJRLw5nqqCBoMTix4sPc/NGvd3OTjgo6fzCdoCjXN1OLTd
+JKf5A9uYxohUh9zgZUyVxTmcADDc8NMsGcrx9GzG2bXESse8oS6Ie7Uz0P/7SF4+
+KfpY5QPe2Bfe7Zb8fh/+mPa+mTiHUcDTt5oPJpLlUxvWJUysSPMp/HRknQdqJVck
+qqdw+o9spyu3nYFGEDKTuUVtDxYYsiEf8zAkYj/hbAcdcSjLTLv1OQX5slugBRs=
+-----END CERTIFICATE-----

+ 27 - 0
test/test_headers/certs/default.key

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAlVbHDUilKzxlST8m4TgrYTBW5JLXY+Drraz5M5uyMfE5Ewvl
+Q3vFvYqFyNk92KxxuhbngZayq67GwL2+p9GWj7Kb37r5TaE7fiFKzbZF+W15UL8k
+j8FrwQkZW2LLlugEFCDo1BZiavI3wZbinVMFC1Id52iS24s2aM2NWwL/EvCsXQzE
+4HpVoklgn/9HH1JzVU3U8tFiovRQncn28UOz3FfhMXa04KRpfvJtNK65jXQme9n2
+BwDvSzZhs+96oTY6ttCe+LipDUwwou3rq2vrLuILKL73BLHp4ITWXTF3fNzSH9Qd
+cW9vbG0bvzHiW8NS0BT8i/tF6kHsysc7ZxLE3wIDAQABAoIBAEmK7IecKMq7+V0y
+3mC3GpXICmKR9cRX9XgX4LkLiZuSoXrBtuuevmhzGSMp6I0VjwQHV4a3wdFORs6Q
+Ip3eVvj5Ck4Jc9BJAFVC6+WWR6tnwACFwOmSZRAw/O3GH2B3bdrDwiT/yQPFuLN7
+LKoxQiCrFdLp6rh3PBosb9pMBXU7k/HUazIdgmSKg6/JIoo/4Gwyid04TF/4MI2l
+RscxtP5/ANtS8VgwBEqhgdafRJ4KnLEpgvswgIQvUKmduVhZQlzd0LMY8FbhKVqz
+Utg8gsXaTyH6df/nmgUIInxLMz/MKPnMkv99fS6Sp/hvYlGpLZFWBJ6unMq3lKEr
+LMbHfIECgYEAxB+5QWdVqG2r9loJlf8eeuNeMPml4P8Jmi5RKyJC7Cww6DMlMxOS
+78ZJfl4b3ZrWuyvhjOfX/aTq7kQaF1BI9o3KJBH8k6EtO4gI8KeNmDONyQk9zsrn
+ru8Zwr7hVbAo8fCXxCnmPzhDLsYg6f3BVOsQWoX2SFYKZ1GvkPfIReECgYEAwu6G
+qtgFb57Vim10ecfWGM6vrPxvyfqP+zlH/p4nR+aQ+2sFbt27D0B1byWBRZe4KQyw
+Vq6XiQ09Fk6MJr8E8iAr9GXPPHcqlYI6bbNc6YOP3jVSKut0tQdTUOHll4kYIY+h
+RS3VA3+BA//ADpWpywu+7RZRbaIECA+U2a224r8CgYB5PCMIixgoRaNHZeEHF+1/
+iY1wOOKRcxY8eOU0BLnZxHd3EiasrCzoi2pi80nGczDKAxYqRCcAZDHVl8OJJdf0
+kTGjmnrHx5pucmkUWn7s1vGOlGfgrQ0K1kLWX6hrj7m/1Tn7yOrLqbvd7hvqiTI5
+jBVP3/+eN5G2zIf61TC4AQKBgCX2Q92jojNhsF58AHHy+/vqzIWYx8CC/mVDe4TX
+kfjLqzJ7XhyAK/zFZdlWaX1/FYtRAEpxR+uV226rr1mgW7s3jrfS1/ADmRRyvyQ8
+CP0k9PCmW7EmF51lptEanRbMyRlIGnUZfuFmhF6eAO4WMXHsgKs1bHg4VCapuihG
+T1aLAoGACRGn1UxFuBGqtsh2zhhsBZE7GvXKJSk/eP7QJeEXUNpNjCpgm8kIZM5K
+GorpL7PSB8mwVlDl18TpMm3P7nz6YkJYte+HdjO7pg59H39Uvtg3tZnIrFxNxVNb
+YF62/yHfk2AyTgjQZQUSmDS84jq1zUK4oS90lxr+u8qwELTniMs=
+-----END RSA PRIVATE KEY-----

+ 0 - 5
test/test_headers/test_http.yml

@@ -15,8 +15,3 @@ services:
       WEB_PORTS: "80"
       VIRTUAL_HOST: web-server-tokens-off.nginx-proxy.tld
       SERVER_TOKENS: "off"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 5 - 11
test/test_headers/test_https.yml

@@ -1,4 +1,9 @@
 services:
+  nginx-proxy:
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+      - ${PYTEST_MODULE_PATH}/certs:/etc/nginx/certs:ro
+
   web:
     image: web
     expose:
@@ -15,14 +20,3 @@ services:
       WEB_PORTS: "80"
       VIRTUAL_HOST: web-server-tokens-off.nginx-proxy.tld
       SERVER_TOKENS: "off"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/default.crt:ro
-      - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/default.key:ro
-      - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro
-      - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro
-      - ./certs/web-server-tokens-off.nginx-proxy.tld.crt:/etc/nginx/certs/web-server-tokens-off.nginx-proxy.tld.crt:ro
-      - ./certs/web-server-tokens-off.nginx-proxy.tld.key:/etc/nginx/certs/web-server-tokens-off.nginx-proxy.tld.key:ro

+ 5 - 8
test/test_host-network-mode/test_host-network-mode.yml

@@ -4,6 +4,11 @@ networks:
   net2:
 
 services:
+  nginx-proxy:
+    networks:
+      - net1
+      - net2
+
   bridge-network:
     image: web
     environment:
@@ -19,11 +24,3 @@ services:
       VIRTUAL_HOST: "host-network.nginx-proxy.tld"
       VIRTUAL_PORT: "8080"
     network_mode: host
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    networks:
-      - net1
-      - net2

+ 3 - 0
test/test_host-network-mode/test_proxy-host-network-mode.py

@@ -1,3 +1,6 @@
+# Note: on Docker Desktop, host networking must be manually enabled.
+# See https://docs.docker.com/engine/network/drivers/host/
+
 def test_forwards_to_host_network_container_1(docker_compose, nginxproxy):
     r = nginxproxy.get("http://host-network-1.nginx-proxy.tld:8888/port")
     assert r.status_code == 200

+ 5 - 8
test/test_host-network-mode/test_proxy-host-network-mode.yml

@@ -1,4 +1,9 @@
 services:
+  nginx-proxy:
+    environment:
+      HTTP_PORT: 8888
+    network_mode: host
+
   host-network-1:
     image: web
     environment:
@@ -14,11 +19,3 @@ services:
       VIRTUAL_HOST: "host-network-2.nginx-proxy.tld"
       VIRTUAL_PORT: "8181"
     network_mode: host
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      HTTP_PORT: 8888
-    network_mode: host

+ 5 - 0
test/test_htpasswd/compose.base.override.yml

@@ -0,0 +1,5 @@
+services:
+  nginx-proxy:
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+      - ${PYTEST_MODULE_PATH}/htpasswd:/etc/nginx/htpasswd:ro

+ 0 - 7
test/test_htpasswd/test_htpasswd-regex-virtual-host.yml

@@ -6,10 +6,3 @@ services:
     environment:
       WEB_PORTS: "80"
       VIRTUAL_HOST: ~^regex.*\.nginx-proxy\.example$
-
-  sut:
-    container_name: sut
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./htpasswd:/etc/nginx/htpasswd:ro

+ 0 - 7
test/test_htpasswd/test_htpasswd-virtual-host.yml

@@ -6,10 +6,3 @@ services:
     environment:
       WEB_PORTS: "80"
       VIRTUAL_HOST: htpasswd.nginx-proxy.tld
-
-  sut:
-    container_name: sut
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./htpasswd:/etc/nginx/htpasswd:ro

+ 0 - 7
test/test_htpasswd/test_htpasswd-virtual-path.yml

@@ -8,10 +8,3 @@ services:
       VIRTUAL_HOST: htpasswd.nginx-proxy.tld
       VIRTUAL_PATH: /foo/
       VIRTUAL_DEST: /
-
-  sut:
-    container_name: sut
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./htpasswd:/etc/nginx/htpasswd:ro

+ 6 - 7
test/test_http-port/test_http-port.yml

@@ -1,4 +1,10 @@
 services:
+  nginx-proxy:
+    environment:
+      HTTP_PORT: 8080
+    ports:
+      - "8080:8080"
+
   web1:
     image: web
     expose:
@@ -6,10 +12,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: "*.nginx-proxy.tld"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      HTTP_PORT: 8080

+ 4 - 7
test/test_http2/test_http2-global-disabled.yml

@@ -1,4 +1,8 @@
 services:
+  nginx-proxy:
+    environment:
+      ENABLE_HTTP2: "false"
+
   http2-global-disabled:
     image: web
     expose:
@@ -6,10 +10,3 @@ services:
     environment:
       WEB_PORTS: "80"
       VIRTUAL_HOST: http2-global-disabled.nginx-proxy.tld
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      ENABLE_HTTP2: "false"

+ 4 - 7
test/test_http3/test_http3-global-disabled.yml

@@ -1,4 +1,8 @@
 services:
+#  nginx-proxy:
+#    environment:
+#      ENABLE_HTTP3: "false"    #Disabled by default
+
   http3-global-disabled:
     image: web
     expose:
@@ -6,10 +10,3 @@ services:
     environment:
       WEB_PORTS: "80"
       VIRTUAL_HOST: http3-global-disabled.nginx-proxy.tld
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    #environment:
-    #ENABLE_HTTP3: "false"    #Disabled by default

+ 4 - 7
test/test_http3/test_http3-global-enabled.yml

@@ -1,4 +1,8 @@
 services:
+  nginx-proxy:
+    environment:
+      ENABLE_HTTP3: "true"
+
   http3-global-enabled:
     image: web
     expose:
@@ -6,10 +10,3 @@ services:
     environment:
       WEB_PORTS: "80"
       VIRTUAL_HOST: http3-global-enabled.nginx-proxy.tld
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      ENABLE_HTTP3: "true"

+ 4 - 5
test/test_http3/test_http3-vhost.yml

@@ -1,4 +1,8 @@
 services:
+#  nginx-proxy:
+#    environment:
+#      ENABLE_HTTP3: "false"    #Disabled by default
+
   http3-vhost-enabled:
     image: web
     expose:
@@ -26,8 +30,3 @@ services:
     environment:
       WEB_PORTS: "80"
       VIRTUAL_HOST: http3-vhost-default-disabled.nginx-proxy.tld
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 5 - 0
test/test_internal/compose.base.override.yml

@@ -0,0 +1,5 @@
+services:
+  nginx-proxy:
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+      - ${PYTEST_MODULE_PATH}/network_internal.conf:/etc/nginx/network_internal.conf:ro

+ 0 - 6
test/test_internal/test_internal-per-vhost.yml

@@ -15,9 +15,3 @@ services:
     environment:
       WEB_PORTS: "82"
       VIRTUAL_HOST: web2.nginx-proxy.example
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./network_internal.conf:/etc/nginx/network_internal.conf:ro

+ 0 - 5
test/test_internal/test_internal-per-vpath.yml

@@ -20,8 +20,3 @@ services:
       VIRTUAL_PATH: /web2/
       VIRTUAL_DEST: /
 
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./network_internal.conf:/etc/nginx/network_internal.conf:ro

+ 8 - 10
test/test_ipv6/test_ipv6-prefer-ipv4-network.yml

@@ -11,6 +11,14 @@ networks:
         - subnet: fd00:cafe:face:feed::/64
 
 services:
+  nginx-proxy:
+    networks:
+      ipv4net:
+        ipv4_address: 172.16.10.3
+      dualstacknet:
+        ipv4_address: 172.16.20.3
+        ipv6_address: fd00:cafe:face:feed::3
+
   ipv4only:
     image: web
     expose:
@@ -31,13 +39,3 @@ services:
         ipv4_address: 172.16.20.2
         ipv6_address: fd00:cafe:face:feed::2
 
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    networks:
-      ipv4net:
-        ipv4_address: 172.16.10.3
-      dualstacknet:
-        ipv4_address: 172.16.20.3
-        ipv6_address: fd00:cafe:face:feed::3

+ 10 - 12
test/test_ipv6/test_ipv6-prefer-ipv6-network.yml

@@ -11,6 +11,16 @@ networks:
         - subnet: fd00:cafe:face:feed::/64
 
 services:
+  nginx-proxy:
+    environment:
+      PREFER_IPV6_NETWORK: "true"
+    networks:
+      ipv4net:
+        ipv4_address: 172.16.10.3
+      dualstacknet:
+        ipv4_address: 172.16.20.3
+        ipv6_address: fd00:cafe:face:feed::3
+
   ipv4only:
     image: web
     expose:
@@ -31,15 +41,3 @@ services:
         ipv4_address: 172.16.20.2
         ipv6_address: fd00:cafe:face:feed::2
 
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      PREFER_IPV6_NETWORK: "true"
-    networks:
-      ipv4net:
-        ipv4_address: 172.16.10.3
-      dualstacknet:
-        ipv4_address: 172.16.20.3
-        ipv6_address: fd00:cafe:face:feed::3

+ 10 - 0
test/test_ipv6/test_ipv6.py

@@ -1,3 +1,13 @@
+import platform
+
+import pytest
+
+pytestmark = pytest.mark.skipif(
+    platform.system() == "Darwin",
+    reason="Those tests rely entirely on being able to directly contact the container's IP"
+)
+
+
 def test_unknown_virtual_host_ipv4(docker_compose, nginxproxy):
     r = nginxproxy.get("http://nginx-proxy/port")
     assert r.status_code == 503

+ 6 - 8
test/test_ipv6/test_ipv6.yml

@@ -6,6 +6,12 @@ networks:
         - subnet: fd00:1::/80
 
 services:
+  nginx-proxy:
+    environment:
+      ENABLE_IPV6: "true"
+    networks:
+      - net1
+
   web1:
     image: web
     expose:
@@ -26,11 +32,3 @@ services:
     networks:
       - net1
 
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      ENABLE_IPV6: "true"
-    networks:
-      - net1

+ 5 - 7
test/test_keepalive/test_keepalive.yml

@@ -1,4 +1,8 @@
 services:
+  nginx-proxy:
+    environment:
+      HTTPS_METHOD: nohttps
+
   keepalive-disabled:
     image: web
     expose:
@@ -18,7 +22,7 @@ services:
       VIRTUAL_HOST: keepalive-enabled.nginx-proxy.test
     labels:
       com.github.nginx-proxy.nginx-proxy.keepalive: "64"
-  
+
   keepalive-auto:
     image: web
     deploy:
@@ -30,9 +34,3 @@ services:
       WEB_PORTS: "80"
       VIRTUAL_HOST: keepalive-auto.nginx-proxy.test
 
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      HTTPS_METHOD: nohttps

+ 0 - 5
test/test_loadbalancing/test_loadbalancing.yml

@@ -20,8 +20,3 @@ services:
       VIRTUAL_HOST: loadbalance-disabled.nginx-proxy.tld
     deploy:
       replicas: 2
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 2 - 3
test/test_location-override/test_location-override.yml

@@ -1,9 +1,8 @@
 services:
-  sut:
-    image: nginxproxy/nginx-proxy:test
+  nginx-proxy:
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./vhost.d:/etc/nginx/vhost.d:ro
+      - ${PYTEST_MODULE_PATH}/vhost.d:/etc/nginx/vhost.d:ro
 
   explicit-root:
     image: web

+ 1 - 1
test/test_logs/test_log-disabled.py

@@ -2,7 +2,7 @@ def test_log_disabled(docker_compose, nginxproxy):
     r = nginxproxy.get("http://nginx-proxy.test/port")
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"
-    sut_container = docker_compose.containers.get("sut")
+    sut_container = docker_compose.containers.get("nginx-proxy")
     docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
     docker_logs = docker_logs.decode("utf-8").splitlines()
     docker_logs = [line for line in docker_logs if "GET /port" in line]

+ 4 - 8
test/test_logs/test_log-disabled.yml

@@ -1,4 +1,8 @@
 services:
+  nginx-proxy:
+    environment:
+      DISABLE_ACCESS_LOGS: true
+
   web1:
     image: web
     expose:
@@ -6,11 +10,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: nginx-proxy.test
-
-  sut:
-    container_name: sut
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      DISABLE_ACCESS_LOGS: true

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

@@ -2,7 +2,7 @@ def test_log_format(docker_compose, nginxproxy):
     r = nginxproxy.get("http://nginx-proxy.test/port")
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"
-    sut_container = docker_compose.containers.get("sut")
+    sut_container = docker_compose.containers.get("nginx-proxy")
     docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
     docker_logs = docker_logs.decode("utf-8").splitlines()
     docker_logs = [line for line in docker_logs if "GET /port" in line]

+ 4 - 8
test/test_logs/test_log-format.yml

@@ -1,4 +1,8 @@
 services:
+  nginx-proxy:
+    environment:
+      LOG_FORMAT: '$$remote_addr - $$remote_user [$$time_local] "$$request" $$status $$body_bytes_sent "$$http_referer" "$$http_user_agent" request_time=$$request_time $$upstream_response_time'
+
   web1:
     image: web
     expose:
@@ -6,11 +10,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: nginx-proxy.test
-
-  sut:
-    container_name: sut
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      LOG_FORMAT: '$$remote_addr - $$remote_user [$$time_local] "$$request" $$status $$body_bytes_sent "$$http_referer" "$$http_user_agent" request_time=$$request_time $$upstream_response_time'

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

@@ -5,7 +5,7 @@ def test_log_json_format(docker_compose, nginxproxy):
     r = nginxproxy.get("http://nginx-proxy.test/port")
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"
-    sut_container = docker_compose.containers.get("sut")
+    sut_container = docker_compose.containers.get("nginx-proxy")
     docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
     docker_logs = docker_logs.decode("utf-8").splitlines()
     docker_logs = [line for line in docker_logs if "{\"time_local\":" in line]

+ 4 - 8
test/test_logs/test_log-json-format.yml

@@ -1,4 +1,8 @@
 services:
+  nginx-proxy:
+    environment:
+      LOG_FORMAT: '{"time_local":"$$time_iso8601","remote_addr":"$$remote_addr","request":"$$request","upstream_addr":"$$upstream_addr"}'
+
   web1:
     image: web
     expose:
@@ -6,11 +10,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: nginx-proxy.test
-
-  sut:
-    container_name: sut
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      LOG_FORMAT: '{"time_local":"$$time_iso8601","remote_addr":"$$remote_addr","request":"$$request","upstream_addr":"$$upstream_addr"}'

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

@@ -5,7 +5,7 @@ def test_log_json(docker_compose, nginxproxy):
     r = nginxproxy.get("http://nginx-proxy.test/port")
     assert r.status_code == 200
     assert r.text == "answer from port 81\n"
-    sut_container = docker_compose.containers.get("sut")
+    sut_container = docker_compose.containers.get("nginx-proxy")
     docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
     docker_logs = docker_logs.decode("utf-8").splitlines()
     docker_logs = [line for line in docker_logs if "{\"time_local\":" in line]

+ 4 - 8
test/test_logs/test_log-json.yml

@@ -1,4 +1,8 @@
 services:
+  nginx-proxy:
+    environment:
+      LOG_JSON: 1
+
   web1:
     image: web
     expose:
@@ -6,11 +10,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: nginx-proxy.test
-
-  sut:
-    container_name: sut
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    environment:
-      LOG_JSON: 1

+ 0 - 5
test/test_multiple-hosts/test_multiple-hosts.yml

@@ -6,8 +6,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: webA.nginx-proxy.tld,webB.nginx-proxy.tld
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 0 - 3
test/test_multiple-networks/test_multiple-networks.yml

@@ -6,9 +6,6 @@ networks:
 
 services:
   nginx-proxy:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
     networks:
       - net1
       - net2

+ 0 - 5
test/test_multiports/test_multiports-base-json.yml

@@ -68,8 +68,3 @@ services:
             }
           }
         }
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 0 - 5
test/test_multiports/test_multiports-base-yaml.yml

@@ -52,8 +52,3 @@ services:
           "/customdest":
             port: 10002
             dest: "/port"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 0 - 5
test/test_multiports/test_multiports-invalid-syntax.yml

@@ -35,8 +35,3 @@ services:
             port: 8080
           "/":
             port: 9000
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 0 - 5
test/test_multiports/test_multiports-merge.yml

@@ -32,8 +32,3 @@ services:
           "/foo":
             port: 9191
             dest: "/"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 6 - 0
test/test_nominal/test_nominal.py

@@ -1,3 +1,5 @@
+import platform
+
 import pytest
 from requests import ConnectionError
 
@@ -19,6 +21,10 @@ def test_forwards_to_web2(docker_compose, nginxproxy):
     assert r.text == "answer from port 82\n" 
 
 
+@pytest.mark.skipif(
+    platform.system() == "Darwin",
+    reason="This test depends on direct communication with the container's IP"
+)
 def test_ipv6_is_disabled_by_default(docker_compose, nginxproxy):
     with pytest.raises(ConnectionError):
         nginxproxy.get("http://nginx-proxy/port", ipv6=True)

+ 4 - 7
test/test_nominal/test_nominal.yml

@@ -6,6 +6,10 @@ networks:
         - subnet: fd00:1::/80
 
 services:
+  nginx-proxy:
+    networks:
+      - net1
+
   web1:
     image: web
     expose:
@@ -25,10 +29,3 @@ services:
       VIRTUAL_HOST: web2.nginx-proxy.tld
     networks:
       - net1
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    networks:
-      - net1

+ 0 - 5
test/test_ports/test_default-80.yml

@@ -7,8 +7,3 @@ services:
     environment:
       WEB_PORTS: "80 81"
       VIRTUAL_HOST: "web.nginx-proxy.tld"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 0 - 5
test/test_ports/test_single-port-not-80.yml

@@ -6,8 +6,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: "web.nginx-proxy.tld"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 0 - 5
test/test_ports/test_virtual-port-single-different-from-single-port.yml

@@ -7,8 +7,3 @@ services:
       WEB_PORTS: "81"
       VIRTUAL_HOST: "web.nginx-proxy.tld"
       VIRTUAL_PORT: "90"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 0 - 5
test/test_ports/test_virtual-port.yml

@@ -8,8 +8,3 @@ services:
       WEB_PORTS: "80 90"
       VIRTUAL_HOST: "web.nginx-proxy.tld"
       VIRTUAL_PORT: 90
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 2 - 2
test/test_raw-ip-vhost/test_raw-ip-vhost.py

@@ -1,12 +1,12 @@
 def test_raw_ipv4_vhost_forwards_to_web1(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://172.20.0.4")
+    r = nginxproxy.get("http://172.20.0.1")
     assert r.status_code == 200
     web1_container = docker_compose.containers.get("web1")
     assert r.text == f"I'm {web1_container.id[:12]}\n"
 
 
 def test_raw_ipv6_vhost_forwards_to_web2(docker_compose, nginxproxy):
-    r = nginxproxy.get("http://[fd00::4]", ipv6=True)
+    r = nginxproxy.get("http://[fd00::1]")
     assert r.status_code == 200
     web2_container = docker_compose.containers.get("web2")
     assert r.text == f"I'm {web2_container.id[:12]}\n"

+ 10 - 12
test/test_raw-ip-vhost/test_raw-ip-vhost.yml

@@ -7,6 +7,14 @@ networks:
         - subnet: fd00::/80
 
 services:
+  nginx-proxy:
+    environment:
+      ENABLE_IPV6: "true"
+    networks:
+      net1:
+        ipv4_address: 172.20.0.4
+        ipv6_address: fd00::4
+
   web1:
     container_name: web1
     image: web
@@ -14,7 +22,7 @@ services:
       - "81"
     environment:
       WEB_PORTS: "81"
-      VIRTUAL_HOST: "172.20.0.4"
+      VIRTUAL_HOST: "172.20.0.1"
     networks:
       net1:
         ipv4_address: 172.20.0.2
@@ -27,19 +35,9 @@ services:
       - "82"
     environment:
       WEB_PORTS: "82"
-      VIRTUAL_HOST: "[fd00::4]"
+      VIRTUAL_HOST: "[fd00::1]"
     networks:
       net1:
         ipv4_address: 172.20.0.3
         ipv6_address: fd00::3
 
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    environment:
-      ENABLE_IPV6: "true"
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-    networks:
-      net1:
-        ipv4_address: 172.20.0.4
-        ipv6_address: fd00::4

+ 0 - 5
test/test_server-down/test_load-balancing.yml

@@ -23,8 +23,3 @@ services:
       WEB_PORTS: "83"
       VIRTUAL_HOST: web.nginx-proxy.tld
     network_mode: "none"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 0 - 5
test/test_server-down/test_no-server-down.yml

@@ -6,8 +6,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: web.nginx-proxy.tld
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 0 - 5
test/test_server-down/test_server-down.yml

@@ -7,8 +7,3 @@ services:
       WEB_PORTS: "81"
       VIRTUAL_HOST: web.nginx-proxy.tld
     network_mode: "none"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro

+ 0 - 0
test/test_ssl/wildcard_cert_and_nohttps/certs/default.crt → test/test_ssl/certs_wildcard_nohttps/default.crt


+ 0 - 0
test/test_ssl/wildcard_cert_and_nohttps/certs/default.key → test/test_ssl/certs_wildcard_nohttps/default.key


+ 0 - 0
test/test_ssl/wildcard_cert_and_nohttps/certs/web.nginx-proxy.tld.crt → test/test_ssl/certs_wildcard_nohttps/web.nginx-proxy.tld.crt


+ 0 - 0
test/test_ssl/wildcard_cert_and_nohttps/certs/web.nginx-proxy.tld.key → test/test_ssl/certs_wildcard_nohttps/web.nginx-proxy.tld.key


+ 6 - 0
test/test_ssl/compose.base.override.yml

@@ -0,0 +1,6 @@
+services:
+  nginx-proxy:
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+      - ${PYTEST_MODULE_PATH}/certs:/etc/nginx/certs:ro
+      - ${PYTEST_MODULE_PATH}/acme_root:/usr/share/nginx/html:ro

+ 10 - 11
test/test_ssl/test_cert-selection.yml

@@ -1,5 +1,13 @@
 services:
-  base: 
+  nginx-proxy:
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+      - ${PYTEST_MODULE_PATH}/cert_selection:/etc/nginx/certs:ro
+      - ${PYTEST_MODULE_PATH}/acme_root:/usr/share/nginx/html:ro
+    environment:
+      DEBUG_ENDPOINT: "true"
+
+  base:
       image: web
       environment:
         WEB_PORTS: "80"
@@ -10,7 +18,7 @@ services:
       environment:
         WEB_PORTS: "80"
         VIRTUAL_HOST: "www.nginx-proxy.tld"
-  
+
   sub-www:
       image: web
       environment:
@@ -22,12 +30,3 @@ services:
       environment:
         WEB_PORTS: "80"
         VIRTUAL_HOST: "web1.nginx-proxy.tld"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./cert_selection:/etc/nginx/certs:ro
-      - ./acme_root:/usr/share/nginx/html:ro
-    environment:
-      DEBUG_ENDPOINT: "true"

+ 4 - 0
test/test_ssl/test_dhparam.yml → test/test_ssl/test_dhparam.base.yml

@@ -1,3 +1,7 @@
+networks:
+  default:
+    name: test_dhparam-net
+
 services:
   web5:
     image: web

+ 6 - 1
test/test_ssl/test_dhparam.py

@@ -1,3 +1,4 @@
+import platform
 import re
 import subprocess
 
@@ -7,6 +8,10 @@ import pytest
 
 docker_client = docker.from_env()
 
+pytestmark = pytest.mark.skipif(
+    platform.system() == "Darwin",
+    reason="Those tests rely entirely on being able to directly contact container's IP"
+)
 
 ###############################################################################
 #
@@ -61,7 +66,7 @@ def require_openssl(required_version):
 @require_openssl("1.0.2")
 def negotiate_cipher(sut_container, additional_params='', grep='Cipher is'):
     sut_container.reload()
-    host = f"{sut_container.attrs['NetworkSettings']['Networks']['test_ssl_default']['IPAddress']}:443"
+    host = f"{sut_container.attrs['NetworkSettings']['Networks']['test_dhparam-net']['IPAddress']}:443"
 
     try:
         # Enforce TLS 1.2 as newer versions don't support custom dhparam or ciphersuite preference.

+ 0 - 6
test/test_ssl/test_hsts.yml

@@ -44,9 +44,3 @@ services:
       VIRTUAL_HOST: http3-vhost-enabled.nginx-proxy.tld
     labels:
       com.github.nginx-proxy.nginx-proxy.http3.enable: "true"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs:/etc/nginx/certs:ro

+ 8 - 10
test/test_ssl/test_https-port.yml

@@ -1,4 +1,12 @@
 services:
+  nginx-proxy:
+    environment:
+      HTTP_PORT: 8080
+      HTTPS_PORT: 8443
+    ports:
+      - "8080:8080"
+      - "8443:8443"
+
   web1:
     image: web
     expose:
@@ -6,13 +14,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: "*.nginx-proxy.tld"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs:/etc/nginx/certs:ro
-      - ./acme_root:/usr/share/nginx/html:ro
-    environment:
-      HTTP_PORT: 8080
-      HTTPS_PORT: 8443

+ 0 - 7
test/test_ssl/test_nohttp.yml

@@ -7,10 +7,3 @@ services:
       WEB_PORTS: "82"
       VIRTUAL_HOST: "web2.nginx-proxy.tld"
       HTTPS_METHOD: nohttp
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs:/etc/nginx/certs:ro
-      - ./acme_root:/usr/share/nginx/html:ro

+ 0 - 6
test/test_ssl/test_nohttps.yml

@@ -7,9 +7,3 @@ services:
       WEB_PORTS: "83"
       VIRTUAL_HOST: "web.nginx-proxy.tld"
       HTTPS_METHOD: nohttps
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./acme_root:/usr/share/nginx/html:ro

+ 0 - 7
test/test_ssl/test_noredirect.yml

@@ -7,10 +7,3 @@ services:
       WEB_PORTS: "83"
       VIRTUAL_HOST: "web3.nginx-proxy.tld"
       HTTPS_METHOD: noredirect
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs:/etc/nginx/certs:ro
-      - ./acme_root:/usr/share/nginx/html:ro

+ 0 - 7
test/test_ssl/test_virtual-path.yml

@@ -18,10 +18,3 @@ services:
       VIRTUAL_HOST: "www.nginx-proxy.tld"
       VIRTUAL_PATH: "/web2/"
       VIRTUAL_DEST: "/"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs:/etc/nginx/certs:ro
-      - ./acme_root:/usr/share/nginx/html:ro

+ 0 - 0
test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py → test/test_ssl/test_wildcard-cert-nohttps.py


+ 9 - 6
test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml → test/test_ssl/test_wildcard-cert-nohttps.yml

@@ -1,13 +1,16 @@
-version: "3"
+# In this scenario, we have a wildcard certificate for `*.web.nginx-proxy.tld` and 3 web containers:
+# - 1.web.nginx-proxy.tld
+# - 2.web.nginx-proxy.tld
+# - 3.web.nginx-proxy.tld
+#
+# We want web containers 1 and 2 to support SSL, but 3 should not (using `HTTPS_METHOD=nohttps`)
 
 services:
-
-  proxy:
-    image: nginxproxy/nginx-proxy:test
+  nginx-proxy:
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs:/etc/nginx/certs:ro
-      - ./acme_root:/usr/share/nginx/html:ro
+      - ${PYTEST_MODULE_PATH}/certs_wildcard_nohttps:/etc/nginx/certs:ro
+      - ${PYTEST_MODULE_PATH}/acme_root:/usr/share/nginx/html:ro
 
   web1:
     image: web

+ 0 - 7
test/test_ssl/test_wildcard.yml

@@ -6,10 +6,3 @@ services:
     environment:
       WEB_PORTS: "81"
       VIRTUAL_HOST: "*.nginx-proxy.tld"
-
-  sut:
-    image: nginxproxy/nginx-proxy:test
-    volumes:
-      - /var/run/docker.sock:/tmp/docker.sock:ro
-      - ./certs:/etc/nginx/certs:ro
-      - ./acme_root:/usr/share/nginx/html:ro

+ 0 - 6
test/test_ssl/wildcard_cert_and_nohttps/README.md

@@ -1,6 +0,0 @@
-In this scenario, we have a wildcard certificate for `*.web.nginx-proxy.tld` and 3 web containers:
-- 1.web.nginx-proxy.tld
-- 2.web.nginx-proxy.tld
-- 3.web.nginx-proxy.tld
-
-We want web containers 1 and 2 to support SSL, but 3 should not (using `HTTPS_METHOD=nohttps`)

Some files were not shown because too many files changed in this diff