Merge remote-tracking branch 'upstream/main' into conda-channels

This commit is contained in:
YuviPanda
2023-09-29 14:27:25 -07:00
180 changed files with 7796 additions and 6028 deletions

View File

@@ -1,7 +1,7 @@
"""pytest fixtures"""
from importlib import reload
import os
import types
from importlib import reload
from unittest import mock
import pytest

View File

@@ -0,0 +1,129 @@
# Unit test some functions from bootstrap.py
import os
import sys
import pytest
# Since bootstrap.py isn't part of the package, it's not automatically importable
GIT_REPO_PATH = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
sys.path.insert(0, GIT_REPO_PATH)
from bootstrap import bootstrap
@pytest.mark.parametrize(
"requested,expected",
[
((1,), (1, 1, 0)),
((1, 0), (1, 0, 1)),
((1, 2), None),
((2, 0, 0), (2, 0, 0)),
("latest", (2, 0, 1)),
],
)
def test_find_matching_version(requested, expected):
all_versions = [
(0, 0, 1),
(1, 0, 0),
(1, 0, 1),
(1, 1, 0),
(2, 0, 0),
(2, 0, 1),
]
r = bootstrap._find_matching_version(all_versions, requested)
assert r == expected
# git ls-remote --tags --refs https://github.com/jupyterhub/jupyterhub.git
mock_git_ls_remote = """\
c345aa658eb482b8102b51f6ec3f0fc667b60520 refs/tags/0.1.0
e2cbc2fb41c04cfe416b19e83f36ea67b1a4e693 refs/tags/0.2.0
7fd56fe943bf0038cb14e7aa2af5a3e5ad929d47 refs/tags/0.3.0
89cf4c60a905b4093ba7584c4561073a9faa0d3d refs/tags/0.4.0
bd08efc4a5485a9ecd17882e9bfcab9486d9956a refs/tags/0.4.1
19c77d0c7016c08a4a0e883446114a430a551882 refs/tags/0.5.0
b4621d354b6bbc865373b7c033f29c6872237780 refs/tags/0.6.0
ed38f08daf4d5cf84f04b2d96327681221c579dd refs/tags/0.6.1
d5cf9657f2ca16df080e2be21da792288e9f4f99 refs/tags/0.7.0
2cdb4be46a0eb291850fc706cfe044873889a9bc refs/tags/0.7.1
e4dd65d2611e3c85fe486c561fc0efe9ca720042 refs/tags/0.7.2
4179668e49ceedb805cb1a38dc5a70e6a21fa685 refs/tags/0.8.0
9bab206eb96c6726ac936cf5da3f61eb9c9aa519 refs/tags/0.8.0b1
5f2c6d25fefcbe91d86945f530e6533822449c46 refs/tags/0.8.0b2
0d720103c5207d008947580b7b453e1eb0e7594a refs/tags/0.8.0b3
a2458ffa402fa2d2905c558100c673e98789a8a8 refs/tags/0.8.0b4
b9e2838a4d9b35a9ad7c3353e62ab006b4ec10a4 refs/tags/0.8.0b5
a62fc1bc1c9b2408713511cb56e7751403ed5503 refs/tags/0.8.0rc1
a77ca08e3e25c14552e246e8ad3ca65a354ba192 refs/tags/0.8.0rc2
6eef64842a7d7939b3f1986558849d1977a0e121 refs/tags/0.8.1
de46a16029b7ae217293e7e64e14a9c2e06e5e60 refs/tags/0.9.0
9f612b52187db878f529458e304bd519fda82e42 refs/tags/0.9.0b1
ec4b038b93495eb769007a0d3d56e6d6a5ff000c refs/tags/0.9.0b2
ea8a30b1a5b189b2f2f0dbfdb22f83427d1c9163 refs/tags/0.9.0b3
99c155a61a1d95a3a8ca41ebb684cdedc1fb170f refs/tags/0.9.0rc1
1aeebd4e4937ea5185ce02f693f94272c30f4ebd refs/tags/0.9.1
01b3601a12b52259b541b48eaa7a7afb3f7d988c refs/tags/0.9.2
70ddc22e071bb7797528831d25c567f6f4920c67 refs/tags/0.9.3
7ecb093163a453ae2edfa6bc8bf1f7cfc2320627 refs/tags/0.9.4
3e83bc440b8d5abdc0a4336978bd542435402f77 refs/tags/0.9.5
cc07c706931c78f46367db9c0c20e6ed9f0f6f85 refs/tags/0.9.6
4e24276d40ad83fd113c7c2f1f8619a9ba3af0d8 refs/tags/1.0.0
582162c760e81995f4f5405e9c8908d2a76f4abf refs/tags/1.0.0b1
1193f6a74c38b36594f6f57c786fa923a2747150 refs/tags/1.0.0b2
512dae6cd8a846dd490d77d21fd4e13f59c38961 refs/tags/1.1.0
a420c55391273852332ef5f454a0a3b9e0e5b71f refs/tags/1.1.0b1
317f0efaf25eb7cb2de4503817cf20937ce110bd refs/tags/1.2.0
f66e5d35b5f89a28f6328c91801a8f99e0855a8e refs/tags/1.2.0b1
27e1196471729cf6f25fd3786286797e32de973a refs/tags/1.2.1
af0c1ed932d00fa26ac91f066a5a9eafb49b7cb1 refs/tags/1.2.2
3794abfbdda0a92237f4c31985420691da70da36 refs/tags/1.3.0
e22ab5dc93dd8e724b828a0880032f6b5dc00231 refs/tags/1.4.0
0656586b75b30091583c0573b3d272cb3add24d2 refs/tags/1.4.1
5744ce73bcf0014cc3de6c946f12027448b136da refs/tags/1.4.2
c6fb64d8f30686c2c2667b69b53402d506a3bac5 refs/tags/1.5.0
4ceb906435dbd4cf800b0480d413303f056e4900 refs/tags/2.0.0
61233698dfb353c703ea2e085312b9066ea2e92e refs/tags/2.0.0b1
fe61c932409550dc352abf68bd6aaaa8871ac81f refs/tags/2.0.0b2
a79c5c5a6bfe553af277f2835419d65b98ae0cb9 refs/tags/2.0.0b3
fa1098a998561321de29c6147235032fd6b0c3f5 refs/tags/2.0.0rc1
75b115c356983c138c2d8d92cb45f068ad3d9c9d refs/tags/2.0.0rc2
ed8e25ef3f471d60b671f2a1cf2db17581c778a2 refs/tags/2.0.0rc3
4083307b3f37039075862034963ed42a459b1bdb refs/tags/2.0.0rc4
baf1f36dbfe8d8264b3914650b4db6daed843389 refs/tags/2.0.0rc5
12961be3b13a10617d8f95f333da2bb67390a2c7 refs/tags/2.0.1
e40df3f1a5e284926f5c9ce66a1e57a814bb98f8 refs/tags/2.0.2
11d40c13860bd02816ad724979ad2e08b8bd103a refs/tags/2.1.0
bde6b66287e3d157f2577bcaf2e986af020139f4 refs/tags/2.1.1
29f51794db562ecc4c7653525193d6e210151fdb refs/tags/2.2.0
8cbafd25425b7eaf2fdc46e183cee437c09b53c1 refs/tags/2.2.1
1eada986101f2385ee7498395a799f28bcd167e8 refs/tags/2.2.2
1bb0ec38ae4c5e4e5c8b6cc3b89b7b20ea8bd400 refs/tags/2.3.0
69f926706be03505f9b9e30a5ad2d4f8c9f9d48d refs/tags/2.3.1
"""
@pytest.mark.parametrize(
"requested,expected",
[
("1", "1.5.0"),
("1.0", "1.0.0"),
("1.2", "1.2.2"),
("1.100", None),
("2.0.0", "2.0.0"),
("random-branch", "random-branch"),
("1234567890abcdef", "1234567890abcdef"),
("2.0.0rc4", "2.0.0rc4"),
("latest", "2.3.1"),
],
)
def test_resolve_git_version(monkeypatch, requested, expected):
def mock_run_subprocess(*args, **kwargs):
return mock_git_ls_remote
monkeypatch.setattr(bootstrap, "run_subprocess", mock_run_subprocess)
if expected is None:
with pytest.raises(Exception) as exc:
bootstrap._resolve_git_version(requested)
assert exc.value.args[0].startswith("No version matching 1.100 found")
else:
assert bootstrap._resolve_git_version(requested) == expected

View File

@@ -1,37 +1,26 @@
"""
Test conda commandline wrappers
"""
from tljh import conda
import os
import pytest
import subprocess
import tempfile
import pytest
from tljh import conda, installer
@pytest.fixture(scope="module")
def prefix():
"""
Provide a temporary directory with a mambaforge conda environment
"""
# see https://github.com/conda-forge/miniforge/releases
mambaforge_version = "4.10.3-7"
if os.uname().machine == "aarch64":
installer_sha256 = (
"ac95f137b287b3408e4f67f07a284357b1119ee157373b788b34e770ef2392b2"
)
elif os.uname().machine == "x86_64":
installer_sha256 = (
"fc872522ec427fcab10167a93e802efaf251024b58cc27b084b915a9a73c4474"
)
installer_url = "https://github.com/conda-forge/miniforge/releases/download/{v}/Mambaforge-{v}-Linux-{arch}.sh".format(
v=mambaforge_version, arch=os.uname().machine
)
installer_url, checksum = installer._mambaforge_url()
with tempfile.TemporaryDirectory() as tmpdir:
with conda.download_miniconda_installer(
installer_url, installer_sha256
installer_url, checksum
) as installer_path:
conda.install_miniconda(installer_path, tmpdir)
conda.ensure_conda_packages(tmpdir, ["conda==4.10.3"])
yield tmpdir

View File

@@ -56,7 +56,7 @@ def test_set_overwrite():
def test_unset_no_mutate():
conf = {"a": "b"}
new_conf = config.unset_item_from_config(conf, "a")
config.unset_item_from_config(conf, "a")
assert conf == {"a": "b"}

View File

@@ -2,10 +2,11 @@
Test configurer
"""
from traitlets.config import Config
import os
import sys
from traitlets.config import Config
from tljh import configurer
@@ -57,24 +58,15 @@ def test_app_default():
Test default application with no config overrides.
"""
c = apply_mock_config({})
# default_url is not set, so JupyterHub will pick default.
assert "default_url" not in c.Spawner
def test_app_jupyterlab():
"""
Test setting JupyterLab as default application
"""
c = apply_mock_config({"user_environment": {"default_app": "jupyterlab"}})
assert c.Spawner.default_url == "/lab"
def test_app_nteract():
def test_app_classic():
"""
Test setting nteract as default application
Test setting classic as default application
"""
c = apply_mock_config({"user_environment": {"default_app": "nteract"}})
assert c.Spawner.default_url == "/nteract"
c = apply_mock_config({"user_environment": {"default_app": "classic"}})
assert c.Spawner.default_url == "/tree"
def test_auth_default():
@@ -163,8 +155,8 @@ def test_traefik_api_default():
"""
c = apply_mock_config({})
assert c.TraefikTomlProxy.traefik_api_username == "api_admin"
assert len(c.TraefikTomlProxy.traefik_api_password) == 0
assert c.TraefikProxy.traefik_api_username == "api_admin"
assert len(c.TraefikProxy.traefik_api_password) == 0
def test_set_traefik_api():
@@ -174,8 +166,8 @@ def test_set_traefik_api():
c = apply_mock_config(
{"traefik_api": {"username": "some_user", "password": "1234"}}
)
assert c.TraefikTomlProxy.traefik_api_username == "some_user"
assert c.TraefikTomlProxy.traefik_api_password == "1234"
assert c.TraefikProxy.traefik_api_username == "some_user"
assert c.TraefikProxy.traefik_api_password == "1234"
def test_cull_service_default():
@@ -228,6 +220,43 @@ def test_set_cull_service():
]
def test_cull_service_named():
"""
Test default cull service settings with named server removal
"""
c = apply_mock_config(
{
"services": {
"cull": {
"every": 10,
"cull_users": True,
"remove_named_servers": True,
"max_age": 60,
}
}
}
)
cull_cmd = [
sys.executable,
"-m",
"jupyterhub_idle_culler",
"--timeout=600",
"--cull-every=10",
"--concurrency=5",
"--max-age=60",
"--cull-users",
"--remove-named-servers",
]
assert c.JupyterHub.services == [
{
"name": "cull-idle",
"admin": True,
"command": cull_cmd,
}
]
def test_load_secrets(tljh_dir):
"""
Test loading secret files
@@ -238,7 +267,7 @@ def test_load_secrets(tljh_dir):
tljh_config = configurer.load_config()
assert tljh_config["traefik_api"]["password"] == "traefik-password"
c = apply_mock_config(tljh_config)
assert c.TraefikTomlProxy.traefik_api_password == "traefik-password"
assert c.TraefikProxy.traefik_api_password == "traefik-password"
def test_auth_native():

View File

@@ -1,10 +1,16 @@
"""
Unit test functions in installer.py
"""
import json
import os
import pytest
from subprocess import PIPE, run
from unittest import mock
from tljh import installer
import pytest
from packaging.specifiers import SpecifierSet
from packaging.version import parse as V
from tljh import conda, installer
from tljh.yaml import yaml
@@ -36,3 +42,202 @@ def test_ensure_admins(tljh_dir, admins, expected_config):
# verify the list was flattened
assert config["users"]["admin"] == expected_config
def setup_conda(distro, version, prefix):
"""Install mambaforge or miniconda in a prefix"""
if distro == "mambaforge":
installer_url, _ = installer._mambaforge_url(version)
elif distro == "miniforge":
installer_url, _ = installer._mambaforge_url(version)
installer_url = installer_url.replace("Mambaforge", "Miniforge3")
elif distro == "miniconda":
arch = os.uname().machine
installer_url = (
f"https://repo.anaconda.com/miniconda/Miniconda3-{version}-Linux-{arch}.sh"
)
else:
raise ValueError(
f"{distro=} must be 'miniconda' or 'mambaforge' or 'miniforge'"
)
with conda.download_miniconda_installer(installer_url, None) as installer_path:
conda.install_miniconda(installer_path, str(prefix))
# avoid auto-updating conda when we install other packages
run(
[
str(prefix / "bin/conda"),
"config",
"--system",
"--set",
"auto_update_conda",
"false",
],
input="",
check=True,
)
@pytest.fixture
def user_env_prefix(tmp_path):
user_env_prefix = tmp_path / "user_env"
with mock.patch.object(installer, "USER_ENV_PREFIX", str(user_env_prefix)):
yield user_env_prefix
def _specifier(version):
"""Convert version string to SpecifierSet
If just a version number, add == to make it a specifier
Any missing fields are replaced with .*
If it's already a specifier string, pass it directly to SpecifierSet
e.g.
- 3.7 -> ==3.7.*
- 1.2.3 -> ==1.2.3
"""
if version[0].isdigit():
# it's a version number, not a specifier
if version.count(".") < 2:
# pad missing fields
version += ".*"
version = f"=={version}"
return SpecifierSet(version)
@pytest.mark.parametrize(
# - distro: None, mambaforge, or miniforge
# - distro_version: https://github.com/conda-forge/miniforge/releases
# - expected_versions: versions of python, conda, and mamba in user env
#
# TLJH of a specific version comes with a specific distro_version as
# declared in installer.py's MAMBAFORGE_VERSION variable, and it comes with
# python, conda, and mamba of certain versions.
#
"distro, distro_version, expected_versions",
[
# No previous install, start fresh
(
None,
None,
{
"python": "3.10.*",
"conda": "23.1.0",
"mamba": "1.4.1",
},
),
# previous install, 1.0
(
"mambaforge",
"23.1.0-1",
{
"python": "3.10.*",
"conda": "23.1.0",
"mamba": "1.4.1",
},
),
# 0.2 install, no upgrade needed
(
"mambaforge",
"4.10.3-7",
{
"python": "3.9.*",
"conda": "4.10.3",
"mamba": "0.16.0",
},
),
# simulate missing mamba
# will be installed but not pinned
# to avoid conflicts
(
"miniforge",
"4.10.3-7",
{
"python": "3.9.*",
"conda": "4.10.3",
"mamba": ">=1.1.0",
},
),
# too-old Python (3.7), abort
(
"miniconda",
"4.7.10",
ValueError,
),
],
)
def test_ensure_user_environment(
user_env_prefix,
distro,
distro_version,
expected_versions,
):
if (
distro_version
and V(distro_version) < V("4.10.1")
and os.uname().machine == "aarch64"
):
pytest.skip(f"{distro} {distro_version} not available for aarch64")
canary_file = user_env_prefix / "test-file.txt"
canary_package = "types-backports_abc"
if distro:
setup_conda(distro, distro_version, user_env_prefix)
# install a noarch: python package that won't be used otherwise
# should depend on Python, so it will interact with possible upgrades
pkgs = [canary_package]
run(
[
str(user_env_prefix / "bin/conda"),
"install",
"-S",
"-y",
"-c",
"conda-forge",
]
+ pkgs,
input="",
check=True,
)
# make a file not managed by conda, to check for wipeouts
with canary_file.open("w") as f:
f.write("I'm here\n")
if isinstance(expected_versions, type) and issubclass(expected_versions, Exception):
exc_class = expected_versions
with pytest.raises(exc_class):
installer.ensure_user_environment("")
return
else:
installer.ensure_user_environment("")
p = run(
[str(user_env_prefix / "bin/conda"), "list", "--json"],
stdout=PIPE,
text=True,
check=True,
)
package_list = json.loads(p.stdout)
packages = {package["name"]: package for package in package_list}
if distro:
# make sure we didn't wipe out files
assert canary_file.exists()
# make sure we didn't delete the installed package
assert canary_package in packages
for pkg, version in expected_versions.items():
assert pkg in packages
assert V(packages[pkg]["version"]) in _specifier(version)
def test_ensure_user_environment_no_clobber(user_env_prefix):
# don't clobber existing user-env dir if it's non-empty and not a conda install
user_env_prefix.mkdir()
canary_file = user_env_prefix / "test-file.txt"
with canary_file.open("w") as f:
pass
with pytest.raises(OSError):
installer.ensure_user_environment("")

View File

@@ -4,7 +4,7 @@ Unit test functions in installer.py
import os
from datetime import date
from tljh import migrator, config
from tljh import config, migrator
def test_migrate_config(tljh_dir):

View File

@@ -1,11 +1,10 @@
"""Test traefik configuration"""
import os
import toml
import pytest
import toml
from tljh import config
from tljh import traefik
from tljh import config, traefik
def test_download_traefik(tmpdir):
@@ -16,30 +15,51 @@ def test_download_traefik(tmpdir):
assert (traefik_bin.stat().mode & 0o777) == 0o755
def _read_toml(path):
"""Read a toml file
print config for debugging on failure
"""
print(path)
with open(path) as f:
toml_cfg = f.read()
print(toml_cfg)
return toml.loads(toml_cfg)
def _read_static_config(state_dir):
return _read_toml(os.path.join(state_dir, "traefik.toml"))
def _read_dynamic_config(state_dir):
return _read_toml(os.path.join(state_dir, "rules", "dynamic.toml"))
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 len(cfg["entryPoints"]["auth_api"]["auth"]["basic"]["users"]) == 1
# runtime generated entry, value not testable
cfg["entryPoints"]["auth_api"]["auth"]["basic"]["users"] = [""]
os.path.join(state_dir, "traefik.toml")
rules_dir = os.path.join(state_dir, "rules")
cfg = _read_static_config(state_dir)
assert cfg["api"] == {}
assert cfg["entryPoints"] == {
"http": {"address": ":80"},
"http": {
"address": ":80",
"transport": {"respondingTimeouts": {"idleTimeout": "10m"}},
},
"auth_api": {
"address": "127.0.0.1:8099",
"auth": {"basic": {"users": [""]}},
"whiteList": {"sourceRange": ["127.0.0.1"]},
"address": "localhost:8099",
},
}
assert cfg["providers"] == {
"providersThrottleDuration": "0s",
"file": {"directory": rules_dir, "watch": True},
}
dynamic_config = _read_dynamic_config(state_dir)
assert dynamic_config == {}
def test_letsencrypt_config(tljh_dir):
@@ -52,34 +72,67 @@ def test_letsencrypt_config(tljh_dir):
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 len(cfg["entryPoints"]["auth_api"]["auth"]["basic"]["users"]) == 1
# runtime generated entry, value not testable
cfg["entryPoints"]["auth_api"]["auth"]["basic"]["users"] = [""]
cfg = _read_static_config(state_dir)
assert cfg["entryPoints"] == {
"http": {"address": ":80", "redirect": {"entryPoint": "https"}},
"https": {"address": ":443", "tls": {"minVersion": "VersionTLS12"}},
"http": {
"address": ":80",
"http": {
"redirections": {
"entryPoint": {
"scheme": "https",
"to": "https",
},
},
},
"transport": {"respondingTimeouts": {"idleTimeout": "10m"}},
},
"https": {
"address": ":443",
"http": {"tls": {"options": "default"}},
"transport": {"respondingTimeouts": {"idleTimeout": "10m"}},
},
"auth_api": {
"address": "127.0.0.1:8099",
"auth": {"basic": {"users": [""]}},
"whiteList": {"sourceRange": ["127.0.0.1"]},
"address": "localhost:8099",
},
}
assert cfg["acme"] == {
assert "tls" not in cfg
dynamic_config = _read_dynamic_config(state_dir)
assert dynamic_config["tls"] == {
"options": {
"default": {
"minVersion": "VersionTLS12",
"cipherSuites": [
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
],
}
},
"stores": {
"default": {
"defaultGeneratedCert": {
"resolver": "letsencrypt",
"domain": {
"main": "testing.jovyan.org",
"sans": [],
},
}
}
},
}
assert "certificatesResolvers" in cfg
assert "letsencrypt" in cfg["certificatesResolvers"]
assert cfg["certificatesResolvers"]["letsencrypt"]["acme"] == {
"email": "fake@jupyter.org",
"storage": "acme.json",
"entryPoint": "https",
"httpChallenge": {"entryPoint": "http"},
"domains": [{"main": "testing.jovyan.org"}],
"tlsChallenge": {},
}
@@ -89,33 +142,62 @@ def test_manual_ssl_config(tljh_dir):
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 len(cfg["entryPoints"]["auth_api"]["auth"]["basic"]["users"]) == 1
# runtime generated entry, value not testable
cfg["entryPoints"]["auth_api"]["auth"]["basic"]["users"] = [""]
cfg = _read_static_config(state_dir)
assert cfg["entryPoints"] == {
"http": {"address": ":80", "redirect": {"entryPoint": "https"}},
"http": {
"address": ":80",
"http": {
"redirections": {
"entryPoint": {
"scheme": "https",
"to": "https",
},
},
},
"transport": {
"respondingTimeouts": {
"idleTimeout": "10m",
}
},
},
"https": {
"address": ":443",
"tls": {
"http": {"tls": {"options": "default"}},
"transport": {"respondingTimeouts": {"idleTimeout": "10m"}},
},
"auth_api": {
"address": "localhost:8099",
},
}
assert "tls" not in cfg
dynamic_config = _read_dynamic_config(state_dir)
assert "tls" in dynamic_config
assert dynamic_config["tls"] == {
"options": {
"default": {
"minVersion": "VersionTLS12",
"certificates": [
{"certFile": "/path/to/ssl.cert", "keyFile": "/path/to/ssl.key"}
"cipherSuites": [
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
],
},
},
"auth_api": {
"address": "127.0.0.1:8099",
"auth": {"basic": {"users": [""]}},
"whiteList": {"sourceRange": ["127.0.0.1"]},
"stores": {
"default": {
"defaultCertificate": {
"certFile": "/path/to/ssl.cert",
"keyFile": "/path/to/ssl.key",
}
}
},
}
@@ -132,18 +214,18 @@ def test_extra_config(tmpdir, tljh_dir):
toml_cfg = toml.load(traefik_toml)
# Make sure the defaults are what we expect
assert toml_cfg["logLevel"] == "INFO"
assert toml_cfg["log"]["level"] == "INFO"
with pytest.raises(KeyError):
toml_cfg["checkNewVersion"]
assert toml_cfg["entryPoints"]["auth_api"]["address"] == "127.0.0.1:8099"
toml_cfg["api"]["dashboard"]
assert toml_cfg["entryPoints"]["auth_api"]["address"] == "localhost:8099"
extra_config = {
# modify existing value
"logLevel": "ERROR",
# modify existing value with multiple levels
"entryPoints": {"auth_api": {"address": "127.0.0.1:9999"}},
"log": {
"level": "ERROR",
},
# add new setting
"checkNewVersion": False,
"api": {"dashboard": True},
}
with open(os.path.join(extra_config_dir, "extra.toml"), "w+") as extra_config_file:
@@ -156,6 +238,21 @@ def test_extra_config(tmpdir, tljh_dir):
toml_cfg = toml.load(traefik_toml)
# Check that the defaults were updated by the extra config
assert toml_cfg["logLevel"] == "ERROR"
assert toml_cfg["checkNewVersion"] == False
assert toml_cfg["entryPoints"]["auth_api"]["address"] == "127.0.0.1:9999"
assert toml_cfg["log"]["level"] == "ERROR"
assert toml_cfg["api"]["dashboard"] == True
def test_listen_address(tmpdir, 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")
config.set_config_value(config.CONFIG_FILE, "http.address", "127.0.0.1")
config.set_config_value(config.CONFIG_FILE, "https.address", "127.0.0.1")
traefik.ensure_traefik_config(str(state_dir))
cfg = _read_static_config(state_dir)
assert cfg["entryPoints"]["http"]["address"] == "127.0.0.1:80"
assert cfg["entryPoints"]["https"]["address"] == "127.0.0.1:443"

View File

@@ -1,15 +1,17 @@
"""
Test wrappers in tljw.user module
"""
from tljh import user
import grp
import os
import os.path
import pwd
import stat
import uuid
import pwd
import grp
import pytest
from tljh import user
def test_ensure_user():
"""

View File

@@ -1,7 +1,9 @@
import pytest
from tljh import utils
import subprocess
import logging
import subprocess
import pytest
from tljh import utils
def test_run_subprocess_exception(mocker):