def test_verify_data_prevents_unwanted_loss(): cfg = hint_deploy.HintConfig("config") cfg.protect_data = True msg = "Cannot remove volumes with this configuration" with mock.patch('src.hint_cli.prompt_yes_no') as prompt: with pytest.raises(Exception, match=msg): hint_cli.verify_data_loss("stop", {"remove_volumes": True}, cfg)
def test_load_config_sets_branch_refs(): path = "config" config = "production" options = {"hint": {"tag": "mrc-123"}, "hintr": {"tag": "mrc-456"}} cfg = hint_deploy.HintConfig(path, config, options=options) assert cfg.hint_tag == "mrc-123" assert cfg.hintr_tag == "mrc-456"
def test_verify_data_loss_warns_if_loss(): cfg = hint_deploy.HintConfig("config") f = io.StringIO() with redirect_stdout(f): with mock.patch('src.hint_cli.prompt_yes_no') as prompt: prompt.return_value = True hint_cli.verify_data_loss("stop", {"remove_volumes": True}, cfg) assert prompt.called assert "WARNING! PROBABLE IRREVERSIBLE DATA LOSS!" in f.getvalue()
def test_verify_data_loss_silent_if_no_loss(): cfg = hint_deploy.HintConfig("config") f = io.StringIO() with redirect_stdout(f): with mock.patch('src.hint_cli.prompt_yes_no') as prompt: prompt.return_value = True hint_cli.verify_data_loss("start", {}, cfg) hint_cli.verify_data_loss("stop", {"remove_volumes": False}, cfg) assert not prompt.called assert f.getvalue() == ""
def test_load_and_reload_config(): path = "config" config = "production" cfg = hint_deploy.HintConfig(path, config) cfg.hint_tag = "develop" hint_cli.save_config(path, config, cfg) hint_cli.read_config(path) config_name, config_value = hint_cli.load_config(path, None) assert config_value.hint_tag == "master" assert config_name == "production" hint_cli.remove_config(path)
def test_start_pulls_db_migrate(): cfg = hint_deploy.HintConfig("config") obj = hint_deploy.hint_constellation(cfg) f = io.StringIO() with redirect_stdout(f): hint_deploy.hint_start(obj, cfg, {"pull_images": True}) p = f.getvalue() assert "Pulling docker image db-migrate" in p obj.destroy() # Start without --pull doesn't pull migrate image f = io.StringIO() with redirect_stdout(f): hint_deploy.hint_start(obj, cfg, {"pull_images": False}) p = f.getvalue() assert "Pulling docker image db-migrate" not in p obj.destroy()
def test_configure_proxy(): cfg = hint_deploy.HintConfig("config", "staging") cl = docker.client.from_env() args = ["localhost:80", "localhost", "80", "443"] container = cl.containers.run("reside/proxy-nginx:master", args, detach=True, auto_remove=False) args = [ "self-signed-certificate", "/tmp", "GB", "London", "IC", "reside", cfg.proxy_host ] docker_util.exec_safely(container, args) cert = docker_util.string_from_container(container, "/tmp/certificate.pem") key = docker_util.string_from_container(container, "/tmp/key.pem") cfg.proxy_ssl_certificate = cert cfg.proxy_ssl_key = key hint_deploy.proxy_configure(container, cfg) assert docker_util.string_from_container( container, "/run/proxy/certificate.pem") == cert assert docker_util.string_from_container(container, "/run/proxy/key.pem") == key container.kill()
def test_start_hint(): cfg = hint_deploy.HintConfig("config") obj = hint_deploy.hint_constellation(cfg) obj.status() obj.start() res = requests.get("http://localhost:8080") assert res.status_code == 200 assert "Naomi" in res.content.decode("UTF-8") res = requests.get("http://localhost:8888") assert res.status_code == 200 assert docker_util.network_exists("hint_nw") assert docker_util.volume_exists("hint_db_data") assert docker_util.volume_exists("hint_uploads") assert docker_util.volume_exists("hint_results") assert docker_util.volume_exists("hint_prerun") assert docker_util.container_exists("hint_db") assert docker_util.container_exists("hint_redis") assert docker_util.container_exists("hint_hintr") assert docker_util.container_exists("hint_hint") assert len(docker_util.containers_matching("hint_worker_", False)) == 2 assert len(docker_util.containers_matching("hint_calibrate_worker_", False)) == 1 # Some basic user management user = "******" f = io.StringIO() with redirect_stdout(f): hint_deploy.hint_user(cfg, "add-user", user, True, "password") p = f.getvalue() assert "Adding user {}".format(user) in p assert p.strip().split("\n")[-1] == "OK" f = io.StringIO() with redirect_stdout(f): hint_deploy.hint_user(cfg, "user-exists", user, False) assert f.getvalue() == "Checking if user exists: {}\ntrue\n".format(user) f = io.StringIO() with redirect_stdout(f): hint_deploy.hint_user(cfg, "add-user", user, True, "password") p = f.getvalue() assert "Not adding user {} as they already exist".format(user) in p f = io.StringIO() with redirect_stdout(f): hint_deploy.hint_user(cfg, "remove-user", user, False) assert f.getvalue() == "Removing user {}\nOK\n".format(user) # Confirm we have brought up exactly two workers (none in the # hintr container itself) script = 'message(httr::content(httr::GET(' + \ '"http://localhost:8888/hintr/worker/status"),' + \ '"text", encoding="UTF-8"))' args = ["Rscript", "-e", script] hintr = obj.containers.get("hintr", obj.prefix) result = docker_util.exec_safely(hintr, args).output logs = result.decode("UTF-8") data = json.loads(logs)["data"] assert len(data.keys()) == 3 obj.destroy() assert not docker_util.network_exists("hint_nw") assert not docker_util.volume_exists("hint_db_data") assert not docker_util.volume_exists("hint_uploads") assert not docker_util.volume_exists("hint_results") assert not docker_util.volume_exists("hint_prerun") assert not docker_util.container_exists("hint_db") assert not docker_util.container_exists("hint_redis") assert not docker_util.container_exists("hint_hintr") assert not docker_util.container_exists("hint_hint") assert len(docker_util.containers_matching("hint_worker_", False)) == 0 assert len(docker_util.containers_matching("hint_calibrate_worker_", False)) == 0
def test_update_hintr_and_all(): hint_cli.main(["start"]) f = io.StringIO() with redirect_stdout(f): hint_cli.main(["upgrade", "hintr"]) p = f.getvalue() assert "Pulling docker image hintr" in p assert "Pulling docker image db-migrate" not in p assert "Stopping previous hintr and workers" in p assert "Starting hintr" in p assert "Starting *service* calibrate_worker" in p assert "Starting *service* worker" in p assert docker_util.network_exists("hint_nw") assert docker_util.volume_exists("hint_db_data") assert docker_util.volume_exists("hint_uploads") assert docker_util.volume_exists("hint_results") assert docker_util.volume_exists("hint_prerun") assert docker_util.container_exists("hint_db") assert docker_util.container_exists("hint_redis") assert docker_util.container_exists("hint_hintr") assert docker_util.container_exists("hint_hint") assert len(docker_util.containers_matching("hint_worker_", False)) == 2 assert len(docker_util.containers_matching("hint_worker_", True)) == 4 assert len(docker_util.containers_matching("hint_calibrate_worker", False)) == 1 assert len(docker_util.containers_matching("hint_calibrate_worker", True)) == 2 # We are going to write some data into redis here and later check # that it survived the upgrade. cfg = hint_deploy.HintConfig("config") obj = hint_deploy.hint_constellation(cfg) args_set = ["redis-cli", "SET", "data_persists", "yes"] redis = obj.containers.get("redis", obj.prefix) docker_util.exec_safely(redis, args_set) f = io.StringIO() with redirect_stdout(f): hint_cli.main(["upgrade", "all"]) p = f.getvalue() assert "Pulling docker image db" in p assert "Pulling docker image db-migrate" in p assert "Stop 'redis'" in p assert "Removing 'redis'" in p assert "Starting redis" in p assert "[redis] Waiting for redis to come up" in p assert docker_util.network_exists("hint_nw") assert docker_util.volume_exists("hint_db_data") assert docker_util.volume_exists("hint_uploads") assert docker_util.volume_exists("hint_results") assert docker_util.volume_exists("hint_prerun") assert docker_util.container_exists("hint_db") assert docker_util.container_exists("hint_redis") assert docker_util.container_exists("hint_hintr") assert docker_util.container_exists("hint_hint") assert len(docker_util.containers_matching("hint_worker_", False)) == 2 assert len(docker_util.containers_matching("hint_calibrate_worker_", False)) == 1 redis = obj.containers.get("redis", obj.prefix) args_get = ["redis-cli", "GET", "data_persists"] result = docker_util.exec_safely(redis, args_get).output.decode("UTF-8") assert "yes" in result obj.destroy()
def test_real_adr_optional(): cfg = hint_deploy.HintConfig("config") assert cfg.hint_adr_url is None
def test_production_uses_real_adr(): cfg = hint_deploy.HintConfig("config", "production") assert cfg.hint_adr_url == "https://adr.unaids.org/"
def test_base_uses_fake_email_configuration(): cfg = hint_deploy.HintConfig("config") assert cfg.hint_email_mode == "disk"
def test_production_and_staging_use_real_email_configuration(): cfg = hint_deploy.HintConfig("config", "production") assert cfg.hint_email_mode == "real" cfg = hint_deploy.HintConfig("config", "staging") assert cfg.hint_email_mode == "real"
def test_verify_data_loss_throws_if_loss(): cfg = hint_deploy.HintConfig("config") with mock.patch('src.hint_cli.prompt_yes_no') as prompt: prompt.return_value = False with pytest.raises(Exception, match="Not continuing"): hint_cli.verify_data_loss("stop", {"remove_volumes": True}, cfg)