From 47511f1010e33b5d60fecbfdf88cd24071d070bd Mon Sep 17 00:00:00 2001 From: Zsombor Welker <fedora@zdeqb.com> Date: Sun, 26 Jun 2022 11:15:14 +0200 Subject: [PATCH] Add integration tests --- test/__init__.py | 0 test/integration/functions.sh | 90 +++++++++++++++++++++++++++++++ test/integration/test_compose.sh | 48 +++++++++++++++++ test/integration/test_hostname.sh | 17 ++++++ test/integration/test_hostnet.sh | 17 ++++++ test/integration/test_id_only.sh | 24 +++++++++ test/integration/test_network.sh | 41 ++++++++++++++ test/integration/test_proxy.sh | 22 ++++++++ test/integration/test_wildcard.sh | 11 ++++ test/test_integration.py | 36 +++++++++++++ 10 files changed, 306 insertions(+) create mode 100644 test/__init__.py create mode 100644 test/integration/functions.sh create mode 100755 test/integration/test_compose.sh create mode 100755 test/integration/test_hostname.sh create mode 100755 test/integration/test_hostnet.sh create mode 100755 test/integration/test_id_only.sh create mode 100755 test/integration/test_network.sh create mode 100755 test/integration/test_proxy.sh create mode 100755 test/integration/test_wildcard.sh create mode 100644 test/test_integration.py diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/integration/functions.sh b/test/integration/functions.sh new file mode 100644 index 0000000..18dfc84 --- /dev/null +++ b/test/integration/functions.sh @@ -0,0 +1,90 @@ +set -e + +TEST_PREFIX="$(cat /dev/urandom | tr -dc 'a-z0-9' | head -c 10)" +TEST_LABEL="systemd-resolved-docker=test-${TEST_PREFIX}" + +trap "cleanup" EXIT + +cleanup() { + stop_systemd_resolved_docker + docker ps --all --filter label=${TEST_LABEL} --format '{{ .ID }}' | xargs --no-run-if-empty docker rm --force > /dev/null + docker network ls --filter label=${TEST_LABEL} --format '{{ .ID }}' | xargs --no-run-if-empty docker network rm > /dev/null +} + +start_systemd_resolved_docker() { + stop_systemd_resolved_docker + + PYTHONPATH="$PWD/../../src:$PYTHONPATH" python -m systemd_resolved_docker.cli & + SYSTEMD_RESOLVED_DOCKER_PID=$! + + sleep 2 +} + +stop_systemd_resolved_docker() { + if [ ! -z "$SYSTEMD_RESOLVED_DOCKER_PID" ]; + then + kill $SYSTEMD_RESOLVED_DOCKER_PID || true + sleep 1 + + SYSTEMD_RESOLVED_DOCKER_PID="" + fi +} + +docker_run() { + local name=$1 + shift; + + docker run --detach --label "${TEST_LABEL}" --name "${TEST_PREFIX}-$name" --interactive $@ alpine | cut -c -12 +} + +docker_ip() { + local container_id=$1 + shift; + + docker inspect --format '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $container_id +} + +docker_name() { + local container_id=$1 + shift; + + docker inspect --format '{{ .Name }}' $container_id | cut -c2- +} + +query_ok() { + local query=$1 + local ip=$2 + shift; shift; + + if resolvectl query $query | grep $ip; + then + true + else + >&2 echo "Failed to resolve $query to $ip" + false + fi +} + +query_fail() { + local query=$1 + shift; + + if resolvectl query $query; + then + >&2 echo "Failing, resolved $query" + false + else + true + fi +} + +test_query() { + local name=$1 + local query=$2 + shift; shift; + + local id=$(docker_run $name $@) + local ip=$(docker_ip $id) + + query_ok $query $ip +} diff --git a/test/integration/test_compose.sh b/test/integration/test_compose.sh new file mode 100755 index 0000000..cd136a6 --- /dev/null +++ b/test/integration/test_compose.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +. ./functions.sh + +exec 10<<EOF +version: "2.1" +services: + webserver: + image: nginx + labels: + - $TEST_LABEL + networks: + - network + broker: + image: redis + labels: + - $TEST_LABEL + networks: + - network + +networks: + network: + driver: bridge + enable_ipv6: false + labels: + - $TEST_LABEL + ipam: + driver: default + config: + - subnet: 172.16.238.0/24 + gateway: 172.16.238.1 +EOF + +ALLOWED_DOMAINS=.docker,.$TEST_PREFIX start_systemd_resolved_docker + +docker-compose --file /dev/fd/10 --project-name $TEST_PREFIX up --detach --scale webserver=2 + +broker1_ip=$(docker_ip ${TEST_PREFIX}_broker_1) +webserver1_ip=$(docker_ip ${TEST_PREFIX}_webserver_1) +webserver2_ip=$(docker_ip ${TEST_PREFIX}_webserver_2) + +query_ok broker.$TEST_PREFIX $broker1_ip +query_ok 1.broker.$TEST_PREFIX $broker1_ip + +query_ok webserver.$TEST_PREFIX $webserver1_ip +query_ok webserver.$TEST_PREFIX $webserver2_ip +query_ok 1.webserver.$TEST_PREFIX $webserver1_ip +query_ok 2.webserver.$TEST_PREFIX $webserver2_ip diff --git a/test/integration/test_hostname.sh b/test/integration/test_hostname.sh new file mode 100755 index 0000000..b0a52eb --- /dev/null +++ b/test/integration/test_hostname.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +. ./functions.sh + +ALLOWED_DOMAINS=.docker,host2,.domain2 start_systemd_resolved_docker + +test_query hostname1 host1.docker --hostname host1 +query_fail host1 + +test_query hostname2 host2.docker --hostname host2 +query_fail host2 + +test_query hostdomain1 host1.domain1.docker --hostname host1 --domainname domain1 +query_fail host1.domain1 + +test_query hostdomain2 host2.domain2 --hostname host2 --domainname domain2 +query_fail host2.domain2.docker \ No newline at end of file diff --git a/test/integration/test_hostnet.sh b/test/integration/test_hostnet.sh new file mode 100755 index 0000000..e87fbcc --- /dev/null +++ b/test/integration/test_hostnet.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +. ./functions.sh + +container_id=$(docker_run hostnet1 --network host --hostname hostnet1) + +start_systemd_resolved_docker + +query_ok $container_id.docker 127.0.0.1 +query_ok hostnet1.docker 127.0.0.1 +query_ok ${TEST_PREFIX}-hostnet1.host.docker 127.0.0.1 + +DEFAULT_HOST_IP=1.2.3.4 start_systemd_resolved_docker + +query_ok $container_id.docker 1.2.3.4 +query_ok hostnet1.docker 1.2.3.4 +query_ok ${TEST_PREFIX}-hostnet1.host.docker 1.2.3.4 diff --git a/test/integration/test_id_only.sh b/test/integration/test_id_only.sh new file mode 100755 index 0000000..a6f24ad --- /dev/null +++ b/test/integration/test_id_only.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +. ./functions.sh + +container1_id=$(docker_run id1) +container1_ip=$(docker_ip ${container1_id}) +container2_id=$(docker_run id2) +container2_ip=$(docker_ip ${container2_id}) + + +DEFAULT_DOMAIN=dockerx ALLOWED_DOMAINS=.dockerx start_systemd_resolved_docker +query_ok ${container1_id}.dockerx $container1_ip +query_ok ${container2_id}.dockerx $container2_ip + +query_fail ${container1_id}.docker +query_fail ${container2_id}.docker + + +DEFAULT_DOMAIN=test123 ALLOWED_DOMAINS=.docker start_systemd_resolved_docker +query_ok ${container1_id}.test123 $container1_ip +query_ok ${container2_id}.test123 $container2_ip + +query_fail ${container1_id}.docker +query_fail ${container2_id}.docker diff --git a/test/integration/test_network.sh b/test/integration/test_network.sh new file mode 100755 index 0000000..90073a5 --- /dev/null +++ b/test/integration/test_network.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +. ./functions.sh + +NETWORK1=testnet1-$TEST_PREFIX +NETWORK2=testnet2-$TEST_PREFIX + +docker network create --label $TEST_LABEL $NETWORK1 > /dev/null +docker network create --label $TEST_LABEL $NETWORK2 > /dev/null + +ALLOWED_DOMAINS=.docker,.$NETWORK1 start_systemd_resolved_docker + +container1_id=$(docker_run network1 --network $NETWORK1) +container1_ip=$(docker_ip ${container1_id}) +container1_name=$(docker_name ${container1_id}) + +container2_id=$(docker_run network2 --name name2 --network $NETWORK1) +container2_ip=$(docker_ip ${container2_id}) +container2_name=$(docker_name ${container2_id}) + +container3_id=$(docker_run network3 --network $NETWORK2) +container3_ip=$(docker_ip ${container3_id}) +container3_name=$(docker_name ${container3_id}) + +container4_id=$(docker_run network4 --name name4 --network $NETWORK2) +container4_ip=$(docker_ip ${container4_id}) +container4_name=$(docker_name ${container4_id}) + +query_ok $container1_name.$NETWORK1 $container1_ip +query_fail $container1_name.$NETWORK1.docker $container1_ip + +query_ok $container2_name.$NETWORK1 $container2_ip +query_ok name2.$NETWORK1 $container2_ip +query_fail $container2_name.$NETWORK1.docker $container2_ip + +query_ok $container3_name.$NETWORK2.docker $container3_ip +query_fail $container3_name.$NETWORK2 $container3_ip + +query_ok $container4_name.$NETWORK2.docker $container4_ip +query_ok name4.$NETWORK2.docker $container4_ip +query_fail $container4_name.$NETWORK2 $container4_ip diff --git a/test/integration/test_proxy.sh b/test/integration/test_proxy.sh new file mode 100755 index 0000000..be3baf4 --- /dev/null +++ b/test/integration/test_proxy.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +. ./functions.sh + +start_systemd_resolved_docker + +NETWORK=testnet1-$TEST_PREFIX +docker network create --label $TEST_LABEL $NETWORK > /dev/null + +container_id=$(docker_run resolvetest1 --hostname resolvetest1) +container_ip=$(docker_ip ${container_id}) + +dns_ip=$(docker network inspect bridge --format '{{ range .IPAM.Config }}{{ .Gateway }}{{ end }}') + +query_ok resolvetest1.docker $container_ip + +# Case 1: generated domains are resolved in containers on the default network +# The DNS server is provided explicitly, since it was not provided to the daemon +docker run --dns $dns_ip --rm alpine sh -c "apk add bind-tools && host resolvetest1.docker" + +# Case 2: generated domains are resolved in containers on other networks +docker run --network $NETWORK --rm alpine sh -c "apk add bind-tools && host resolvetest1.docker" diff --git a/test/integration/test_wildcard.sh b/test/integration/test_wildcard.sh new file mode 100755 index 0000000..562832e --- /dev/null +++ b/test/integration/test_wildcard.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +. ./functions.sh + +ALLOWED_DOMAINS=.docker,.$TEST_PREFIX start_systemd_resolved_docker + +container_id=$(docker_run wildcard1 --hostname "*.$TEST_PREFIX") +container_ip=$(docker_ip ${container_id}) + +query_ok anything.$TEST_PREFIX $container_ip +query_ok otherthing.$TEST_PREFIX $container_ip diff --git a/test/test_integration.py b/test/test_integration.py new file mode 100644 index 0000000..bd73e6c --- /dev/null +++ b/test/test_integration.py @@ -0,0 +1,36 @@ +import os +import pathlib +import subprocess +import unittest + +INTEGRATION_DIRECTORY = pathlib.Path(__file__).parent.resolve().joinpath("integration").as_posix() + + +def generate_test(name): + def test(self): + try: + subprocess.check_output( + ['bash', '-c', 'cd {} && ./{}'.format(INTEGRATION_DIRECTORY, name)], stderr=subprocess.STDOUT, + text=True) + except subprocess.CalledProcessError as ex: + self.fail(ex.output) + + return test + + +def extend_testcase(cls): + for file in os.listdir(INTEGRATION_DIRECTORY): + if file.startswith("test") and file.endswith(".sh"): + name = file.removesuffix(".sh") + test = generate_test(file) + setattr(cls, name, test) + + +class IntegrationTest(unittest.TestCase): + pass + + +extend_testcase(IntegrationTest) + +if __name__ == '__main__': + unittest.main() -- GitLab