From 7b1dcc8b9926a7deb9206884341a1ae89287af64 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 1 Aug 2018 17:05:43 +0200 Subject: [PATCH 1/4] move tljh_dir fixture to conftest so it can be used everywhere --- tests/conftest.py | 24 ++++++++++++++++++++++++ tests/test_config.py | 16 ---------------- 2 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 tests/conftest.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..b48fd4a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,24 @@ +"""pytest fixtures""" +from importlib import reload +import os +import types +from unittest import mock + +import pytest + +import tljh + + +@pytest.fixture +def tljh_dir(tmpdir): + """Fixture for setting up a temporary tljh dir""" + tljh_dir = str(tmpdir.join("tljh").mkdir()) + with mock.patch.dict(os.environ, {"TLJH_INSTALL_PREFIX": tljh_dir}): + reload(tljh) + for name in dir(tljh): + mod = getattr(tljh, name) + if isinstance(mod, types.ModuleType) and mod.__name__.startswith('tljh.'): + reload(mod) + assert tljh.config.INSTALL_PREFIX == tljh_dir + os.makedirs(tljh.config.STATE_DIR) + yield tljh_dir diff --git a/tests/test_config.py b/tests/test_config.py index aed0f49..f84582a 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2,7 +2,6 @@ Test configuration commandline tools """ -from importlib import reload import os import tempfile from unittest import mock @@ -12,21 +11,6 @@ import pytest from tljh import config, configurer -@pytest.fixture -def tljh_dir(tmpdir): - """Fixture for setting up a temporary tljh dir""" - tljh_dir = str(tmpdir.join("tljh").mkdir()) - with mock.patch.dict( - os.environ, - {"TLJH_INSTALL_PREFIX": tljh_dir} - ): - reload(config) - reload(configurer) - assert config.INSTALL_PREFIX == tljh_dir - os.makedirs(config.STATE_DIR) - yield tljh_dir - - def test_set_no_mutate(): conf = {} From 51299e619b78f62821c40a9b62730b49cb352fa3 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 1 Aug 2018 17:06:52 +0200 Subject: [PATCH 2/4] unittests for traefik --- dev-requirements.txt | 1 + tests/test_traefik.py | 92 +++++++++++++++++++++++++++++++++++++++++++ tljh/traefik.py | 2 +- 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tests/test_traefik.py diff --git a/dev-requirements.txt b/dev-requirements.txt index 9cf8484..fd93238 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,3 +1,4 @@ pytest pytest-cov codecov +pytoml diff --git a/tests/test_traefik.py b/tests/test_traefik.py new file mode 100644 index 0000000..1d880b5 --- /dev/null +++ b/tests/test_traefik.py @@ -0,0 +1,92 @@ +"""Test traefik configuration""" +import os + +import pytoml as toml + +from tljh import config +from tljh import traefik + + +def test_download_traefik(tmpdir): + traefik_bin = tmpdir.mkdir("bin").join("traefik") + traefik.ensure_traefik_binary(str(tmpdir)) + assert traefik_bin.exists() + assert traefik_bin.stat().mode == 0o755 + + +def test_default_config(tmpdir, tljh_dir): + state_dir = tmpdir.mkdir("state") + traefik.ensure_traefik_config(str(state_dir)) + assert state_dir.join("traefik.toml").exists() + traefik_toml = os.path.join(state_dir, "traefik.toml") + with open(traefik_toml) as f: + toml_cfg = f.read() + # print config for debugging on failure + print(config.CONFIG_FILE) + print(toml_cfg) + cfg = toml.loads(toml_cfg) + assert cfg["defaultEntryPoints"] == ["http"] + assert cfg["entryPoints"] == {"http": {"address": ":80"}} + assert cfg["frontends"] == { + "jupyterhub": {"backend": "jupyterhub", "passHostHeader": True} + } + assert cfg["backends"] == { + "jupyterhub": {"servers": {"chp": {"url": "http://127.0.0.1:15003"}}} + } + + +def test_letsencrypt_config(tljh_dir): + state_dir = config.STATE_DIR + config.set_config_value(config.CONFIG_FILE, "https.enabled", True) + config.set_config_value( + config.CONFIG_FILE, "https.letsencrypt.email", "fake@jupyter.org" + ) + config.set_config_value( + config.CONFIG_FILE, "https.letsencrypt.domains", ["testing.jovyan.org"] + ) + traefik.ensure_traefik_config(str(state_dir)) + traefik_toml = os.path.join(state_dir, "traefik.toml") + with open(traefik_toml) as f: + toml_cfg = f.read() + # print config for debugging on failure + print(config.CONFIG_FILE) + print(toml_cfg) + cfg = toml.loads(toml_cfg) + assert cfg["defaultEntryPoints"] == ["http", "https"] + assert "acme" in cfg + assert cfg["entryPoints"] == { + "http": {"address": ":80", "redirect": {"entryPoint": "https"}}, + "https": {"address": ":443", "backend": "jupyterhub", "tls": {}}, + } + assert cfg["acme"] == { + "email": "fake@jupyter.org", + "storage": "acme.json", + "entryPoint": "https", + "httpChallenge": {"entryPoint": "http"}, + "domains": [{"main": "testing.jovyan.org"}], + } + + +def test_manual_ssl_config(tljh_dir): + state_dir = config.STATE_DIR + config.set_config_value(config.CONFIG_FILE, "https.enabled", True) + config.set_config_value(config.CONFIG_FILE, "https.tls.key", "/path/to/ssl.key") + config.set_config_value(config.CONFIG_FILE, "https.tls.cert", "/path/to/ssl.cert") + traefik.ensure_traefik_config(str(state_dir)) + traefik_toml = os.path.join(state_dir, "traefik.toml") + with open(traefik_toml) as f: + toml_cfg = f.read() + # print config for debugging on failure + print(config.CONFIG_FILE) + print(toml_cfg) + cfg = toml.loads(toml_cfg) + assert cfg["defaultEntryPoints"] == ["http", "https"] + assert "acme" not in cfg + assert cfg["entryPoints"] == { + "http": {"address": ":80", "redirect": {"entryPoint": "https"}}, + "https": { + "address": ":443", + "backend": "jupyterhub", + "tls": {"key": "/path/to/ssl.key", "cert": "/path/to/ssl.cert"}, + }, + } diff --git a/tljh/traefik.py b/tljh/traefik.py index cf10ecc..6fee96f 100644 --- a/tljh/traefik.py +++ b/tljh/traefik.py @@ -3,7 +3,7 @@ import hashlib import os from urllib.request import urlretrieve -from jinja2 import Environment, Template +from jinja2 import Template from tljh.configurer import load_config From f0a0d2f20d0cf089208efbfafb196f4130afd54b Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 3 Aug 2018 16:11:49 +0200 Subject: [PATCH 3/4] limit traefik permission check to ugo ignores possible sticky bits, etc. --- tests/test_traefik.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_traefik.py b/tests/test_traefik.py index 1d880b5..9d8294b 100644 --- a/tests/test_traefik.py +++ b/tests/test_traefik.py @@ -11,7 +11,8 @@ def test_download_traefik(tmpdir): traefik_bin = tmpdir.mkdir("bin").join("traefik") traefik.ensure_traefik_binary(str(tmpdir)) assert traefik_bin.exists() - assert traefik_bin.stat().mode == 0o755 + # ignore higher-order permission bits, only verify ugo permissions + assert (traefik_bin.stat().mode & 0o777) == 0o755 def test_default_config(tmpdir, tljh_dir): From 4522917c23304b8e43dfdff568b2877ae28acb6a Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 3 Aug 2018 16:17:22 +0200 Subject: [PATCH 4/4] fix manual ssl config test --- tests/test_traefik.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_traefik.py b/tests/test_traefik.py index 9d8294b..0d811ec 100644 --- a/tests/test_traefik.py +++ b/tests/test_traefik.py @@ -88,6 +88,10 @@ def test_manual_ssl_config(tljh_dir): "https": { "address": ":443", "backend": "jupyterhub", - "tls": {"key": "/path/to/ssl.key", "cert": "/path/to/ssl.cert"}, + "tls": { + "certificates": [ + {"certFile": "/path/to/ssl.cert", "keyFile": "/path/to/ssl.key"} + ] + }, }, }