From e5d6f969bee6039abe8aaae7873e7eb4c99f9d68 Mon Sep 17 00:00:00 2001 From: cthuang Date: Fri, 5 Mar 2021 22:50:11 +0000 Subject: [PATCH] TUN-4055: Skeleton for component tests --- component-tests/.gitignore | 2 ++ component-tests/README.md | 22 +++++++++++++ component-tests/requirements.txt | 2 ++ component-tests/test_config.py | 53 ++++++++++++++++++++++++++++++++ component-tests/util.py | 27 ++++++++++++++++ 5 files changed, 106 insertions(+) create mode 100644 component-tests/.gitignore create mode 100644 component-tests/README.md create mode 100644 component-tests/requirements.txt create mode 100644 component-tests/test_config.py create mode 100644 component-tests/util.py diff --git a/component-tests/.gitignore b/component-tests/.gitignore new file mode 100644 index 00000000..375de919 --- /dev/null +++ b/component-tests/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +.pytest_cache diff --git a/component-tests/README.md b/component-tests/README.md new file mode 100644 index 00000000..81a4980d --- /dev/null +++ b/component-tests/README.md @@ -0,0 +1,22 @@ +# Requirements +1. Python 3.7 or later with packages in the given `requirements.txt` + - E.g. with conda: + - `conda create -n component-tests python=3.7` + - `conda activate component-tests` + - `pip3 install -r requirements.txt` + +# How to run +## All tests +Run `pytest` inside this(component-tests) folder + +## Specific files +Run `pytest .py .py` + +## Specific tests +Run `pytest file.py -k -k ` + +## Live Logging +Running with `-o log_cli=true` outputs logging to CLI as the tests are. By default the log level is WARN. +`--log-cli-level` control logging level. +For example, to log at info level, run `pytest -o log_cli=true --log-cli-level=INFO`. +See https://docs.pytest.org/en/latest/logging.html#live-logs for more documentation on logging. \ No newline at end of file diff --git a/component-tests/requirements.txt b/component-tests/requirements.txt new file mode 100644 index 00000000..cfd18756 --- /dev/null +++ b/component-tests/requirements.txt @@ -0,0 +1,2 @@ +pytest==6.2.2 +pyyaml==5.4.1 \ No newline at end of file diff --git a/component-tests/test_config.py b/component-tests/test_config.py new file mode 100644 index 00000000..5aa94e9d --- /dev/null +++ b/component-tests/test_config.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +from util import start_cloudflared + +class TestConfig: + # tmp_path is a fixture provides a temporary directory unique to the test invocation + def test_validate_ingress_rules(self, tmp_path): + config = { + 'metrics': 'localhost:50000', + 'ingress': [ + { + "hostname": "example.com", + "service": "https://localhost:8000", + "originRequest": { + "originServerName": "test.example.com", + "caPool": "/etc/certs/ca.pem" + }, + }, + { + "hostname": "api.example.com", + "path": "login", + "service": "https://localhost:9000", + }, + { + "hostname": "wss.example.com", + "service": "wss://localhost:8000", + }, + { + "hostname": "ssh.example.com", + "service": "ssh://localhost:8000", + }, + {"service": "http_status:404"} + ], + } + validate_args = ["ingress", "validate"] + pre_args = ["tunnel"] + validate = start_cloudflared(tmp_path, config, validate_args, pre_args) + assert validate.returncode == 0, "failed to validate ingress" + validate.stderr.decode("utf-8") + + self.match_rule(tmp_path, config, "http://example.com/index.html", 1) + self.match_rule(tmp_path, config, "https://example.com/index.html", 1) + self.match_rule(tmp_path, config, "https://api.example.com/login", 2) + self.match_rule(tmp_path, config, "https://wss.example.com", 3) + self.match_rule(tmp_path, config, "https://ssh.example.com", 4) + self.match_rule(tmp_path, config, "https://api.example.com", 5) + + # This is used to check that the command tunnel ingress url matches rule number . Note that rule number uses 1-based indexing + def match_rule(self, tmp_path, config, url, rule_num): + args = ["ingress", "rule", url] + pre_args = ["tunnel"] + match_rule = start_cloudflared(tmp_path, config, args, pre_args) + + assert match_rule.returncode == 0, "failed to check rule" + match_rule.stderr.decode("utf-8") + assert f"Matched rule #{rule_num}" .encode() in match_rule.stdout \ No newline at end of file diff --git a/component-tests/util.py b/component-tests/util.py new file mode 100644 index 00000000..aed3d82b --- /dev/null +++ b/component-tests/util.py @@ -0,0 +1,27 @@ +import logging +import os +import subprocess +import yaml + +LOGGER = logging.getLogger(__name__) + +def get_cloudflared(): + cfd_binary = os.getenv('CFD_BINARY') + return "cloudflared" if cfd_binary is None else cfd_binary + + +def write_config(path, config): + config_path = path / "config.yaml" + with open(config_path, 'w') as outfile: + yaml.dump(config, outfile) + return config_path + + +def start_cloudflared(path, config, args, pre_args=[]): + config_path = write_config(path, config) + cmd = [get_cloudflared()] + cmd += pre_args + cmd += ["--config", config_path] + cmd += args + LOGGER.info(f"Run cmd {cmd} with config {config}") + return subprocess.run(cmd, capture_output=True) \ No newline at end of file