From abdd5883a1cc5a6db496f6cb8b7016491b0b7e12 Mon Sep 17 00:00:00 2001 From: Thomas LEVEIL Date: Wed, 8 Mar 2017 02:37:12 +0100 Subject: [PATCH] TESTS: refactor dhparam tests --- test/test_ssl/test_dhparam.py | 123 +++++++++++++--------- test/test_ssl/test_dhparam.yml | 2 +- test/test_ssl/test_dhparam_generation.py | 66 +++++------- test/test_ssl/test_dhparam_generation.yml | 1 + 4 files changed, 101 insertions(+), 91 deletions(-) diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py index 109432a..67b11fa 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -1,74 +1,93 @@ -import pytest -import os -import docker -import time -import subprocess import re +import subprocess + +import backoff +import docker +import pytest docker_client = docker.from_env() -def wait_for_nginxproxy_to_be_ready(): + +############################################################################### +# +# Tests helpers +# +############################################################################### + +@backoff.on_exception(backoff.constant, AssertionError, interval=2, max_tries=15, jitter=None) +def assert_log_contains(expected_log_line): """ - If one (and only one) container started from image jwilder/nginx-proxy:test is found, - wait for its log to contain substring "Watching docker events" + Check that the nginx-proxy container log contains a given string. + The backoff decorator will retry the check 15 times with a 2 seconds delay. + + :param expected_log_line: string to search for + :return: None + :raises: AssertError if the expected string is not found in the log """ - containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) - if len(containers) != 1: - return - container = containers[0] - for line in container.logs(stream=True): - if "Watching docker events" in line: - break - -def test_dhparam_is_not_generated_if_present(docker_compose, nginxproxy): - wait_for_nginxproxy_to_be_ready() - - containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) - if len(containers) != 1: - assert 0 - return - - sut_container = containers[0] - + sut_container = docker_client.containers.get("nginxproxy") docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) + assert expected_log_line in docker_logs - assert "Custom dhparam.pem file found, generation skipped" in docker_logs + +def require_openssl(required_version): + """ + This function checks that the required version of OpenSSL is present, and skips the test if not. + Use it as a test function decorator: + + @require_openssl("2.3.4") + def test_something(): + ... + + :param required_version: minimal required version as a string: "1.2.3" + """ + + def versiontuple(v): + clean_v = re.sub("[^\d\.]", "", v) + return tuple(map(int, (clean_v.split(".")))) + + try: + command_output = subprocess.check_output(["openssl", "version"]) + except OSError: + return pytest.mark.skip("openssl command is not available in test environment") + else: + if not command_output: + raise Exception("Could not get openssl version") + openssl_version = command_output.split()[1] + return pytest.mark.skipif( + versiontuple(openssl_version) < versiontuple(required_version), + reason="openssl v%s is less than required version %s" % (openssl_version, required_version)) + + +############################################################################### +# +# Tests +# +############################################################################### + +def test_dhparam_is_not_generated_if_present(docker_compose): + sut_container = docker_client.containers.get("nginxproxy") + assert sut_container.status == "running" + + assert_log_contains("Custom dhparam.pem file found, generation skipped") # Make sure the dhparam in use is not the default, pre-generated one default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split() current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").split() assert default_checksum[0] != current_checksum[0] + def test_web5_https_works(docker_compose, nginxproxy): r = nginxproxy.get("https://web5.nginx-proxy.tld/port", allow_redirects=False) assert r.status_code == 200 assert "answer from port 85\n" in r.text -def versiontuple(v): - clean_v = re.sub("[^\d\.]", "", v) - return tuple(map(int, (clean_v.split(".")))) - -# This code checks that the required version of OpenSSL is present, and skips the test if not -openssl_version_required = "1.0.2" -openssl_version = "0.0.0" - -try: - openssl_version = subprocess.check_output(["openssl", "version"]).split()[1] -except: - pass - -@pytest.mark.skipif(versiontuple(openssl_version) < versiontuple(openssl_version_required), - reason="openssl command is not available in test environment or is less than version %s" % openssl_version_required) - -def test_web5_dhparam_is_used(docker_compose, nginxproxy): - containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) - if len(containers) != 1: - assert 0 - return - - sut_container = containers[0] +@require_openssl("1.0.2") +def test_web5_dhparam_is_used(docker_compose): + sut_container = docker_client.containers.get("nginxproxy") + assert sut_container.status == "running" host = "%s:443" % sut_container.attrs["NetworkSettings"]["IPAddress"] - r = subprocess.check_output("echo '' | openssl s_client -verify 0 -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True) - assert "Server Temp Key: DH, 2048 bits" in r + r = subprocess.check_output( + "echo '' | openssl s_client -verify 0 -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True) + assert "Server Temp Key: DH, 2048 bits\n" == r diff --git a/test/test_ssl/test_dhparam.yml b/test/test_ssl/test_dhparam.yml index 6e196b0..66b1a61 100644 --- a/test/test_ssl/test_dhparam.yml +++ b/test/test_ssl/test_dhparam.yml @@ -5,11 +5,11 @@ web5: environment: WEB_PORTS: "85" VIRTUAL_HOST: "web5.nginx-proxy.tld" - HTTPS_METHOD: nohttp sut: image: jwilder/nginx-proxy:test + container_name: nginxproxy volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_ssl/test_dhparam_generation.py b/test/test_ssl/test_dhparam_generation.py index 87e71f1..0f5398b 100644 --- a/test/test_ssl/test_dhparam_generation.py +++ b/test/test_ssl/test_dhparam_generation.py @@ -1,52 +1,42 @@ -import pytest -import os +import backoff import docker -import time docker_client = docker.from_env() -def wait_for_nginxproxy_to_be_ready(): + +############################################################################### +# +# Tests helpers +# +############################################################################### + +@backoff.on_exception(backoff.constant, AssertionError, interval=2, max_tries=15, jitter=None) +def assert_log_contains(expected_log_line): """ - If one (and only one) container started from image jwilder/nginx-proxy:test is found, - wait for its log to contain substring "Watching docker events" + Check that the nginx-proxy container log contains a given string. + The backoff decorator will retry the check 15 times with a 2 seconds delay. + + :param expected_log_line: string to search for + :return: None + :raises: AssertError if the expected string is not found in the log """ - containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) - if len(containers) != 1: - return - container = containers[0] - for line in container.logs(stream=True): - if "Watching docker events" in line: - break - -def test_dhparam_is_generated_if_missing(docker_compose, nginxproxy): - wait_for_nginxproxy_to_be_ready() - - containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) - if len(containers) != 1: - assert 0 - return - - sut_container = containers[0] - + sut_container = docker_client.containers.get("nginxproxy") docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) + assert expected_log_line in docker_logs - assert "Generating DH parameters" in docker_logs - expected_line = "dhparam generation complete, reloading nginx" - max_wait = 30 - sleep_interval = 2 - current_wait = 0 +############################################################################### +# +# Tests +# +############################################################################### - while current_wait < max_wait: - docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) - if expected_line in docker_logs: - break +def test_dhparam_is_generated_if_missing(docker_compose): + sut_container = docker_client.containers.get("nginxproxy") + assert sut_container.status == "running" - time.sleep(sleep_interval) - current_wait += sleep_interval - - # Re-check the logs to get better assert output on failure - assert expected_line in docker_logs + assert_log_contains("Generating DH parameters") + assert_log_contains("dhparam generation complete, reloading nginx") # Make sure the dhparam in use is not the default, pre-generated one default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split() diff --git a/test/test_ssl/test_dhparam_generation.yml b/test/test_ssl/test_dhparam_generation.yml index f55cb95..35f3067 100644 --- a/test/test_ssl/test_dhparam_generation.yml +++ b/test/test_ssl/test_dhparam_generation.yml @@ -1,5 +1,6 @@ sut: image: jwilder/nginx-proxy:test + container_name: nginxproxy volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro