""" Test configuration commandline tools """ import os import tempfile from unittest import mock import pytest from tljh import config, configurer def test_set_no_mutate(): conf = {} new_conf = config.set_item_in_config(conf, 'a.b', 'c') assert new_conf['a']['b'] == 'c' assert conf == {} def test_set_one_level(): conf = {} new_conf = config.set_item_in_config(conf, 'a', 'b') assert new_conf['a'] == 'b' def test_set_multi_level(): conf = {} new_conf = config.set_item_in_config(conf, 'a.b', 'c') new_conf = config.set_item_in_config(new_conf, 'a.d', 'e') new_conf = config.set_item_in_config(new_conf, 'f', 'g') assert new_conf == { 'a': {'b': 'c', 'd': 'e'}, 'f': 'g' } def test_set_overwrite(): """ We can overwrite already existing config items. This might be surprising destructive behavior to some :D """ conf = { 'a': 'b' } new_conf = config.set_item_in_config(conf, 'a', 'c') assert new_conf == {'a': 'c'} new_conf = config.set_item_in_config(new_conf, 'a.b', 'd') assert new_conf == {'a': {'b': 'd'}} new_conf = config.set_item_in_config(new_conf, 'a', 'hi') assert new_conf == {'a': 'hi'} def test_add_to_config_one_level(): conf = {} new_conf = config.add_item_to_config(conf, 'a.b', 'c') assert new_conf == { 'a': {'b': ['c']} } def test_add_to_config_zero_level(): conf = {} new_conf = config.add_item_to_config(conf, 'a', 'b') assert new_conf == { 'a': ['b'] } def test_add_to_config_multiple(): conf = {} new_conf = config.add_item_to_config(conf, 'a.b.c', 'd') assert new_conf == { 'a': {'b': {'c': ['d']}} } new_conf = config.add_item_to_config(new_conf, 'a.b.c', 'e') assert new_conf == { 'a': {'b': {'c': ['d', 'e']}} } def test_remove_from_config(): conf = {} new_conf = config.add_item_to_config(conf, 'a.b.c', 'd') new_conf = config.add_item_to_config(new_conf, 'a.b.c', 'e') assert new_conf == { 'a': {'b': {'c': ['d', 'e']}} } new_conf = config.remove_item_from_config(new_conf, 'a.b.c', 'e') assert new_conf == { 'a': {'b': {'c': ['d']}} } def test_remove_from_config_error(): with pytest.raises(ValueError): config.remove_item_from_config({}, 'a.b.c', 'e') with pytest.raises(ValueError): config.remove_item_from_config({'a': 'b'}, 'a.b', 'e') with pytest.raises(ValueError): config.remove_item_from_config({'a': ['b']}, 'a', 'e') def test_reload_hub(): with mock.patch('tljh.systemd.restart_service') as restart_service, mock.patch( 'tljh.systemd.check_service_active' ) as check_active, mock.patch('tljh.config.check_hub_ready') as check_ready: config.reload_component('hub') assert restart_service.called_with('jupyterhub') assert check_active.called_with('jupyterhub') def test_reload_proxy(tljh_dir): with mock.patch('tljh.systemd.restart_service') as restart_service, mock.patch( 'tljh.systemd.check_service_active' ) as check_active: config.reload_component('proxy') assert restart_service.called_with('traefik') assert check_active.called_with('traefik') assert os.path.exists(os.path.join(config.STATE_DIR, 'traefik.toml')) def test_cli_no_command(capsys): config.main([]) captured = capsys.readouterr() assert "usage:" in captured.out assert "positional arguments:" in captured.out @pytest.mark.parametrize( "arg, value", [ ("true", True), ("FALSE", False) ] ) def test_cli_set_bool(tljh_dir, arg, value): config.main(["set", "https.enabled", arg]) cfg = configurer.load_config() assert cfg['https']['enabled'] == value def test_cli_set_int(tljh_dir): config.main(["set", "https.port", "123"]) cfg = configurer.load_config() assert cfg['https']['port'] == 123 def test_cli_add_float(tljh_dir): config.main(["add-item", "foo.bar", "1.25"]) cfg = configurer.load_config() assert cfg['foo']['bar'] == [1.25] def test_cli_remove_int(tljh_dir): config.main(["add-item", "foo.bar", "1"]) config.main(["add-item", "foo.bar", "2"]) cfg = configurer.load_config() assert cfg['foo']['bar'] == [1, 2] config.main(["remove-item", "foo.bar", "1"]) cfg = configurer.load_config() assert cfg['foo']['bar'] == [2] @pytest.mark.parametrize( "value, expected", [ ("1", 1), ("1.25", 1.25), ("x", "x"), ("1x", "1x"), ("1.2x", "1.2x"), (None, None), ("", ""), ], ) def test_parse_value(value, expected): assert config.parse_value(value) == expected def test_show_config(capsys): """ Test stdout output when showing config """ conf = """ # Just some test YAML a: b: - h - 1 """.strip() with tempfile.NamedTemporaryFile() as tmp: tmp.write(conf.encode()) tmp.flush() config.show_config(tmp.name) out = capsys.readouterr().out assert out.strip() == conf