Compare commits

...

6 commits

Author SHA1 Message Date
Nicolas Duchon
3537960914 tests: IPv6 issue 2024-12-26 01:00:00 +01:00
Nicolas Duchon
250c808353 tests: IPv6 issue 2024-12-26 00:52:30 +01:00
Nicolas Duchon
0af7d35237 tests: IPv6 issue 2024-12-26 00:46:29 +01:00
Nicolas Duchon
38ccc42af6 tests: IPv6 issue 2024-12-26 00:40:39 +01:00
Nicolas Duchon
69bf2665ec tests: faster tests 2024-12-26 00:20:10 +01:00
Nicolas Duchon
011e0c19cb tests: refactor for use on Darwin 2024-12-25 12:22:03 +01:00
173 changed files with 866 additions and 838 deletions

View file

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

View file

@ -1,21 +1,24 @@
import contextlib import contextlib
import errno
import logging import logging
import os import os
import platform
import re import re
import shlex import shlex
import socket import socket
import subprocess import subprocess
import time import time
from io import StringIO
from typing import List from typing import List
import backoff import backoff
import docker.errors import docker.errors
import pathlib
import pytest import pytest
import requests import requests
from packaging.version import Version
from docker.models.containers import Container from docker.models.containers import Container
from docker.models.networks import Network
from packaging.version import Version
from urllib3.util.connection import HAS_IPV6
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
logging.getLogger('backoff').setLevel(logging.INFO) logging.getLogger('backoff').setLevel(logging.INFO)
@ -40,23 +43,6 @@ test_container = 'nginx-proxy-pytest'
# #
############################################################################### ###############################################################################
def system_has_ipv6() -> bool:
# See https://stackoverflow.com/a/66249915
_ADDR_NOT_AVAIL = {errno.EADDRNOTAVAIL, errno.EAFNOSUPPORT}
_ADDR_IN_USE = {errno.EADDRINUSE}
if not socket.has_ipv6:
return False
try:
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as sock:
sock.bind(("::1", 0))
return True
except OSError as e:
if e.errno in _ADDR_NOT_AVAIL:
return False
if e.errno in _ADDR_IN_USE:
return True
raise
@contextlib.contextmanager @contextlib.contextmanager
def ipv6(force_ipv6=True): def ipv6(force_ipv6=True):
@ -88,6 +74,17 @@ class RequestsForDocker(object):
if os.path.isfile(CA_ROOT_CERTIFICATE): if os.path.isfile(CA_ROOT_CERTIFICATE):
self.session.verify = CA_ROOT_CERTIFICATE self.session.verify = CA_ROOT_CERTIFICATE
@staticmethod
def __backoff_predicate(expected_status_codes=None):
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 @staticmethod
def get_nginx_proxy_containers() -> List[Container]: def get_nginx_proxy_containers() -> List[Container]:
""" """
@ -115,8 +112,16 @@ class RequestsForDocker(object):
return container_ip(nginx_proxy_containers[0]) return container_ip(nginx_proxy_containers[0])
def get(self, *args, **kwargs): 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)): 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): def _get(*_args, **_kwargs):
return self.session.get(*_args, **_kwargs) return self.session.get(*_args, **_kwargs)
return _get(*args, **kwargs) return _get(*args, **kwargs)
@ -168,7 +173,7 @@ def container_ip(container: Container):
""" """
global FORCE_CONTAINER_IPV6 global FORCE_CONTAINER_IPV6
if FORCE_CONTAINER_IPV6: if FORCE_CONTAINER_IPV6:
if not system_has_ipv6(): if not HAS_IPV6:
pytest.skip("This system does not support IPv6") pytest.skip("This system does not support IPv6")
ip = container_ipv6(container) ip = container_ipv6(container)
if ip == '': if ip == '':
@ -272,11 +277,15 @@ def monkey_patch_urllib_dns_resolver():
# Fail early when querying IP directly, and it is forced ipv6 when not supported, # Fail early when querying IP directly, and it is forced ipv6 when not supported,
# Otherwise a pytest container not using the host network fails to pass `test_raw-ip-vhost`. # Otherwise a pytest container not using the host network fails to pass `test_raw-ip-vhost`.
if FORCE_CONTAINER_IPV6 and not system_has_ipv6(): if FORCE_CONTAINER_IPV6 and not HAS_IPV6:
pytest.skip("This system does not support IPv6") pytest.skip("This system does not support IPv6")
# custom DNS resolvers # custom DNS resolvers
ip = nginx_proxy_dns_resolver(args[0]) ip = None
if platform.system() == "Darwin":
ip = "127.0.0.1"
if ip is None:
ip = nginx_proxy_dns_resolver(args[0])
if ip is None: if ip is None:
ip = docker_container_dns_resolver(args[0]) ip = docker_container_dns_resolver(args[0])
if ip is not None: if ip is not None:
@ -312,20 +321,31 @@ def get_nginx_conf_from_container(container):
return conffile.read() return conffile.read()
def docker_compose_up(compose_file='docker-compose.yml'): def __prepare_and_execute_compose_cmd(compose_files:List[str], project_name:str, cmd: str):
logging.info(f'{DOCKER_COMPOSE} -f {compose_file} up -d') 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: 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: 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='docker-compose.yml'): def docker_compose_up(compose_files:List[str], project_name:str):
logging.info(f'{DOCKER_COMPOSE} -f {compose_file} down -v') if compose_files is None or len(compose_files) == 0:
try: pytest.fail(f"No compose file passed to docker_compose_up", pytrace=False)
subprocess.check_output(shlex.split(f'{DOCKER_COMPOSE} -f {compose_file} down -v'), stderr=subprocess.STDOUT) __prepare_and_execute_compose_cmd(compose_files, project_name, cmd="up --detach")
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_down(compose_files:List[str], project_name:str):
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(): def wait_for_nginxproxy_to_be_ready():
@ -333,46 +353,63 @@ def wait_for_nginxproxy_to_be_ready():
If one (and only one) container started from image nginxproxy/nginx-proxy:test is found, 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" wait for its log to contain substring "Watching docker events"
""" """
containers = docker_client.containers.list(filters={"ancestor": "nginxproxy/nginx-proxy:test"}) timeout = time.time() + 10
if len(containers) != 1: while True:
return containers = docker_client.containers.list(
container = containers[0] filters={"status": "running", "ancestor": "nginxproxy/nginx-proxy:test"}
for line in container.logs(stream=True): )
if b"Watching docker events" in line:
logging.debug("nginx-proxy ready") if len(containers) != 1:
break 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 @pytest.fixture
def docker_compose_file(request): def docker_compose_files(request) -> List[str]:
"""Fixture naming the docker compose file to consider. """Fixture naming the docker compose file to consider.
If a YAML file exists with the same name as the test module (with the `.py` extension replaced 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 with `.yml`), use that. Otherwise, use `docker-compose.yml` in the same directory
as the test module. as the test module.
Tests can override this fixture to specify a custom location. Tests can override this fixture to specify a custom location.
""" """
test_module_dir = os.path.dirname(request.module.__file__) compose_files:List[str] = []
yml_file = os.path.join(test_module_dir, request.module.__name__ + '.yml') test_module_path = pathlib.Path(request.module.__file__).parent
yaml_file = os.path.join(test_module_dir, request.module.__name__ + '.yaml')
default_file = os.path.join(test_module_dir, 'docker-compose.yml')
if os.path.isfile(yml_file): module_base_file = test_module_path.joinpath(f"{request.module.__name__}.base.yml")
docker_compose_file = yml_file if module_base_file.is_file():
elif os.path.isfile(yaml_file): return [module_base_file.as_posix()]
docker_compose_file = yaml_file
else:
docker_compose_file = default_file
if not os.path.isfile(docker_compose_file): global_base_file = test_module_path.parent.joinpath("compose.base.yml")
logging.error("Could not find any docker compose file named either '{0}.yml', '{0}.yaml' or 'docker-compose.yml'".format(request.module.__name__)) if global_base_file.is_file():
compose_files.append(global_base_file.as_posix())
logging.debug(f"using docker compose file {docker_compose_file}") module_base_override_file = test_module_path.joinpath("compose.base.override.yml")
return docker_compose_file 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())
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): def connect_to_network(network:Network):
""" """
If we are running from a container, connect our container to the given network If we are running from a container, connect our container to the given network
@ -383,7 +420,7 @@ def connect_to_network(network):
my_container = docker_client.containers.get(test_container) my_container = docker_client.containers.get(test_container)
except docker.errors.NotFound: except docker.errors.NotFound:
logging.warning(f"container {test_container} not found") logging.warning(f"container {test_container} not found")
return return None
# figure out our container networks # figure out our container networks
my_networks = list(my_container.attrs["NetworkSettings"]["Networks"].keys()) my_networks = list(my_container.attrs["NetworkSettings"]["Networks"].keys())
@ -400,7 +437,7 @@ def connect_to_network(network):
return network return network
def disconnect_from_network(network=None): def disconnect_from_network(network:Network=None):
""" """
If we are running from a container, disconnect our container from the given network. If we are running from a container, disconnect our container from the given network.
@ -422,7 +459,7 @@ def disconnect_from_network(network=None):
network.disconnect(my_container) network.disconnect(my_container)
def connect_to_all_networks(): def connect_to_all_networks() -> List[Network]:
""" """
If we are running from a container, connect our container to all current docker networks. If we are running from a container, connect our container to all current docker networks.
@ -439,30 +476,32 @@ def connect_to_all_networks():
class DockerComposer(contextlib.AbstractContextManager): class DockerComposer(contextlib.AbstractContextManager):
def __init__(self): def __init__(self):
self._networks = None self._networks = None
self._docker_compose_file = None self._docker_compose_files = None
self._project_name = None
def __exit__(self, *exc_info): def __exit__(self, *exc_info):
self._down() self._down()
def _down(self): def _down(self):
if self._docker_compose_file is None: if self._docker_compose_files is None:
return return
for network in self._networks: for network in self._networks:
disconnect_from_network(network) 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._docker_compose_file = None
self._project_name = None
def compose(self, docker_compose_file): def compose(self, docker_compose_files:List[str], project_name:str):
if docker_compose_file == self._docker_compose_file: if docker_compose_files == self._docker_compose_files and project_name == self._project_name:
return return
self._down() self._down()
if docker_compose_file is None: if docker_compose_files is None or project_name is None:
return return
docker_compose_up(docker_compose_file) docker_compose_up(docker_compose_files, project_name)
self._networks = connect_to_all_networks() self._networks = connect_to_all_networks()
wait_for_nginxproxy_to_be_ready() wait_for_nginxproxy_to_be_ready()
time.sleep(3) # give time to containers to be ready self._docker_compose_files = docker_compose_files
self._docker_compose_file = docker_compose_file self._project_name = project_name
############################################################################### ###############################################################################
@ -491,7 +530,7 @@ def monkey_patched_dns():
@pytest.fixture @pytest.fixture
def docker_compose(monkey_patched_dns, docker_composer, docker_compose_file): def docker_compose(request, monkeypatch, monkey_patched_dns, docker_composer, docker_compose_files):
"""Ensures containers described in a docker compose file are started. """Ensures containers described in a docker compose file are started.
A custom docker compose file name can be specified by overriding the `docker_compose_file` A custom docker compose file name can be specified by overriding the `docker_compose_file`
@ -500,7 +539,9 @@ def docker_compose(monkey_patched_dns, docker_composer, docker_compose_file):
Also, in the case where pytest is running from a docker container, this fixture makes sure 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. our container will be attached to all the docker networks.
""" """
docker_composer.compose(docker_compose_file) project_name = request.module.__name__
monkeypatch.setenv("PYTEST_MODULE_PATH", pathlib.Path(request.module.__file__).parent.as_posix())
docker_composer.compose(docker_compose_files, project_name)
yield docker_client yield docker_client

View file

@ -3,3 +3,4 @@ docker==7.1.0
packaging==24.2 packaging==24.2
pytest==8.3.4 pytest==8.3.4
requests==2.32.3 requests==2.32.3
urllib3==2.3.0

View file

@ -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

View file

@ -1,10 +1,12 @@
def test_redirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path): def test_redirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get( r = nginxproxy.get(
f"http://web1.nginx-proxy.tld/{acme_challenge_path}", f"http://web1.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False allow_redirects=False,
expected_status_code=301
) )
assert r.status_code == 301 assert r.status_code == 301
def test_redirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path): def test_redirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get( r = nginxproxy.get(
f"http://web2.nginx-proxy.tld/{acme_challenge_path}", 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 assert r.status_code == 200
def test_noredirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path): def test_noredirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get( r = nginxproxy.get(
f"http://web3.nginx-proxy.tld/{acme_challenge_path}", f"http://web3.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False allow_redirects=False,
expected_status_code=404
) )
assert r.status_code == 404 assert r.status_code == 404
def test_noredirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path): def test_noredirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get( r = nginxproxy.get(
f"http://web4.nginx-proxy.tld/{acme_challenge_path}", f"http://web4.nginx-proxy.tld/{acme_challenge_path}",

View file

@ -1,4 +1,8 @@
services: services:
nginx-proxy:
environment:
ACME_HTTP_CHALLENGE_LOCATION: "false"
web1: web1:
image: web image: web
expose: expose:
@ -34,12 +38,3 @@ services:
VIRTUAL_HOST: "web4.nginx-proxy.tld" VIRTUAL_HOST: "web4.nginx-proxy.tld"
HTTPS_METHOD: noredirect HTTPS_METHOD: noredirect
ACME_HTTP_CHALLENGE_LOCATION: "true" 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

View file

@ -5,13 +5,16 @@ def test_redirect_acme_challenge_location_enabled(docker_compose, nginxproxy, ac
) )
assert r.status_code == 200 assert r.status_code == 200
def test_redirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path): def test_redirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get( r = nginxproxy.get(
f"http://web2.nginx-proxy.tld/{acme_challenge_path}", f"http://web2.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False allow_redirects=False,
expected_status_code=301
) )
assert r.status_code == 301 assert r.status_code == 301
def test_noredirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path): def test_noredirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get( r = nginxproxy.get(
f"http://web3.nginx-proxy.tld/{acme_challenge_path}", 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 assert r.status_code == 200
def test_noredirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path): def test_noredirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get( r = nginxproxy.get(
f"http://web4.nginx-proxy.tld/{acme_challenge_path}", f"http://web4.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False allow_redirects=False,
expected_status_code=404
) )
assert r.status_code == 404 assert r.status_code == 404

View file

@ -34,10 +34,3 @@ services:
VIRTUAL_HOST: "web4.nginx-proxy.tld" VIRTUAL_HOST: "web4.nginx-proxy.tld"
HTTPS_METHOD: noredirect HTTPS_METHOD: noredirect
ACME_HTTP_CHALLENGE_LOCATION: "false" 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

View file

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

View file

@ -1,4 +1,8 @@
services: services:
nginx-proxy:
environment:
ACME_HTTP_CHALLENGE_LOCATION: "legacy"
web1: web1:
image: web image: web
expose: expose:
@ -15,12 +19,3 @@ services:
WEB_PORTS: "82" WEB_PORTS: "82"
VIRTUAL_HOST: "web2.nginx-proxy.tld" VIRTUAL_HOST: "web2.nginx-proxy.tld"
HTTPS_METHOD: noredirect 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

View file

@ -2,6 +2,6 @@ import re
def test_custom_error_page(docker_compose, nginxproxy): 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 r.status_code == 503
assert re.search(r"Damn, there's some maintenance in progress.", r.text) assert re.search(r"Damn, there's some maintenance in progress.", r.text)

View file

@ -1,6 +1,5 @@
services: services:
sut: nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes: volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro - /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

View file

@ -1,8 +1,3 @@
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): def test_custom_default_conf_applies_to_web1(docker_compose, nginxproxy):
r = nginxproxy.get("http://web1.nginx-proxy.example/port") r = nginxproxy.get("http://web1.nginx-proxy.example/port")
assert r.status_code == 200 assert r.status_code == 200
@ -10,6 +5,7 @@ def test_custom_default_conf_applies_to_web1(docker_compose, nginxproxy):
assert "X-test" in r.headers assert "X-test" in r.headers
assert "f00" == r.headers["X-test"] assert "f00" == r.headers["X-test"]
def test_custom_default_conf_applies_to_web2(docker_compose, nginxproxy): def test_custom_default_conf_applies_to_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.example/port") r = nginxproxy.get("http://web2.nginx-proxy.example/port")
assert r.status_code == 200 assert r.status_code == 200
@ -24,3 +20,9 @@ def test_custom_default_conf_is_overriden_for_web3(docker_compose, nginxproxy):
assert r.text == "answer from port 83\n" assert r.text == "answer from port 83\n"
assert "X-test" in r.headers assert "X-test" in r.headers
assert "bar" == r.headers["X-test"] 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

View file

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

View file

@ -1,8 +1,3 @@
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): def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
r = nginxproxy.get("http://web1.nginx-proxy.example/port") r = nginxproxy.get("http://web1.nginx-proxy.example/port")
assert r.status_code == 200 assert r.status_code == 200
@ -10,9 +5,16 @@ def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
assert "X-test" in r.headers assert "X-test" in r.headers
assert "f00" == r.headers["X-test"] assert "f00" == r.headers["X-test"]
def test_custom_conf_applies_to_web2(docker_compose, nginxproxy): def test_custom_conf_applies_to_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.example/port") 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 r.text == "answer from port 82\n"
assert "X-test" in r.headers assert "X-test" in r.headers
assert "f00" == r.headers["X-test"] 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

View file

@ -1,9 +1,8 @@
services: services:
nginx-proxy: nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes: volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro - /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: web1:
image: web image: web

View file

@ -1,8 +1,3 @@
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): def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
r = nginxproxy.get("http://web1.nginx-proxy.example/port") r = nginxproxy.get("http://web1.nginx-proxy.example/port")
assert r.status_code == 200 assert r.status_code == 200
@ -10,6 +5,7 @@ def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
assert "X-test" in r.headers assert "X-test" in r.headers
assert "f00" == r.headers["X-test"] assert "f00" == r.headers["X-test"]
def test_custom_conf_applies_to_regex(docker_compose, nginxproxy): def test_custom_conf_applies_to_regex(docker_compose, nginxproxy):
r = nginxproxy.get("http://regex.foo.nginx-proxy.example/port") r = nginxproxy.get("http://regex.foo.nginx-proxy.example/port")
assert r.status_code == 200 assert r.status_code == 200
@ -17,11 +13,19 @@ def test_custom_conf_applies_to_regex(docker_compose, nginxproxy):
assert "X-test" in r.headers assert "X-test" in r.headers
assert "bar" == r.headers["X-test"] assert "bar" == r.headers["X-test"]
def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy): def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.example/port") 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 r.text == "answer from port 82\n"
assert "X-test" not in r.headers 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): 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()

View file

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

View file

@ -1,8 +1,3 @@
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): def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
r = nginxproxy.get("http://web1.nginx-proxy.example/port") r = nginxproxy.get("http://web1.nginx-proxy.example/port")
assert r.status_code == 200 assert r.status_code == 200
@ -10,6 +5,7 @@ def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
assert "X-test" in r.headers assert "X-test" in r.headers
assert "f00" == r.headers["X-test"] assert "f00" == r.headers["X-test"]
def test_custom_conf_applies_to_regex(docker_compose, nginxproxy): def test_custom_conf_applies_to_regex(docker_compose, nginxproxy):
r = nginxproxy.get("http://regex.foo.nginx-proxy.example/port") r = nginxproxy.get("http://regex.foo.nginx-proxy.example/port")
assert r.status_code == 200 assert r.status_code == 200
@ -17,8 +13,15 @@ def test_custom_conf_applies_to_regex(docker_compose, nginxproxy):
assert "X-test" in r.headers assert "X-test" in r.headers
assert "bar" == r.headers["X-test"] assert "bar" == r.headers["X-test"]
def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy): def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.example/port") 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 r.text == "answer from port 82\n"
assert "X-test" not in r.headers 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

View file

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

View file

@ -1,8 +1,3 @@
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): def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
r = nginxproxy.get("http://web1.nginx-proxy.example/port") r = nginxproxy.get("http://web1.nginx-proxy.example/port")
assert r.status_code == 200 assert r.status_code == 200
@ -10,9 +5,16 @@ def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
assert "X-test" in r.headers assert "X-test" in r.headers
assert "f00" == r.headers["X-test"] assert "f00" == r.headers["X-test"]
def test_custom_conf_applies_to_web2(docker_compose, nginxproxy): def test_custom_conf_applies_to_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.example/port") 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 r.text == "answer from port 82\n"
assert "X-test" in r.headers assert "X-test" in r.headers
assert "f00" == r.headers["X-test"] 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

View file

@ -1,9 +1,8 @@
services: services:
nginx-proxy: nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes: volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro - /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: web1:
image: web image: web

View file

@ -14,35 +14,36 @@ def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxp
r = nginxproxy.get("http://enabled.debug.nginx-proxy.example/nginx-proxy-debug") r = nginxproxy.get("http://enabled.debug.nginx-proxy.example/nginx-proxy-debug")
assert r.status_code == 200 assert r.status_code == 200
try: 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: except ValueError as err:
pytest.fail("Failed to parse debug endpoint response as JSON: %s" % err, pytrace=False) 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") r = nginxproxy.get("http://stripped.debug.nginx-proxy.example/nginx-proxy-debug")
assert r.status_code == 200 assert r.status_code == 200
try: 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: except ValueError as err:
pytest.fail("Failed to parse debug endpoint response as JSON: %s" % err, pytrace=False) 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") r = nginxproxy.get("http://regexp.foo.debug.nginx-proxy.example/nginx-proxy-debug")
assert r.status_code == 200 assert r.status_code == 200
try: 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: except ValueError as err:
pytest.fail("Failed to parse debug endpoint response as JSON: %s" % err, pytrace=False) 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): def test_debug_endpoint_is_disabled_per_container(docker_compose, nginxproxy):
r = nginxproxy.get("http://disabled.debug.nginx-proxy.example/nginx-proxy-debug") r = nginxproxy.get("http://disabled.debug.nginx-proxy.example/nginx-proxy-debug", expected_status_code=404)
assert r.status_code == 404 assert r.status_code == 404

View file

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

View file

@ -4,9 +4,9 @@ import pytest
def test_debug_endpoint_is_disabled_globally(docker_compose, nginxproxy): def test_debug_endpoint_is_disabled_globally(docker_compose, nginxproxy):
r = nginxproxy.get("http://disabled1.debug.nginx-proxy.example/nginx-proxy-debug") r = nginxproxy.get("http://disabled1.debug.nginx-proxy.example/nginx-proxy-debug", expected_status_code=404)
assert r.status_code == 404 assert r.status_code == 404
r = nginxproxy.get("http://disabled2.debug.nginx-proxy.example/nginx-proxy-debug") r = nginxproxy.get("http://disabled2.debug.nginx-proxy.example/nginx-proxy-debug", expected_status_code=404)
assert r.status_code == 404 assert r.status_code == 404
@ -19,8 +19,8 @@ def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxp
r = nginxproxy.get("http://enabled.debug.nginx-proxy.example/nginx-proxy-debug") r = nginxproxy.get("http://enabled.debug.nginx-proxy.example/nginx-proxy-debug")
assert r.status_code == 200 assert r.status_code == 200
try: 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: except ValueError as err:
pytest.fail("Failed to parse debug endpoint response as JSON:: %s" % err, pytrace=False) 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

View file

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

View file

@ -1,5 +1,8 @@
services: services:
# GIVEN a webserver with VIRTUAL_HOST set to web1.tld nginx-proxy:
environment:
DEFAULT_HOST: web1.tld
web1: web1:
image: web image: web
expose: expose:
@ -7,11 +10,3 @@ services:
environment: environment:
WEB_PORTS: 81 WEB_PORTS: 81
VIRTUAL_HOST: web1.tld 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

View file

@ -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): def test_forwards_to_web1(docker_compose, nginxproxy):
r = nginxproxy.get("http://web1.nginx-proxy.tld/port") 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" assert r.text == "answer from port 81\n"
def test_forwards_to_web2(docker_compose, nginxproxy): def test_forwards_to_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.tld/port") r = nginxproxy.get("http://web2.nginx-proxy.tld/port")
assert r.status_code == 200 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

View file

@ -1,4 +1,10 @@
services: services:
nginx-proxy:
volumes:
- /var/run/docker.sock:/f00.sock:ro
environment:
DOCKER_HOST: unix:///f00.sock
web1: web1:
image: web image: web
expose: expose:
@ -14,10 +20,3 @@ services:
environment: environment:
WEB_PORTS: 82 WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.tld 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

View file

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

View file

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

View file

@ -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): 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 assert r.status_code == 200
def test_redirect_missing_cert_disabled(docker_compose, nginxproxy): 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 assert r.status_code == 301
def test_redirect_missing_cert_enabled(docker_compose, nginxproxy): def test_redirect_missing_cert_enabled(docker_compose, nginxproxy):
r = nginxproxy.get("http://redirect-missing-cert-enabled.nginx-proxy.tld/", allow_redirects=False) r = nginxproxy.get("http://redirect-missing-cert-enabled.nginx-proxy.tld/", allow_redirects=False)
assert r.status_code == 200 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

View file

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

View file

@ -0,0 +1,6 @@
include:
- ../compose.base.yml
networks:
default:
name: test_events-net

View file

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

View file

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

View file

@ -1,6 +1,5 @@
services: services:
sut: nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes: volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro - /var/run/docker.sock:/tmp/docker.sock:ro
- ./custom-fallback.conf:/etc/nginx/conf.d/zzz-custom-fallback.conf:ro - ./custom-fallback.conf:/etc/nginx/conf.d/zzz-custom-fallback.conf:ro

View file

@ -1,6 +1,5 @@
services: services:
sut: nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes: volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro - /var/run/docker.sock:/tmp/docker.sock:ro
- ./nodefault.certs:/etc/nginx/certs:ro - ./nodefault.certs:/etc/nginx/certs:ro

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,24 +1,23 @@
import os.path
import re import re
from typing import List
import backoff import backoff
import pathlib
import pytest import pytest
import requests import requests
@pytest.fixture @pytest.fixture
def data_dir(): def docker_compose_files(compose_file) -> List[str]:
return f"{os.path.splitext(__file__)[0]}.data" data_dir = pathlib.Path(__file__).parent.joinpath("test_fallback.data")
yield [
data_dir.joinpath("compose.base.yml"),
@pytest.fixture data_dir.joinpath(compose_file).as_posix()
def docker_compose_file(data_dir, compose_file): ]
return os.path.join(data_dir, compose_file)
@pytest.fixture @pytest.fixture
def get(docker_compose, nginxproxy, want_err_re): def get(docker_compose, nginxproxy, want_err_re):
@backoff.on_exception( @backoff.on_exception(
backoff.constant, backoff.constant,
requests.exceptions.SSLError, requests.exceptions.SSLError,
@ -26,10 +25,12 @@ def get(docker_compose, nginxproxy, want_err_re):
interval=.3, interval=.3,
max_tries=30, max_tries=30,
jitter=None) jitter=None)
def _get(url): def _get(url, want_code=None):
return nginxproxy.get(url, allow_redirects=False) if want_code is None:
return nginxproxy.get_without_backoff(url, allow_redirects=False)
return _get else:
return nginxproxy.get(url, allow_redirects=False, expected_status_code=want_code)
yield _get
INTERNAL_ERR_RE = re.compile("TLSV1_UNRECOGNIZED_NAME") INTERNAL_ERR_RE = re.compile("TLSV1_UNRECOGNIZED_NAME")
@ -108,9 +109,9 @@ INTERNAL_ERR_RE = re.compile("TLSV1_UNRECOGNIZED_NAME")
# should prefer that server for handling requests for unknown vhosts. # should prefer that server for handling requests for unknown vhosts.
("custom-fallback.yml", "http://unknown.nginx-proxy.test/", 418, None), ("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: if want_err_re is None:
r = get(url) r = get(url, want_code)
assert r.status_code == want_code assert r.status_code == want_code
else: else:
with pytest.raises(requests.exceptions.SSLError, match=want_err_re): with pytest.raises(requests.exceptions.SSLError, match=want_err_re):

View file

@ -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-----

View file

@ -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-----

View file

@ -11,6 +11,7 @@ def test_X_Forwarded_For_is_generated(docker_compose, nginxproxy):
assert r.status_code == 200 assert r.status_code == 200
assert "X-Forwarded-For:" in r.text assert "X-Forwarded-For:" in r.text
def test_X_Forwarded_For_is_passed_on(docker_compose, nginxproxy): 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'}) r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-For': '1.2.3.4'})
assert r.status_code == 200 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 r.status_code == 200
assert "X-Forwarded-Proto: http" in r.text assert "X-Forwarded-Proto: http" in r.text
def test_X_Forwarded_Proto_is_passed_on(docker_compose, nginxproxy): 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'}) r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Proto': 'f00'})
assert r.status_code == 200 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 r.status_code == 200
assert "X-Forwarded-Host: web.nginx-proxy.tld\n" in r.text assert "X-Forwarded-Host: web.nginx-proxy.tld\n" in r.text
def test_X_Forwarded_Host_is_passed_on(docker_compose, nginxproxy): 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'}) r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Host': 'example.com'})
assert r.status_code == 200 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 r.status_code == 200
assert "X-Forwarded-Port: 80\n" in r.text assert "X-Forwarded-Port: 80\n" in r.text
def test_X_Forwarded_Port_is_passed_on(docker_compose, nginxproxy): 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'}) r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Port': '1234'})
assert r.status_code == 200 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 r.status_code == 200
assert "X-Forwarded-Ssl: off\n" in r.text assert "X-Forwarded-Ssl: off\n" in r.text
def test_X_Forwarded_Ssl_is_overwritten(docker_compose, nginxproxy): def test_X_Forwarded_Ssl_is_overwritten(docker_compose, nginxproxy):
r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Ssl': 'f00'}) r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Ssl': 'f00'})
assert r.status_code == 200 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 r.status_code == 200
assert "X-Real-IP: " in r.text assert "X-Real-IP: " in r.text
def test_Host_is_passed_on(docker_compose, nginxproxy): def test_Host_is_passed_on(docker_compose, nginxproxy):
r = nginxproxy.get("http://web.nginx-proxy.tld/headers") r = nginxproxy.get("http://web.nginx-proxy.tld/headers")
assert r.status_code == 200 assert r.status_code == 200
assert "Host: web.nginx-proxy.tld" in r.text assert "Host: web.nginx-proxy.tld" in r.text
def test_httpoxy_safe(docker_compose, nginxproxy): def test_httpoxy_safe(docker_compose, nginxproxy):
""" """
See https://httpoxy.org/ 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): def test_no_host_server_tokens_off(docker_compose, nginxproxy):
ip = nginxproxy.get_ip() 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.status_code == 503
assert r.headers["Server"] == "nginx" assert r.headers["Server"] == "nginx"

View file

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

View file

@ -14,6 +14,7 @@ def test_X_Forwarded_For_is_generated(docker_compose, nginxproxy):
assert r.status_code == 200 assert r.status_code == 200
assert "X-Forwarded-For:" in r.text assert "X-Forwarded-For:" in r.text
def test_X_Forwarded_For_is_passed_on(docker_compose, nginxproxy): 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'}) r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-For': '1.2.3.4'})
assert r.status_code == 200 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 r.status_code == 200
assert "X-Forwarded-Proto: https" in r.text assert "X-Forwarded-Proto: https" in r.text
def test_X_Forwarded_Proto_is_passed_on(docker_compose, nginxproxy): 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'}) r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Proto': 'f00'})
assert r.status_code == 200 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 r.status_code == 200
assert "X-Forwarded-Host: web.nginx-proxy.tld\n" in r.text assert "X-Forwarded-Host: web.nginx-proxy.tld\n" in r.text
def test_X_Forwarded_Host_is_passed_on(docker_compose, nginxproxy): 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'}) r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Host': 'example.com'})
assert r.status_code == 200 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 r.status_code == 200
assert "X-Forwarded-Port: 443\n" in r.text assert "X-Forwarded-Port: 443\n" in r.text
def test_X_Forwarded_Port_is_passed_on(docker_compose, nginxproxy): 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'}) r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Port': '1234'})
assert r.status_code == 200 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 r.status_code == 200
assert "X-Forwarded-Ssl: on\n" in r.text assert "X-Forwarded-Ssl: on\n" in r.text
def test_X_Forwarded_Ssl_is_overwritten(docker_compose, nginxproxy): def test_X_Forwarded_Ssl_is_overwritten(docker_compose, nginxproxy):
r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Ssl': 'f00'}) r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Ssl': 'f00'})
assert r.status_code == 200 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 r.status_code == 200
assert "X-Real-IP: " in r.text assert "X-Real-IP: " in r.text
def test_Host_is_passed_on(docker_compose, nginxproxy): def test_Host_is_passed_on(docker_compose, nginxproxy):
r = nginxproxy.get("https://web.nginx-proxy.tld/headers") r = nginxproxy.get("https://web.nginx-proxy.tld/headers")
assert r.status_code == 200 assert r.status_code == 200
assert "Host: web.nginx-proxy.tld" in r.text assert "Host: web.nginx-proxy.tld" in r.text
def test_httpoxy_safe(docker_compose, nginxproxy): def test_httpoxy_safe(docker_compose, nginxproxy):
""" """
See https://httpoxy.org/ See https://httpoxy.org/
@ -97,7 +104,7 @@ def test_httpoxy_safe(docker_compose, nginxproxy):
@pytest.mark.filterwarnings('ignore::urllib3.exceptions.InsecureRequestWarning') @pytest.mark.filterwarnings('ignore::urllib3.exceptions.InsecureRequestWarning')
def test_no_host_server_tokens_off(docker_compose, nginxproxy): def test_no_host_server_tokens_off(docker_compose, nginxproxy):
ip = nginxproxy.get_ip() 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.status_code == 503
assert r.headers["Server"] == "nginx" assert r.headers["Server"] == "nginx"

View file

@ -1,4 +1,9 @@
services: services:
nginx-proxy:
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ${PYTEST_MODULE_PATH}/certs:/etc/nginx/certs:ro
web: web:
image: web image: web
expose: expose:
@ -15,14 +20,3 @@ services:
WEB_PORTS: 80 WEB_PORTS: 80
VIRTUAL_HOST: web-server-tokens-off.nginx-proxy.tld VIRTUAL_HOST: web-server-tokens-off.nginx-proxy.tld
SERVER_TOKENS: "off" 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

View file

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

View file

@ -1,4 +1,13 @@
services: services:
nginx-proxy:
image: nginxproxy/nginx-proxy:test
container_name: nginx-proxy
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
environment:
HTTP_PORT: 8888
network_mode: host
host-network-1: host-network-1:
image: web image: web
environment: environment:
@ -14,11 +23,3 @@ services:
VIRTUAL_HOST: "host-network-2.nginx-proxy.tld" VIRTUAL_HOST: "host-network-2.nginx-proxy.tld"
VIRTUAL_PORT: "8181" VIRTUAL_PORT: "8181"
network_mode: host 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

View file

@ -1,9 +1,16 @@
import platform
import pytest
@pytest.mark.xfail(platform.system() == "Darwin", reason="Host networking only work on Linux")
def test_forwards_to_host_network_container_1(docker_compose, nginxproxy): def test_forwards_to_host_network_container_1(docker_compose, nginxproxy):
r = nginxproxy.get("http://host-network-1.nginx-proxy.tld:8888/port") r = nginxproxy.get("http://host-network-1.nginx-proxy.tld:8888/port")
assert r.status_code == 200 assert r.status_code == 200
assert r.text == "answer from port 8080\n" assert r.text == "answer from port 8080\n"
@pytest.mark.xfail(platform.system() == "Darwin", reason="Host networking only work on Linux")
def test_forwards_to_host_network_container_2(docker_compose, nginxproxy): def test_forwards_to_host_network_container_2(docker_compose, nginxproxy):
r = nginxproxy.get("http://host-network-2.nginx-proxy.tld:8888/port") r = nginxproxy.get("http://host-network-2.nginx-proxy.tld:8888/port")
assert r.status_code == 200 assert r.status_code == 200

View file

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

View file

@ -1,5 +1,5 @@
def test_htpasswd_regex_virtual_host_is_restricted(docker_compose, nginxproxy): 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 r.status_code == 401
assert "WWW-Authenticate" in r.headers assert "WWW-Authenticate" in r.headers
assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted access"' assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted access"'

View file

@ -6,10 +6,3 @@ services:
environment: environment:
WEB_PORTS: 80 WEB_PORTS: 80
VIRTUAL_HOST: ~^regex.*\.nginx-proxy\.example$ 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

View file

@ -1,5 +1,5 @@
def test_htpasswd_virtual_host_is_restricted(docker_compose, nginxproxy): 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 r.status_code == 401
assert "WWW-Authenticate" in r.headers assert "WWW-Authenticate" in r.headers
assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted htpasswd.nginx-proxy.tld"' assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted htpasswd.nginx-proxy.tld"'

View file

@ -6,10 +6,3 @@ services:
environment: environment:
WEB_PORTS: 80 WEB_PORTS: 80
VIRTUAL_HOST: htpasswd.nginx-proxy.tld 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

View file

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

View file

@ -8,10 +8,3 @@ services:
VIRTUAL_HOST: htpasswd.nginx-proxy.tld VIRTUAL_HOST: htpasswd.nginx-proxy.tld
VIRTUAL_PATH: /foo/ VIRTUAL_PATH: /foo/
VIRTUAL_DEST: / 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

View file

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

View file

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

View file

@ -1,4 +1,8 @@
services: services:
nginx-proxy:
environment:
ENABLE_HTTP2: "false"
http2-global-disabled: http2-global-disabled:
image: web image: web
expose: expose:
@ -6,10 +10,3 @@ services:
environment: environment:
WEB_PORTS: 80 WEB_PORTS: 80
VIRTUAL_HOST: http2-global-disabled.nginx-proxy.tld 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"

View file

@ -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 "Host: http3-global-disabled.nginx-proxy.tld" in r.text
assert not "alt-svc" in r.headers assert not "alt-svc" in r.headers
def test_http3_global_disabled_config(docker_compose, nginxproxy): def test_http3_global_disabled_config(docker_compose, nginxproxy):
conf = nginxproxy.get_conf().decode('ASCII') conf = nginxproxy.get_conf().decode('ASCII')
r = nginxproxy.get("http://http3-global-disabled.nginx-proxy.tld") r = nginxproxy.get("http://http3-global-disabled.nginx-proxy.tld")

View file

@ -1,4 +1,8 @@
services: services:
# nginx-proxy:
# environment:
# ENABLE_HTTP3: "false" #Disabled by default
http3-global-disabled: http3-global-disabled:
image: web image: web
expose: expose:
@ -6,10 +10,3 @@ services:
environment: environment:
WEB_PORTS: 80 WEB_PORTS: 80
VIRTUAL_HOST: http3-global-disabled.nginx-proxy.tld 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

View file

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

View file

@ -1,4 +1,8 @@
services: services:
nginx-proxy:
environment:
ENABLE_HTTP3: "true"
http3-global-enabled: http3-global-enabled:
image: web image: web
expose: expose:
@ -6,10 +10,3 @@ services:
environment: environment:
WEB_PORTS: 80 WEB_PORTS: 80
VIRTUAL_HOST: http3-global-enabled.nginx-proxy.tld 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"

View file

@ -11,28 +11,32 @@ def test_http3_vhost_enabled_ALTSVC_header(docker_compose, nginxproxy):
assert "alt-svc" in r.headers assert "alt-svc" in r.headers
assert r.headers["alt-svc"] == 'h3=":443"; ma=86400;' assert r.headers["alt-svc"] == 'h3=":443"; ma=86400;'
def test_http3_vhost_enabled_config(docker_compose, nginxproxy): def test_http3_vhost_enabled_config(docker_compose, nginxproxy):
conf = nginxproxy.get_conf().decode('ASCII') conf = nginxproxy.get_conf().decode('ASCII')
r = nginxproxy.get("http://http3-vhost-enabled.nginx-proxy.tld") r = nginxproxy.get("http://http3-vhost-enabled.nginx-proxy.tld")
assert r.status_code == 200 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;.*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) 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): def test_http3_vhost_disabled_ALTSVC_header(docker_compose, nginxproxy):
r = nginxproxy.get("http://http3-vhost-disabled.nginx-proxy.tld/headers") r = nginxproxy.get("http://http3-vhost-disabled.nginx-proxy.tld/headers")
assert r.status_code == 200 assert r.status_code == 200
assert "Host: http3-vhost-disabled.nginx-proxy.tld" in r.text assert "Host: http3-vhost-disabled.nginx-proxy.tld" in r.text
assert not "alt-svc" in r.headers assert not "alt-svc" in r.headers
def test_http3_vhost_disabled_config(docker_compose, nginxproxy): def test_http3_vhost_disabled_config(docker_compose, nginxproxy):
conf = nginxproxy.get_conf().decode('ASCII') conf = nginxproxy.get_conf().decode('ASCII')
r = nginxproxy.get("http://http3-vhost-disabled.nginx-proxy.tld") r = nginxproxy.get("http://http3-vhost-disabled.nginx-proxy.tld")
assert r.status_code == 200 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.*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.*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;.*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): def test_http3_vhost_disabledbydefault_ALTSVC_header(docker_compose, nginxproxy):
r = nginxproxy.get("http://http3-vhost-default-disabled.nginx-proxy.tld/headers") 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 "Host: http3-vhost-default-disabled.nginx-proxy.tld" in r.text
assert not "alt-svc" in r.headers assert not "alt-svc" in r.headers
def test_http3_vhost_disabledbydefault_config(docker_compose, nginxproxy): def test_http3_vhost_disabledbydefault_config(docker_compose, nginxproxy):
conf = nginxproxy.get_conf().decode('ASCII') conf = nginxproxy.get_conf().decode('ASCII')
r = nginxproxy.get("http://http3-vhost-default-disabled.nginx-proxy.tld") r = nginxproxy.get("http://http3-vhost-default-disabled.nginx-proxy.tld")
assert r.status_code == 200 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.*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.*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;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'.*# http3-vhost-disabled\.nginx-proxy\.tld", conf)

View file

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

View file

@ -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

View file

@ -5,6 +5,7 @@ def test_network_web1(docker_compose, nginxproxy):
assert "X-network" in r.headers assert "X-network" in r.headers
assert "internal" == r.headers["X-network"] assert "internal" == r.headers["X-network"]
def test_network_web2(docker_compose, nginxproxy): def test_network_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.example/port") r = nginxproxy.get("http://web2.nginx-proxy.example/port")
assert r.status_code == 200 assert r.status_code == 200

View file

@ -15,9 +15,3 @@ services:
environment: environment:
WEB_PORTS: 82 WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.example 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

View file

@ -5,6 +5,7 @@ def test_network_web1(docker_compose, nginxproxy):
assert "X-network" in r.headers assert "X-network" in r.headers
assert "internal" == r.headers["X-network"] assert "internal" == r.headers["X-network"]
def test_network_web2(docker_compose, nginxproxy): def test_network_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://nginx-proxy.example/web2/port") r = nginxproxy.get("http://nginx-proxy.example/web2/port")
assert r.status_code == 200 assert r.status_code == 200

View file

@ -20,8 +20,3 @@ services:
VIRTUAL_PATH: /web2/ VIRTUAL_PATH: /web2/
VIRTUAL_DEST: / 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

View file

@ -11,6 +11,14 @@ networks:
- subnet: fd00:cafe:face:feed::/64 - subnet: fd00:cafe:face:feed::/64
services: 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: ipv4only:
image: web image: web
expose: expose:
@ -31,13 +39,3 @@ services:
ipv4_address: 172.16.20.2 ipv4_address: 172.16.20.2
ipv6_address: fd00:cafe:face:feed::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

View file

@ -11,6 +11,16 @@ networks:
- subnet: fd00:cafe:face:feed::/64 - subnet: fd00:cafe:face:feed::/64
services: 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: ipv4only:
image: web image: web
expose: expose:
@ -31,15 +41,3 @@ services:
ipv4_address: 172.16.20.2 ipv4_address: 172.16.20.2
ipv6_address: fd00:cafe:face:feed::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

View file

@ -1,8 +1,3 @@
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): def test_forwards_to_web1_ipv4(docker_compose, nginxproxy):
r = nginxproxy.get("http://web1.nginx-proxy.tld/port") r = nginxproxy.get("http://web1.nginx-proxy.tld/port")
assert r.status_code == 200 assert r.status_code == 200
@ -15,8 +10,8 @@ def test_forwards_to_web2_ipv4(docker_compose, nginxproxy):
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): def test_unknown_virtual_host_ipv4(docker_compose, nginxproxy):
r = nginxproxy.get("http://nginx-proxy/port", ipv6=True) r = nginxproxy.get("http://nginx-proxy/port", expected_status_code=503)
assert r.status_code == 503 assert r.status_code == 503
@ -30,3 +25,8 @@ def test_forwards_to_web2_ipv6(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.tld/port", ipv6=True) r = nginxproxy.get("http://web2.nginx-proxy.tld/port", ipv6=True)
assert r.status_code == 200 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

View file

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

View file

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

View file

@ -1,4 +1,8 @@
services: services:
nginx-proxy:
environment:
HTTPS_METHOD: nohttps
keepalive-disabled: keepalive-disabled:
image: web image: web
expose: expose:
@ -30,9 +34,3 @@ services:
WEB_PORTS: 80 WEB_PORTS: 80
VIRTUAL_HOST: keepalive-auto.nginx-proxy.test 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

View file

@ -1,15 +1,18 @@
import re import re
import time
def test_loadbalance_hash(docker_compose, nginxproxy): def test_loadbalance_hash(docker_compose, nginxproxy):
conf = nginxproxy.get_conf().decode('ASCII') conf = nginxproxy.get_conf().decode('ASCII')
r1 = nginxproxy.get("http://loadbalance-enabled.nginx-proxy.tld") r1 = nginxproxy.get("http://loadbalance-enabled.nginx-proxy.tld")
r2 = 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 r1.status_code == 200
assert r2.text == r1.text assert r2.text == r1.text
def test_loadbalance_roundrobin(docker_compose, nginxproxy): def test_loadbalance_roundrobin(docker_compose, nginxproxy):
time.sleep(3)
r1 = nginxproxy.get("http://loadbalance-disabled.nginx-proxy.tld") r1 = nginxproxy.get("http://loadbalance-disabled.nginx-proxy.tld")
r2 = nginxproxy.get("http://loadbalance-disabled.nginx-proxy.tld") r2 = nginxproxy.get("http://loadbalance-disabled.nginx-proxy.tld")
assert r1.status_code == 200 assert r1.status_code == 200

View file

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

View file

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

View file

@ -1,9 +1,8 @@
services: services:
sut: nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes: volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro - /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: explicit-root:
image: web image: web

View file

@ -1,8 +1,12 @@
import time
def test_log_disabled(docker_compose, nginxproxy): def test_log_disabled(docker_compose, nginxproxy):
time.sleep(3)
r = nginxproxy.get("http://nginx-proxy.test/port") r = nginxproxy.get("http://nginx-proxy.test/port")
assert r.status_code == 200 assert r.status_code == 200
assert r.text == "answer from port 81\n" 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 = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
docker_logs = docker_logs.decode("utf-8").splitlines() docker_logs = docker_logs.decode("utf-8").splitlines()
docker_logs = [line for line in docker_logs if "GET /port" in line] docker_logs = [line for line in docker_logs if "GET /port" in line]

View file

@ -1,4 +1,8 @@
services: services:
nginx-proxy:
environment:
DISABLE_ACCESS_LOGS: true
web1: web1:
image: web image: web
expose: expose:
@ -6,11 +10,3 @@ services:
environment: environment:
WEB_PORTS: 81 WEB_PORTS: 81
VIRTUAL_HOST: nginx-proxy.test 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

View file

@ -1,8 +1,12 @@
import time
def test_log_format(docker_compose, nginxproxy): def test_log_format(docker_compose, nginxproxy):
time.sleep(3)
r = nginxproxy.get("http://nginx-proxy.test/port") r = nginxproxy.get("http://nginx-proxy.test/port")
assert r.status_code == 200 assert r.status_code == 200
assert r.text == "answer from port 81\n" 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 = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
docker_logs = docker_logs.decode("utf-8").splitlines() docker_logs = docker_logs.decode("utf-8").splitlines()
docker_logs = [line for line in docker_logs if "GET /port" in line] docker_logs = [line for line in docker_logs if "GET /port" in line]

View file

@ -1,4 +1,8 @@
services: 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: web1:
image: web image: web
expose: expose:
@ -6,11 +10,3 @@ services:
environment: environment:
WEB_PORTS: 81 WEB_PORTS: 81
VIRTUAL_HOST: nginx-proxy.test 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'

View file

@ -1,11 +1,12 @@
def test_log_json_format(docker_compose, nginxproxy): 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] assert "{\"time_local\":\"$time_iso8601\"," in log_conf[0]
r = nginxproxy.get("http://nginx-proxy.test/port") r = nginxproxy.get("http://nginx-proxy.test/port")
assert r.status_code == 200 assert r.status_code == 200
assert r.text == "answer from port 81\n" 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 = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
docker_logs = docker_logs.decode("utf-8").splitlines() docker_logs = docker_logs.decode("utf-8").splitlines()
docker_logs = [line for line in docker_logs if "{\"time_local\":" in line] docker_logs = [line for line in docker_logs if "{\"time_local\":" in line]

View file

@ -1,4 +1,8 @@
services: services:
nginx-proxy:
environment:
LOG_FORMAT: '{"time_local":"$$time_iso8601","remote_addr":"$$remote_addr","request":"$$request","upstream_addr":"$$upstream_addr"}'
web1: web1:
image: web image: web
expose: expose:
@ -6,11 +10,3 @@ services:
environment: environment:
WEB_PORTS: 81 WEB_PORTS: 81
VIRTUAL_HOST: nginx-proxy.test 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"}'

View file

@ -1,11 +1,12 @@
def test_log_json(docker_compose, nginxproxy): 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] assert "{\"time_local\":\"$time_iso8601\"," in log_conf[0]
r = nginxproxy.get("http://nginx-proxy.test/port") r = nginxproxy.get("http://nginx-proxy.test/port")
assert r.status_code == 200 assert r.status_code == 200
assert r.text == "answer from port 81\n" 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 = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
docker_logs = docker_logs.decode("utf-8").splitlines() docker_logs = docker_logs.decode("utf-8").splitlines()
docker_logs = [line for line in docker_logs if "{\"time_local\":" in line] docker_logs = [line for line in docker_logs if "{\"time_local\":" in line]

View file

@ -1,4 +1,8 @@
services: services:
nginx-proxy:
environment:
LOG_JSON: 1
web1: web1:
image: web image: web
expose: expose:
@ -6,11 +10,3 @@ services:
environment: environment:
WEB_PORTS: 81 WEB_PORTS: 81
VIRTUAL_HOST: nginx-proxy.test 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

View file

@ -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): def test_webA_is_forwarded(docker_compose, nginxproxy):
r = nginxproxy.get("http://webA.nginx-proxy.tld/port") r = nginxproxy.get("http://webA.nginx-proxy.tld/port")
assert r.status_code == 200 assert r.status_code == 200
assert r.text == "answer from port 81\n" assert r.text == "answer from port 81\n"
def test_webB_is_forwarded(docker_compose, nginxproxy): def test_webB_is_forwarded(docker_compose, nginxproxy):
r = nginxproxy.get("http://webB.nginx-proxy.tld/port") r = nginxproxy.get("http://webB.nginx-proxy.tld/port")
assert r.status_code == 200 assert r.status_code == 200
assert r.text == "answer from port 81\n" 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

View file

@ -6,8 +6,3 @@ services:
environment: environment:
WEB_PORTS: 81 WEB_PORTS: 81
VIRTUAL_HOST: webA.nginx-proxy.tld,webB.nginx-proxy.tld 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

View file

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

View file

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

View file

@ -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") r = nginxproxy.get("http://notskipped.nginx-proxy.tld/port")
assert r.status_code == 200 assert r.status_code == 200
assert "answer from port 81\n" in r.text 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 assert r.status_code == 503

View file

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

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