From ab43b315d5118d5fc240191feaaa19c3fd371653 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 13:26:21 +0100 Subject: [PATCH 01/28] improve typing --- src/env_file_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env_file_helper.py b/src/env_file_helper.py index 29fb914..80f4d31 100644 --- a/src/env_file_helper.py +++ b/src/env_file_helper.py @@ -28,7 +28,7 @@ def _is_rule_satisfied(in_list: list, rule: DependencyRule) -> tuple[bool, int]: return parent_index < child_index, parent_index -def sort_env_files_by_rule(env_list: list[EnvFile], rules: list[DependencyRule]) -> list: +def sort_env_files_by_rule(env_list: list[EnvFile], rules: list[DependencyRule]) -> list[EnvFile]: in_list = env_list.copy() def swap_item_with_previous(in_list: list[EnvFile], index: int): -- 2.47.2 From fad33956135e8c1dd1afd39bc5097dba6f26fa39 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 13:26:31 +0100 Subject: [PATCH 02/28] successful env file test via pytest --- tests/test_env_resolution.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/test_env_resolution.py b/tests/test_env_resolution.py index 9d14908..6bbb67b 100644 --- a/tests/test_env_resolution.py +++ b/tests/test_env_resolution.py @@ -3,10 +3,8 @@ from pathlib import Path from icecream import ic -sys.path.append(Path(__file__).parent.parent.resolve().__str__()) - +# sys.path.append(Path(__file__).parent.parent.resolve().__str__()) # import pytest - # from prototyping.sorting_algo import Rule, is_rule_satisfied, sort_by_rules from src.coordinator import Coordinator from src.env_file_helper import DependencyRule, EnvFile, sort_env_files_by_rule @@ -50,10 +48,14 @@ ENV_FILES = [ ] -env_files: list[EnvFile] = Coordinator._getn_env_files_list(ENV_FILES) -dependency_rules: list[DependencyRule] = Coordinator._get_dependency_rules(env_files) +def test_real_env_files(): + """authentik should be first""" -ic(env_files) -sorted_env_files = sort_env_files_by_rule(env_files, dependency_rules) -ic(env_files) -ic(sorted_env_files) + env_files: list[EnvFile] = Coordinator._getn_env_files_list(ENV_FILES) + dependency_rules: list[DependencyRule] = Coordinator._get_dependency_rules(env_files) + + ic(env_files) + sorted_env_files = sort_env_files_by_rule(env_files, dependency_rules) + ic(env_files) + ic(sorted_env_files) + assert sorted_env_files[0].env_type == "authentik" -- 2.47.2 From c0605a155fae1a9e792516fa63a874ec9f0b0430 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 13:32:56 +0100 Subject: [PATCH 03/28] add second test, cleanup --- tests/test_env_resolution.py | 70 ++++++++++++------------------------ 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/tests/test_env_resolution.py b/tests/test_env_resolution.py index 6bbb67b..e192de7 100644 --- a/tests/test_env_resolution.py +++ b/tests/test_env_resolution.py @@ -1,61 +1,35 @@ -import sys from pathlib import Path -from icecream import ic - -# sys.path.append(Path(__file__).parent.parent.resolve().__str__()) -# import pytest -# from prototyping.sorting_algo import Rule, is_rule_satisfied, sort_by_rules from src.coordinator import Coordinator from src.env_file_helper import DependencyRule, EnvFile, sort_env_files_by_rule -# @pytest.fixture -# def in_list(): -# return ["a", "b", "c", "d", "e", "f", "g"] + +def test_complex_sorting() -> None: + demo_rules = [ # X depends on Y + DependencyRule("a", "e"), + DependencyRule("b", "e"), + DependencyRule("b", "f"), + DependencyRule("c", "e"), + DependencyRule("d", "e"), + DependencyRule("f", "e"), + ] + + demo_types = ["a", "b", "c", "d", "e", "f", "g"] + env_files = [EnvFile(env_type=t, env_path=Path(), config=dict()) for t in demo_types] + + sorted_env_files = sort_env_files_by_rule(env_files, demo_rules) + + assert sorted_env_files[0].env_type == "e" -# @pytest.fixture -# def rules() -> list[Rule]: -# return [ # X depends on Y -# Rule("a", "e"), -# Rule("b", "e"), -# Rule("b", "f"), -# Rule("c", "e"), -# Rule("d", "e"), -# Rule("f", "e"), -# ] - - -# def has_rules_satisfied(in_list, rules): -# rule_satisfied: list[bool] = [] -# for rule in rules: -# if is_rule_satisfied(in_list, rule): -# rule_satisfied.append(True) -# else: -# rule_satisfied.append(False) -# return all(rule_satisfied) - - -# def test_stuff(in_list, rules): -# sort_by_rules(in_list, rules) -# assert has_unique_elements(in_list) -# assert has_rules_satisfied(in_list, rules) - - -ENV_FILES = [ - Path("envfiles/blog.test.dev.local-it.cloud.env"), # wordpress - Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik -] - - -def test_real_env_files(): +def test_real_env_files() -> None: """authentik should be first""" + ENV_FILES = [ + Path("envfiles/blog.test.dev.local-it.cloud.env"), # wordpress + Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik + ] env_files: list[EnvFile] = Coordinator._getn_env_files_list(ENV_FILES) dependency_rules: list[DependencyRule] = Coordinator._get_dependency_rules(env_files) - - ic(env_files) sorted_env_files = sort_env_files_by_rule(env_files, dependency_rules) - ic(env_files) - ic(sorted_env_files) assert sorted_env_files[0].env_type == "authentik" -- 2.47.2 From e609394ac1aa072303a2777b85bb9d564cf381bd Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 13:37:36 +0100 Subject: [PATCH 04/28] cleanup delete_nextcloud_user --- src/tests_nextcloud/cleanup_nextcloud.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/tests_nextcloud/cleanup_nextcloud.py b/src/tests_nextcloud/cleanup_nextcloud.py index 0bd456f..e510b75 100644 --- a/src/tests_nextcloud/cleanup_nextcloud.py +++ b/src/tests_nextcloud/cleanup_nextcloud.py @@ -1,18 +1,12 @@ -import pytest -from playwright.sync_api import BrowserContext, expect +from playwright.sync_api import Page # todo: what is this test for, why is it a fixture? -> ignore for now -@pytest.fixture(scope="session", autouse=True) -def delete_nextcloud_user(admin_context: BrowserContext): +def delete_nextcloud_user(authentik_admin_page: Page): """Delete Nextcloud User""" - yield - context = setup_context(browser, f"{STATES}/admin_state.json") - page = context.new_page() - page.goto(CONFIG["domain"]) - with page.expect_popup() as nextcloud_info: - page.get_by_role("link", name="Nextcloud").click() + with authentik_admin_page.expect_popup() as nextcloud_info: + authentik_admin_page.get_by_role("link", name="Nextcloud").click() nextcloud = nextcloud_info.value nextcloud.get_by_role("link", name="Open settings menu").click() nextcloud.get_by_role("link", name="Users").click() @@ -21,5 +15,3 @@ def delete_nextcloud_user(admin_context: BrowserContext): ).click() nextcloud.get_by_role("button", name="Delete user").click() nextcloud.get_by_role("button", name=f"Delete authentik-{testuser['username']}'s account").click() - context.tracing.stop(path=f"{RECORDS}/nextcloud_delete_user.zip") - context.close() -- 2.47.2 From 7d7b871b178c081ddfabe859e38041b30a90dc47 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 13:42:03 +0100 Subject: [PATCH 05/28] use demo credentials from nextcloud conftest --- src/tests_nextcloud/cleanup_nextcloud.py | 8 ++++---- src/tests_nextcloud/conftest.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/tests_nextcloud/cleanup_nextcloud.py b/src/tests_nextcloud/cleanup_nextcloud.py index e510b75..22e4f4f 100644 --- a/src/tests_nextcloud/cleanup_nextcloud.py +++ b/src/tests_nextcloud/cleanup_nextcloud.py @@ -1,6 +1,6 @@ -from playwright.sync_api import Page +import os -# todo: what is this test for, why is it a fixture? -> ignore for now +from playwright.sync_api import Page def delete_nextcloud_user(authentik_admin_page: Page): @@ -10,8 +10,8 @@ def delete_nextcloud_user(authentik_admin_page: Page): nextcloud = nextcloud_info.value nextcloud.get_by_role("link", name="Open settings menu").click() nextcloud.get_by_role("link", name="Users").click() - nextcloud.locator("#app-content div").filter(has_text=testuser["username"]).get_by_role( + nextcloud.locator("#app-content div").filter(has_text=os.environ["NEXTCLOUD_USER"]).get_by_role( "button", name="Toggle user actions menu" ).click() nextcloud.get_by_role("button", name="Delete user").click() - nextcloud.get_by_role("button", name=f"Delete authentik-{testuser['username']}'s account").click() + nextcloud.get_by_role("button", name=f"Delete authentik-{os.environ["NEXTCLOUD_USER"]}'s account").click() diff --git a/src/tests_nextcloud/conftest.py b/src/tests_nextcloud/conftest.py index df1eac3..ccb4e5e 100644 --- a/src/tests_nextcloud/conftest.py +++ b/src/tests_nextcloud/conftest.py @@ -1 +1,11 @@ +import os + from src.tests_authentik.fixtures_authentik import admin_context, authentik_admin_page, user_context + +NEXTCLOUD_DEMO_USER = { + "NEXTCLOUD_USER": "next_demo_user", + "NEXTCLOUD_PASS": "P@ss.123", +} + +for key, value in NEXTCLOUD_DEMO_USER.items(): + os.environ[key] = value -- 2.47.2 From 6170840286aee70262b46f6ddf32193161861dae Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 14:13:22 +0100 Subject: [PATCH 06/28] fix imports for /tests --- conftest.py | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 conftest.py diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..8704865 --- /dev/null +++ b/conftest.py @@ -0,0 +1,2 @@ +# this file exists so that tests inside /tests always find /src imports, +# because this will cause the root (/) to be added to sys.path -- 2.47.2 From 126873793c9a736f50b316f324c036bb94ade0fe Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 14:13:42 +0100 Subject: [PATCH 07/28] fix imports --- src/tests_nextcloud/conftest.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tests_nextcloud/conftest.py b/src/tests_nextcloud/conftest.py index ccb4e5e..0805ce5 100644 --- a/src/tests_nextcloud/conftest.py +++ b/src/tests_nextcloud/conftest.py @@ -1,6 +1,11 @@ import os -from src.tests_authentik.fixtures_authentik import admin_context, authentik_admin_page, user_context +from src.tests_authentik.fixtures_authentik import ( + authentik_admin_context, + authentik_admin_page, + authentik_user_context, + authentik_user_page, +) NEXTCLOUD_DEMO_USER = { "NEXTCLOUD_USER": "next_demo_user", -- 2.47.2 From abdbe35daf32df103ded999e059992a90aefe6b5 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 14:30:51 +0100 Subject: [PATCH 08/28] sort_env_files_by_rule now supports duplicate types --- src/env_file_helper.py | 43 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/env_file_helper.py b/src/env_file_helper.py index 80f4d31..5c9440d 100644 --- a/src/env_file_helper.py +++ b/src/env_file_helper.py @@ -18,34 +18,39 @@ class DependencyRule(NamedTuple): dependency: str -def _is_rule_satisfied(in_list: list, rule: DependencyRule) -> tuple[bool, int]: - child_indices = [index for index, element in enumerate(in_list) if element.env_type == rule.child] +def _get_indices_with_string(in_list: list[EnvFile], string: str) -> list[int]: + return [index for index, element in enumerate(in_list) if element.env_type == string] + + +def _swap_item_with_previous(in_list: list[EnvFile], index: int): + """swaps item at index N with item at index N-1""" + assert index > 0, "cannot swap with negative index" + in_list[index], in_list[index - 1] = in_list[index - 1], in_list[index] + + +def _is_rule_satisfied(in_list: list[EnvFile], rule: DependencyRule) -> bool: + child_indices = _get_indices_with_string(in_list, rule.child) + parent_indices = _get_indices_with_string(in_list, rule.dependency) child_index = min(child_indices) - # child_index = in_list.index(rule.child) - parent_indices = [index for index, element in enumerate(in_list) if element.env_type == rule.dependency] - parent_index = max(parent_indices) - # parent_index = in_list.index(rule.dependency) - return parent_index < child_index, parent_index + results: list[bool] = [] + for child_index in child_indices: + for parent_index in parent_indices: + if parent_index < child_index: + results.append(True) + else: + _swap_item_with_previous(in_list, parent_index) + results.append(False) + return all(results) def sort_env_files_by_rule(env_list: list[EnvFile], rules: list[DependencyRule]) -> list[EnvFile]: in_list = env_list.copy() - def swap_item_with_previous(in_list: list[EnvFile], index: int): - """swaps item at index N with item at index N-1""" - assert index > 0, "cannot swap with negative index" - in_list[index], in_list[index - 1] = in_list[index - 1], in_list[index] - for _ in range(10_000): rule_satisfied: list[bool] = [] for rule in rules: - is_rule_satisfied, parent_index = _is_rule_satisfied(in_list, rule) - if is_rule_satisfied: - rule_satisfied.append(True) - else: - rule_satisfied.append(False) - # parent_index = in_list.index(rule.dependency) - swap_item_with_previous(in_list, parent_index) + rule_satisfied.append(_is_rule_satisfied(in_list, rule)) + if all(rule_satisfied): return in_list logger.error("could not find order that satisfys all rules") -- 2.47.2 From 2e988c61505c0eeca73e7cb93a4bd21eb793c032 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 14:35:18 +0100 Subject: [PATCH 09/28] add comments and swap argument --- src/env_file_helper.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/env_file_helper.py b/src/env_file_helper.py index 5c9440d..8e88ad7 100644 --- a/src/env_file_helper.py +++ b/src/env_file_helper.py @@ -19,6 +19,7 @@ class DependencyRule(NamedTuple): def _get_indices_with_string(in_list: list[EnvFile], string: str) -> list[int]: + """returns all indices of items in in_list, where item.env_type matches string""" return [index for index, element in enumerate(in_list) if element.env_type == string] @@ -28,7 +29,11 @@ def _swap_item_with_previous(in_list: list[EnvFile], index: int): in_list[index], in_list[index - 1] = in_list[index - 1], in_list[index] -def _is_rule_satisfied(in_list: list[EnvFile], rule: DependencyRule) -> bool: +def is_rule_satisfied(in_list: list[EnvFile], rule: DependencyRule, swap=False) -> bool: + """returns if the ordering in in_list is compliant with the given rule + + if swap=True, some reordering will happen in case of a violated rule""" + child_indices = _get_indices_with_string(in_list, rule.child) parent_indices = _get_indices_with_string(in_list, rule.dependency) child_index = min(child_indices) @@ -38,7 +43,8 @@ def _is_rule_satisfied(in_list: list[EnvFile], rule: DependencyRule) -> bool: if parent_index < child_index: results.append(True) else: - _swap_item_with_previous(in_list, parent_index) + if swap: + _swap_item_with_previous(in_list, parent_index) results.append(False) return all(results) @@ -49,7 +55,7 @@ def sort_env_files_by_rule(env_list: list[EnvFile], rules: list[DependencyRule]) for _ in range(10_000): rule_satisfied: list[bool] = [] for rule in rules: - rule_satisfied.append(_is_rule_satisfied(in_list, rule)) + rule_satisfied.append(is_rule_satisfied(in_list, rule, swap=True)) if all(rule_satisfied): return in_list -- 2.47.2 From dc50a9d6f70da68eb694b23ff396a757f5aa5eea Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 14:38:09 +0100 Subject: [PATCH 10/28] refactoring and improvement, sort_env_files_by_rule now passes more complex test case --- src/env_file_helper.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/env_file_helper.py b/src/env_file_helper.py index 8e88ad7..4a7d3eb 100644 --- a/src/env_file_helper.py +++ b/src/env_file_helper.py @@ -36,17 +36,13 @@ def is_rule_satisfied(in_list: list[EnvFile], rule: DependencyRule, swap=False) child_indices = _get_indices_with_string(in_list, rule.child) parent_indices = _get_indices_with_string(in_list, rule.dependency) - child_index = min(child_indices) - results: list[bool] = [] for child_index in child_indices: for parent_index in parent_indices: - if parent_index < child_index: - results.append(True) - else: + if not parent_index < child_index: if swap: _swap_item_with_previous(in_list, parent_index) - results.append(False) - return all(results) + return False + return True def sort_env_files_by_rule(env_list: list[EnvFile], rules: list[DependencyRule]) -> list[EnvFile]: -- 2.47.2 From 82fcc0bafbdfded4d3f17142de60390e77db3567 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 14:38:22 +0100 Subject: [PATCH 11/28] add test cases --- tests/test_env_resolution.py | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/test_env_resolution.py b/tests/test_env_resolution.py index e192de7..b8086ca 100644 --- a/tests/test_env_resolution.py +++ b/tests/test_env_resolution.py @@ -33,3 +33,41 @@ def test_real_env_files() -> None: dependency_rules: list[DependencyRule] = Coordinator._get_dependency_rules(env_files) sorted_env_files = sort_env_files_by_rule(env_files, dependency_rules) assert sorted_env_files[0].env_type == "authentik" + + +def test_real_env_files_duplicate() -> None: + """authentik should be first""" + + ENV_FILES = [ + Path("envfiles/blog.test.dev.local-it.cloud.env"), # wordpress + Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik + Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik + ] + env_files: list[EnvFile] = Coordinator._getn_env_files_list(ENV_FILES) + dependency_rules: list[DependencyRule] = Coordinator._get_dependency_rules(env_files) + sorted_env_files = sort_env_files_by_rule(env_files, dependency_rules) + assert sorted_env_files[0].env_type == "authentik" + assert sorted_env_files[1].env_type == "authentik" + assert sorted_env_files[2].env_type == "wordpress" + + +def test_real_env_files_duplicate_six() -> None: + """authentik should be first""" + + ENV_FILES = [ + Path("envfiles/blog.test.dev.local-it.cloud.env"), # wordpress + Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik + Path("envfiles/blog.test.dev.local-it.cloud.env"), # wordpress + Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik + Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik + Path("envfiles/blog.test.dev.local-it.cloud.env"), # wordpress + ] + env_files: list[EnvFile] = Coordinator._getn_env_files_list(ENV_FILES) + dependency_rules: list[DependencyRule] = Coordinator._get_dependency_rules(env_files) + sorted_env_files = sort_env_files_by_rule(env_files, dependency_rules) + assert sorted_env_files[0].env_type == "authentik" + assert sorted_env_files[1].env_type == "authentik" + assert sorted_env_files[2].env_type == "authentik" + assert sorted_env_files[3].env_type == "wordpress" + assert sorted_env_files[4].env_type == "wordpress" + assert sorted_env_files[5].env_type == "wordpress" -- 2.47.2 From dc0e568c04c443a8296c64ac893a11d3b765dfbc Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 14:41:26 +0100 Subject: [PATCH 12/28] add error message to ValueError --- src/env_file_helper.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/env_file_helper.py b/src/env_file_helper.py index 4a7d3eb..9ce4f77 100644 --- a/src/env_file_helper.py +++ b/src/env_file_helper.py @@ -1,8 +1,6 @@ from pathlib import Path from typing import NamedTuple -from loguru import logger - class EnvFile(NamedTuple): env_path: Path @@ -55,5 +53,6 @@ def sort_env_files_by_rule(env_list: list[EnvFile], rules: list[DependencyRule]) if all(rule_satisfied): return in_list - logger.error("could not find order that satisfys all rules") - raise ValueError + raise ValueError( + "Could not resolve test order. This is possibly due to a circular dependency (a on b, b on c, c on a)" + ) -- 2.47.2 From d40ae799918824a9fe6865ee1d8efda2f5f6744d Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 14:44:40 +0100 Subject: [PATCH 13/28] add circular import test --- tests/test_env_resolution.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_env_resolution.py b/tests/test_env_resolution.py index b8086ca..ad6ff60 100644 --- a/tests/test_env_resolution.py +++ b/tests/test_env_resolution.py @@ -1,5 +1,7 @@ from pathlib import Path +import pytest + from src.coordinator import Coordinator from src.env_file_helper import DependencyRule, EnvFile, sort_env_files_by_rule @@ -22,6 +24,20 @@ def test_complex_sorting() -> None: assert sorted_env_files[0].env_type == "e" +def test_circular_import() -> None: + """This test will raise ValueError because the example input cannot be correctly ordered""" + demo_rules = [ + DependencyRule("a", "b"), + DependencyRule("b", "c"), + DependencyRule("c", "a"), + ] + + demo_types = ["a", "b", "c"] + env_files = [EnvFile(env_type=t, env_path=Path(), config=dict()) for t in demo_types] + with pytest.raises(ValueError): + sort_env_files_by_rule(env_files, demo_rules) + + def test_real_env_files() -> None: """authentik should be first""" -- 2.47.2 From 8835243577de087c89850e14ae8f798c712817ff Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:26:56 +0100 Subject: [PATCH 14/28] move stuff to Envmanager --- src/coordinator.py | 41 +++------------------- src/{env_file_helper.py => env_manager.py} | 31 ++++++++++++++++ 2 files changed, 36 insertions(+), 36 deletions(-) rename src/{env_file_helper.py => env_manager.py} (57%) diff --git a/src/coordinator.py b/src/coordinator.py index 0baf934..6e7c035 100644 --- a/src/coordinator.py +++ b/src/coordinator.py @@ -1,28 +1,18 @@ import shutil from pathlib import Path -from dotenv import dotenv_values from loguru import logger from src.dirmanager import DirManager -from src.env_file_helper import DependencyRule, EnvFile, sort_env_files_by_rule +from src.env_manager import EnvFile, EnvManager from src.html_helper import merge_html_files from src.runner import Runner -from src.tests_authentik.runner_authentik import RunnerAuthentik -from src.tests_nextcloud.runner_nextcloud import RunnerNextcloud -from src.tests_wordpress.runner_wordpress import RunnerWordpress from src.utils import rmtree -# Register all runners here. Each .env file with TYPE=authentik will be run with RunnerAuthentik -RUNNER_DICT: dict[str, type[Runner]] = { - "authentik": RunnerAuthentik, - "wordpress": RunnerWordpress, - "nextcloud": RunnerNextcloud, -} - class Coordinator: def __init__(self, env_paths_list: list[Path], output_dir: Path, session_id: str) -> None: + # logging out_string = "".join([e.name + "\n" for e in env_paths_list]) out_string += f"output_dir = {output_dir}\n" out_string += f"session_id = {session_id}" @@ -33,30 +23,9 @@ class Coordinator: self.session_id = session_id # parse env files - self.env_files: list[EnvFile] = self._getn_env_files_list(env_paths_list) - self.dependency_rules: list[DependencyRule] = self._get_dependency_rules(self.env_files) - - @staticmethod - def _getn_env_files_list(env_paths: list[Path]) -> list[EnvFile]: - """Returns a list of EnvFile objects created from the given env files""" - env_files: list[EnvFile] = [] - for env_path in env_paths: - assert env_path.is_file(), f"the env file {env_path} does not exist" - config: dict[str, str] = dotenv_values(env_path) # type: ignore - assert "TYPE" in config, f"the env file {env_path} does not specify the required TYPE key." - env_type = config["TYPE"] - env_files.append(EnvFile(env_path=env_path, config=config, env_type=env_type)) - return env_files - - @staticmethod - def _get_dependency_rules(env_files: list[EnvFile]) -> list[DependencyRule]: - dependency_rules: list[DependencyRule] = [] - for env_file in env_files: - child_runner_class = RUNNER_DICT[env_file.env_type] - for dependency in child_runner_class.dependencies: - dependency_rule = DependencyRule(child=child_runner_class.name, dependency=dependency.name) - dependency_rules.append(dependency_rule) - return dependency_rules + # self.env_files: list[EnvFile] = self._getn_env_files_list(env_paths_list) + # self.dependency_rules: list[DependencyRule] = self._get_dependency_rules(self.env_files) + self.ENV = EnvManager(env_paths_list) def setup_test(self) -> None: logger.info("calling setup_test()") diff --git a/src/env_file_helper.py b/src/env_manager.py similarity index 57% rename from src/env_file_helper.py rename to src/env_manager.py index 9ce4f77..5bca1f6 100644 --- a/src/env_file_helper.py +++ b/src/env_manager.py @@ -1,6 +1,9 @@ from pathlib import Path from typing import NamedTuple +from dotenv import dotenv_values +from loguru import logger + class EnvFile(NamedTuple): env_path: Path @@ -56,3 +59,31 @@ def sort_env_files_by_rule(env_list: list[EnvFile], rules: list[DependencyRule]) raise ValueError( "Could not resolve test order. This is possibly due to a circular dependency (a on b, b on c, c on a)" ) + + +class EnvManager: + def __init__(self, env_paths_list: list[Path]): + self.env_files: list[EnvFile] = self._getn_env_files_list(env_paths_list) + self.dependency_rules: list[DependencyRule] = self._get_dependency_rules(self.env_files) + + @staticmethod + def _getn_env_files_list(env_paths: list[Path]) -> list[EnvFile]: + """Returns a list of EnvFile objects created from the given env files""" + env_files: list[EnvFile] = [] + for env_path in env_paths: + assert env_path.is_file(), f"the env file {env_path} does not exist" + config: dict[str, str] = dotenv_values(env_path) # type: ignore + assert "TYPE" in config, f"the env file {env_path} does not specify the required TYPE key." + env_type = config["TYPE"] + env_files.append(EnvFile(env_path=env_path, config=config, env_type=env_type)) + return env_files + + @staticmethod + def _get_dependency_rules(env_files: list[EnvFile]) -> list[DependencyRule]: + dependency_rules: list[DependencyRule] = [] + for env_file in env_files: + child_runner_class = RUNNER_DICT[env_file.env_type] + for dependency in child_runner_class.dependencies: + dependency_rule = DependencyRule(child=child_runner_class.name, dependency=dependency.name) + dependency_rules.append(dependency_rule) + return dependency_rules -- 2.47.2 From a2f2876e4503029f90d9a1bf314da4242cec76e6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:27:05 +0100 Subject: [PATCH 15/28] put RUNNER_DICT in runner.py --- src/runner.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/runner.py b/src/runner.py index 71ca7ed..e4d500e 100644 --- a/src/runner.py +++ b/src/runner.py @@ -7,6 +7,17 @@ from dotenv import dotenv_values from loguru import logger from src.dirmanager import DirManager +from src.tests_authentik.runner_authentik import RunnerAuthentik +from src.tests_nextcloud.runner_nextcloud import RunnerNextcloud +from src.tests_wordpress.runner_wordpress import RunnerWordpress + +# Register all runners here. Each .env file with TYPE=authentik will be run with RunnerAuthentik + +RUNNER_DICT: dict[str, type["Runner"]] = { + "authentik": RunnerAuthentik, + "wordpress": RunnerWordpress, + "nextcloud": RunnerNextcloud, +} @dataclass -- 2.47.2 From a830be53a5c1c4b59b730d81a71f5d59e90cad04 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:27:44 +0100 Subject: [PATCH 16/28] import RUNNER_DICT --- src/coordinator.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/coordinator.py b/src/coordinator.py index 6e7c035..3631f49 100644 --- a/src/coordinator.py +++ b/src/coordinator.py @@ -6,7 +6,7 @@ from loguru import logger from src.dirmanager import DirManager from src.env_manager import EnvFile, EnvManager from src.html_helper import merge_html_files -from src.runner import Runner +from src.runner import RUNNER_DICT, Runner from src.utils import rmtree @@ -22,9 +22,6 @@ class Coordinator: self.output_dir = output_dir self.session_id = session_id - # parse env files - # self.env_files: list[EnvFile] = self._getn_env_files_list(env_paths_list) - # self.dependency_rules: list[DependencyRule] = self._get_dependency_rules(self.env_files) self.ENV = EnvManager(env_paths_list) def setup_test(self) -> None: @@ -36,12 +33,12 @@ class Coordinator: """Copies all env files to STATES/env_files. Files will be renamed to their own TYPE value.""" env_files_dir = self.DIR.STATES / "env_files" env_files_dir.mkdir(exist_ok=True) - for env_file in self.env_files: + for env_file in self.ENV.env_files: shutil.copy(env_file.env_path, env_files_dir / env_file.env_type) def run_test(self) -> None: logger.info("calling run_test()") - self.runners: list[Runner] = self._load_runners(self.env_files) + self.runners: list[Runner] = self._load_runners(self.ENV.env_files) for runner in self.runners: runner.run_setups() for runner in self.runners: -- 2.47.2 From 73969a2a3ba1bfce49df32229b0df2b2cdbcb3db Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:28:15 +0100 Subject: [PATCH 17/28] remove self.session_id --- src/coordinator.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/coordinator.py b/src/coordinator.py index 3631f49..99d1f66 100644 --- a/src/coordinator.py +++ b/src/coordinator.py @@ -19,9 +19,6 @@ class Coordinator: logger.info(f"initialize Coordinator instance with\nenv_paths_list =\n{out_string}") self.DIR = DirManager(output_dir=output_dir, session_id=session_id) - self.output_dir = output_dir - self.session_id = session_id - self.ENV = EnvManager(env_paths_list) def setup_test(self) -> None: @@ -53,7 +50,9 @@ class Coordinator: for env_file in env_files: RunnerClass = RUNNER_DICT[env_file.config["TYPE"]] runners.append( - RunnerClass(dotenv_path=env_file.env_path, output_dir=self.output_dir, session_id=self.session_id) + RunnerClass( + dotenv_path=env_file.env_path, output_dir=self.DIR.output_dir, session_id=self.DIR.session_id + ) ) return runners -- 2.47.2 From a077afa92ae4e3f68dc97eef69fd36e63c4e76bb Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:29:08 +0100 Subject: [PATCH 18/28] make output_dir public --- src/dirmanager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dirmanager.py b/src/dirmanager.py index b5228bf..256b9df 100644 --- a/src/dirmanager.py +++ b/src/dirmanager.py @@ -20,18 +20,18 @@ class DirManager: # root test dir if isinstance(output_dir, str): output_dir = Path(output_dir) - self._output_dir = output_dir.resolve() + self.output_dir = output_dir.resolve() self.session_id = session_id def create_all_dirs(self): - self.create_dirs(self._output_dir, exist_ok=True) + self.create_dirs(self.output_dir, exist_ok=True) self.create_dirs( [self.SESSION, self.RECORDS, self.HTML, self.STATES, self.ENV_FILES, self.RESULTS], exist_ok=True ) @property def OUTPUT_DIR(self): - return self._output_dir + return self.output_dir @property def SESSION(self): -- 2.47.2 From 9a7606a740419fffffdc38750ddb929b98e4ad88 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:31:06 +0100 Subject: [PATCH 19/28] move copy_env_files to env_manager --- src/coordinator.py | 10 +--------- src/env_manager.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/coordinator.py b/src/coordinator.py index 99d1f66..e306bba 100644 --- a/src/coordinator.py +++ b/src/coordinator.py @@ -1,4 +1,3 @@ -import shutil from pathlib import Path from loguru import logger @@ -24,14 +23,7 @@ class Coordinator: def setup_test(self) -> None: logger.info("calling setup_test()") self.DIR.create_all_dirs() - self._copy_env_files() - - def _copy_env_files(self) -> None: - """Copies all env files to STATES/env_files. Files will be renamed to their own TYPE value.""" - env_files_dir = self.DIR.STATES / "env_files" - env_files_dir.mkdir(exist_ok=True) - for env_file in self.ENV.env_files: - shutil.copy(env_file.env_path, env_files_dir / env_file.env_type) + self.ENV.copy_env_files(self.DIR) def run_test(self) -> None: logger.info("calling run_test()") diff --git a/src/env_manager.py b/src/env_manager.py index 5bca1f6..239f9a9 100644 --- a/src/env_manager.py +++ b/src/env_manager.py @@ -1,9 +1,12 @@ +import shutil from pathlib import Path from typing import NamedTuple from dotenv import dotenv_values from loguru import logger +from src.dirmanager import DirManager + class EnvFile(NamedTuple): env_path: Path @@ -87,3 +90,10 @@ class EnvManager: dependency_rule = DependencyRule(child=child_runner_class.name, dependency=dependency.name) dependency_rules.append(dependency_rule) return dependency_rules + + def copy_env_files(self, DIR: DirManager) -> None: + """Copies all env files to STATES/env_files. Files will be renamed to their own TYPE value.""" + env_files_dir = DIR.STATES / "env_files" + env_files_dir.mkdir(exist_ok=True) + for env_file in self.env_files: + shutil.copy(env_file.env_path, env_files_dir / env_file.env_type) -- 2.47.2 From 21e9c740484d85c7176a1d6f62b7dee644c20043 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:31:22 +0100 Subject: [PATCH 20/28] rename dir_manager.py --- main.py | 2 +- previous-work/wordpress_test.py | 2 +- src/conftest.py | 2 +- src/coordinator.py | 2 +- src/{dirmanager.py => dir_manager.py} | 0 src/env_manager.py | 2 +- src/runner.py | 2 +- src/tests_authentik/fixtures_authentik.py | 2 +- src/tests_authentik/setup_authentik.py | 2 +- src/tests_wordpress/conftest.py | 2 +- src/tests_wordpress/setup_wordpress.py | 2 +- src/tests_wordpress/test_wordpress_localization.py | 2 +- 12 files changed, 11 insertions(+), 11 deletions(-) rename src/{dirmanager.py => dir_manager.py} (100%) diff --git a/main.py b/main.py index 9005385..5821bdf 100644 --- a/main.py +++ b/main.py @@ -5,7 +5,7 @@ from pathlib import Path from loguru import logger from src.coordinator import Coordinator -from src.dirmanager import DirManager +from src.dir_manager import DirManager from src.utils import get_session_id # ----------------------------- lookup env files ----------------------------- # diff --git a/previous-work/wordpress_test.py b/previous-work/wordpress_test.py index 1d65311..0e84a46 100644 --- a/previous-work/wordpress_test.py +++ b/previous-work/wordpress_test.py @@ -1,6 +1,6 @@ from playwright.sync_api import BrowserContext, expect -from src.dirmanager import DirManager +from src.dir_manager import DirManager def test_wordpress(admin_session: BrowserContext, dotenv_config: dict[str, str], DIR: DirManager): diff --git a/src/conftest.py b/src/conftest.py index 690aaf6..6098f4e 100644 --- a/src/conftest.py +++ b/src/conftest.py @@ -14,7 +14,7 @@ from dotenv import dotenv_values from playwright.sync_api import BrowserContext, expect from pytest import Parser -from src.dirmanager import DirManager +from src.dir_manager import DirManager # global timeout and LOCALE LOCALE = {"Accept-Language": "de_DE"} diff --git a/src/coordinator.py b/src/coordinator.py index e306bba..74e53fd 100644 --- a/src/coordinator.py +++ b/src/coordinator.py @@ -2,7 +2,7 @@ from pathlib import Path from loguru import logger -from src.dirmanager import DirManager +from src.dir_manager import DirManager from src.env_manager import EnvFile, EnvManager from src.html_helper import merge_html_files from src.runner import RUNNER_DICT, Runner diff --git a/src/dirmanager.py b/src/dir_manager.py similarity index 100% rename from src/dirmanager.py rename to src/dir_manager.py diff --git a/src/env_manager.py b/src/env_manager.py index 239f9a9..5524e36 100644 --- a/src/env_manager.py +++ b/src/env_manager.py @@ -5,7 +5,7 @@ from typing import NamedTuple from dotenv import dotenv_values from loguru import logger -from src.dirmanager import DirManager +from src.dir_manager import DirManager class EnvFile(NamedTuple): diff --git a/src/runner.py b/src/runner.py index e4d500e..4a54b61 100644 --- a/src/runner.py +++ b/src/runner.py @@ -6,7 +6,7 @@ import pytest from dotenv import dotenv_values from loguru import logger -from src.dirmanager import DirManager +from src.dir_manager import DirManager from src.tests_authentik.runner_authentik import RunnerAuthentik from src.tests_nextcloud.runner_nextcloud import RunnerNextcloud from src.tests_wordpress.runner_wordpress import RunnerWordpress diff --git a/src/tests_authentik/fixtures_authentik.py b/src/tests_authentik/fixtures_authentik.py index d4c21c8..6b24538 100644 --- a/src/tests_authentik/fixtures_authentik.py +++ b/src/tests_authentik/fixtures_authentik.py @@ -4,7 +4,7 @@ import pytest from dotenv import dotenv_values from playwright.sync_api import BrowserContext, Page -from src.dirmanager import DirManager +from src.dir_manager import DirManager @pytest.fixture diff --git a/src/tests_authentik/setup_authentik.py b/src/tests_authentik/setup_authentik.py index 7927895..18a4e3f 100644 --- a/src/tests_authentik/setup_authentik.py +++ b/src/tests_authentik/setup_authentik.py @@ -4,7 +4,7 @@ import re from playwright.sync_api import BrowserContext, expect -from src.dirmanager import DirManager +from src.dir_manager import DirManager ADMIN_USER = os.environ["ADMIN_USER"] ADMIN_PASS = os.environ["ADMIN_PASS"] diff --git a/src/tests_wordpress/conftest.py b/src/tests_wordpress/conftest.py index f2d4e2c..ac095dc 100644 --- a/src/tests_wordpress/conftest.py +++ b/src/tests_wordpress/conftest.py @@ -4,7 +4,7 @@ import pytest from dotenv import dotenv_values from playwright.sync_api import BrowserContext, Page -from src.dirmanager import DirManager +from src.dir_manager import DirManager # from src.tests_authentik.fixtures_authentik import ( # authentik_admin_context, diff --git a/src/tests_wordpress/setup_wordpress.py b/src/tests_wordpress/setup_wordpress.py index 6543c9d..725964b 100644 --- a/src/tests_wordpress/setup_wordpress.py +++ b/src/tests_wordpress/setup_wordpress.py @@ -1,7 +1,7 @@ import pytest from playwright.sync_api import BrowserContext, Page, expect -from src.dirmanager import DirManager +from src.dir_manager import DirManager @pytest.mark.xfail(reason="wordpress sso login has not been generated") diff --git a/src/tests_wordpress/test_wordpress_localization.py b/src/tests_wordpress/test_wordpress_localization.py index 77bce95..8c9ffa4 100644 --- a/src/tests_wordpress/test_wordpress_localization.py +++ b/src/tests_wordpress/test_wordpress_localization.py @@ -2,7 +2,7 @@ from playwright.sync_api import BrowserContext, expect -from src.dirmanager import DirManager +from src.dir_manager import DirManager def test_welcome_message(context: BrowserContext, dotenv_config: dict[str, str], DIR: DirManager): -- 2.47.2 From e903360767b6991e23e7628d6b9133d55dea9767 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:32:02 +0100 Subject: [PATCH 21/28] import RUNNER_DICT --- src/env_manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/env_manager.py b/src/env_manager.py index 5524e36..6857293 100644 --- a/src/env_manager.py +++ b/src/env_manager.py @@ -6,6 +6,7 @@ from dotenv import dotenv_values from loguru import logger from src.dir_manager import DirManager +from src.runner import RUNNER_DICT class EnvFile(NamedTuple): -- 2.47.2 From eb0714da9b13f2edcebc15c45110c86b15bf0e0e Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:40:17 +0100 Subject: [PATCH 22/28] move functions to envmanager --- src/env_manager.py | 92 +++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/env_manager.py b/src/env_manager.py index 6857293..cfc81fb 100644 --- a/src/env_manager.py +++ b/src/env_manager.py @@ -3,10 +3,9 @@ from pathlib import Path from typing import NamedTuple from dotenv import dotenv_values -from loguru import logger from src.dir_manager import DirManager -from src.runner import RUNNER_DICT +from src.runner_dict import RUNNER_DICT class EnvFile(NamedTuple): @@ -23,55 +22,14 @@ class DependencyRule(NamedTuple): dependency: str -def _get_indices_with_string(in_list: list[EnvFile], string: str) -> list[int]: - """returns all indices of items in in_list, where item.env_type matches string""" - return [index for index, element in enumerate(in_list) if element.env_type == string] - - -def _swap_item_with_previous(in_list: list[EnvFile], index: int): - """swaps item at index N with item at index N-1""" - assert index > 0, "cannot swap with negative index" - in_list[index], in_list[index - 1] = in_list[index - 1], in_list[index] - - -def is_rule_satisfied(in_list: list[EnvFile], rule: DependencyRule, swap=False) -> bool: - """returns if the ordering in in_list is compliant with the given rule - - if swap=True, some reordering will happen in case of a violated rule""" - - child_indices = _get_indices_with_string(in_list, rule.child) - parent_indices = _get_indices_with_string(in_list, rule.dependency) - for child_index in child_indices: - for parent_index in parent_indices: - if not parent_index < child_index: - if swap: - _swap_item_with_previous(in_list, parent_index) - return False - return True - - -def sort_env_files_by_rule(env_list: list[EnvFile], rules: list[DependencyRule]) -> list[EnvFile]: - in_list = env_list.copy() - - for _ in range(10_000): - rule_satisfied: list[bool] = [] - for rule in rules: - rule_satisfied.append(is_rule_satisfied(in_list, rule, swap=True)) - - if all(rule_satisfied): - return in_list - raise ValueError( - "Could not resolve test order. This is possibly due to a circular dependency (a on b, b on c, c on a)" - ) - - class EnvManager: def __init__(self, env_paths_list: list[Path]): - self.env_files: list[EnvFile] = self._getn_env_files_list(env_paths_list) + self.env_files: list[EnvFile] = self._get_env_files(env_paths_list) self.dependency_rules: list[DependencyRule] = self._get_dependency_rules(self.env_files) + self.env_files = self.sort_env_files_by_rule(self.env_files, self.dependency_rules) @staticmethod - def _getn_env_files_list(env_paths: list[Path]) -> list[EnvFile]: + def _get_env_files(env_paths: list[Path]) -> list[EnvFile]: """Returns a list of EnvFile objects created from the given env files""" env_files: list[EnvFile] = [] for env_path in env_paths: @@ -92,6 +50,48 @@ class EnvManager: dependency_rules.append(dependency_rule) return dependency_rules + @staticmethod + def _get_indices_by_string(in_list: list[EnvFile], string: str) -> list[int]: + """returns all indices of items in in_list, where item.env_type matches string""" + return [index for index, element in enumerate(in_list) if element.env_type == string] + + @staticmethod + def _swap_item_with_previous(in_list: list[EnvFile], index: int): + """swaps item at index N with item at index N-1""" + assert index > 0, "cannot swap with negative index" + in_list[index], in_list[index - 1] = in_list[index - 1], in_list[index] + + @classmethod + def is_rule_satisfied(cls, env_list: list[EnvFile], rule: DependencyRule, swap=False) -> bool: + """returns if the ordering in in_list is compliant with the given rule + + if swap=True, some reordering will happen in case of a violated rule""" + + child_indices = cls._get_indices_by_string(env_list, rule.child) + parent_indices = cls._get_indices_by_string(env_list, rule.dependency) + for child_index in child_indices: + for parent_index in parent_indices: + if not parent_index < child_index: + if swap: + cls._swap_item_with_previous(env_list, parent_index) + return False + return True + + @classmethod + def sort_env_files_by_rule(cls, env_list: list[EnvFile], rules: list[DependencyRule]) -> list[EnvFile]: + out_list = env_list.copy() + + for _ in range(10_000): + rule_satisfied: list[bool] = [] + for rule in rules: + rule_satisfied.append(cls.is_rule_satisfied(out_list, rule, swap=True)) + + if all(rule_satisfied): + return out_list + raise ValueError( + "Could not resolve test order. This is possibly due to a circular dependency (a on b, b on c, c on a)" + ) + def copy_env_files(self, DIR: DirManager) -> None: """Copies all env files to STATES/env_files. Files will be renamed to their own TYPE value.""" env_files_dir = DIR.STATES / "env_files" -- 2.47.2 From 87126ef254745ce4205ae068543fd8a0ba9d88fc Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:40:28 +0100 Subject: [PATCH 23/28] move runner_dict to its own file to prevent circular import --- src/coordinator.py | 3 ++- src/runner.py | 11 ----------- src/runner_dict.py | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 src/runner_dict.py diff --git a/src/coordinator.py b/src/coordinator.py index 74e53fd..509aa3e 100644 --- a/src/coordinator.py +++ b/src/coordinator.py @@ -5,7 +5,8 @@ from loguru import logger from src.dir_manager import DirManager from src.env_manager import EnvFile, EnvManager from src.html_helper import merge_html_files -from src.runner import RUNNER_DICT, Runner +from src.runner import Runner +from src.runner_dict import RUNNER_DICT from src.utils import rmtree diff --git a/src/runner.py b/src/runner.py index 4a54b61..8ef444a 100644 --- a/src/runner.py +++ b/src/runner.py @@ -7,17 +7,6 @@ from dotenv import dotenv_values from loguru import logger from src.dir_manager import DirManager -from src.tests_authentik.runner_authentik import RunnerAuthentik -from src.tests_nextcloud.runner_nextcloud import RunnerNextcloud -from src.tests_wordpress.runner_wordpress import RunnerWordpress - -# Register all runners here. Each .env file with TYPE=authentik will be run with RunnerAuthentik - -RUNNER_DICT: dict[str, type["Runner"]] = { - "authentik": RunnerAuthentik, - "wordpress": RunnerWordpress, - "nextcloud": RunnerNextcloud, -} @dataclass diff --git a/src/runner_dict.py b/src/runner_dict.py new file mode 100644 index 0000000..5b000db --- /dev/null +++ b/src/runner_dict.py @@ -0,0 +1,16 @@ +from typing import TYPE_CHECKING + +from src.tests_authentik.runner_authentik import RunnerAuthentik +from src.tests_nextcloud.runner_nextcloud import RunnerNextcloud +from src.tests_wordpress.runner_wordpress import RunnerWordpress + +if TYPE_CHECKING: + from src.runner import Runner + +# Register all runners here. Each .env file with TYPE=authentik will be run with RunnerAuthentik + +RUNNER_DICT: dict[str, type["Runner"]] = { + "authentik": RunnerAuthentik, + "wordpress": RunnerWordpress, + "nextcloud": RunnerNextcloud, +} -- 2.47.2 From beddd1f46970c5e90cd2b770380f7260164903c5 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:43:18 +0100 Subject: [PATCH 24/28] fix all tests with new imports --- tests/test_env_resolution.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tests/test_env_resolution.py b/tests/test_env_resolution.py index ad6ff60..19c8ad8 100644 --- a/tests/test_env_resolution.py +++ b/tests/test_env_resolution.py @@ -3,7 +3,9 @@ from pathlib import Path import pytest from src.coordinator import Coordinator -from src.env_file_helper import DependencyRule, EnvFile, sort_env_files_by_rule + +# from src.env_file_helper import DependencyRule, EnvFile, sort_env_files_by_rule +from src.env_manager import DependencyRule, EnvFile, EnvManager def test_complex_sorting() -> None: @@ -18,8 +20,8 @@ def test_complex_sorting() -> None: demo_types = ["a", "b", "c", "d", "e", "f", "g"] env_files = [EnvFile(env_type=t, env_path=Path(), config=dict()) for t in demo_types] - - sorted_env_files = sort_env_files_by_rule(env_files, demo_rules) + EnvManager.sort_env_files_by_rule + sorted_env_files = EnvManager.sort_env_files_by_rule(env_files, demo_rules) assert sorted_env_files[0].env_type == "e" @@ -35,7 +37,7 @@ def test_circular_import() -> None: demo_types = ["a", "b", "c"] env_files = [EnvFile(env_type=t, env_path=Path(), config=dict()) for t in demo_types] with pytest.raises(ValueError): - sort_env_files_by_rule(env_files, demo_rules) + EnvManager.sort_env_files_by_rule(env_files, demo_rules) def test_real_env_files() -> None: @@ -45,9 +47,9 @@ def test_real_env_files() -> None: Path("envfiles/blog.test.dev.local-it.cloud.env"), # wordpress Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik ] - env_files: list[EnvFile] = Coordinator._getn_env_files_list(ENV_FILES) - dependency_rules: list[DependencyRule] = Coordinator._get_dependency_rules(env_files) - sorted_env_files = sort_env_files_by_rule(env_files, dependency_rules) + env_files: list[EnvFile] = EnvManager._get_env_files(ENV_FILES) + dependency_rules: list[DependencyRule] = EnvManager._get_dependency_rules(env_files) + sorted_env_files = EnvManager.sort_env_files_by_rule(env_files, dependency_rules) assert sorted_env_files[0].env_type == "authentik" @@ -59,9 +61,9 @@ def test_real_env_files_duplicate() -> None: Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik ] - env_files: list[EnvFile] = Coordinator._getn_env_files_list(ENV_FILES) - dependency_rules: list[DependencyRule] = Coordinator._get_dependency_rules(env_files) - sorted_env_files = sort_env_files_by_rule(env_files, dependency_rules) + env_files: list[EnvFile] = EnvManager._get_env_files(ENV_FILES) + dependency_rules: list[DependencyRule] = EnvManager._get_dependency_rules(env_files) + sorted_env_files = EnvManager.sort_env_files_by_rule(env_files, dependency_rules) assert sorted_env_files[0].env_type == "authentik" assert sorted_env_files[1].env_type == "authentik" assert sorted_env_files[2].env_type == "wordpress" @@ -78,9 +80,9 @@ def test_real_env_files_duplicate_six() -> None: Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik Path("envfiles/blog.test.dev.local-it.cloud.env"), # wordpress ] - env_files: list[EnvFile] = Coordinator._getn_env_files_list(ENV_FILES) - dependency_rules: list[DependencyRule] = Coordinator._get_dependency_rules(env_files) - sorted_env_files = sort_env_files_by_rule(env_files, dependency_rules) + env_files: list[EnvFile] = EnvManager._get_env_files(ENV_FILES) + dependency_rules: list[DependencyRule] = EnvManager._get_dependency_rules(env_files) + sorted_env_files = EnvManager.sort_env_files_by_rule(env_files, dependency_rules) assert sorted_env_files[0].env_type == "authentik" assert sorted_env_files[1].env_type == "authentik" assert sorted_env_files[2].env_type == "authentik" -- 2.47.2 From 96cee5fa118172b8fc668d5e51992214bd03d729 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:43:29 +0100 Subject: [PATCH 25/28] cleanup --- tests/test_env_resolution.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_env_resolution.py b/tests/test_env_resolution.py index 19c8ad8..ca446a4 100644 --- a/tests/test_env_resolution.py +++ b/tests/test_env_resolution.py @@ -2,8 +2,6 @@ from pathlib import Path import pytest -from src.coordinator import Coordinator - # from src.env_file_helper import DependencyRule, EnvFile, sort_env_files_by_rule from src.env_manager import DependencyRule, EnvFile, EnvManager -- 2.47.2 From bf1601c608daf42535d837464430ec9e15004e33 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 15:46:03 +0100 Subject: [PATCH 26/28] add test for EnvManager --- tests/test_env_resolution.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_env_resolution.py b/tests/test_env_resolution.py index ca446a4..2c1bc97 100644 --- a/tests/test_env_resolution.py +++ b/tests/test_env_resolution.py @@ -87,3 +87,15 @@ def test_real_env_files_duplicate_six() -> None: assert sorted_env_files[3].env_type == "wordpress" assert sorted_env_files[4].env_type == "wordpress" assert sorted_env_files[5].env_type == "wordpress" + + +def test_env_manager() -> None: + env_paths_list = [ + Path("envfiles/blog.test.dev.local-it.cloud.env"), # wordpress + Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik + Path("envfiles/login.test.dev.local-it.cloud.env"), # authentik + ] + ENV = EnvManager(env_paths_list) + assert ENV.env_files[0].env_type == "authentik" + assert ENV.env_files[1].env_type == "authentik" + assert ENV.env_files[2].env_type == "wordpress" -- 2.47.2 From 83ecd92a8fd655c18fe38794483e536eef2726ff Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 16:20:02 +0100 Subject: [PATCH 27/28] remove create_dirs --- src/dir_manager.py | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/dir_manager.py b/src/dir_manager.py index 256b9df..10cb867 100644 --- a/src/dir_manager.py +++ b/src/dir_manager.py @@ -23,11 +23,18 @@ class DirManager: self.output_dir = output_dir.resolve() self.session_id = session_id - def create_all_dirs(self): - self.create_dirs(self.output_dir, exist_ok=True) - self.create_dirs( - [self.SESSION, self.RECORDS, self.HTML, self.STATES, self.ENV_FILES, self.RESULTS], exist_ok=True - ) + def create_all_dirs(self) -> None: + dirs: list[Path] = [ + self.OUTPUT_DIR, + self.SESSION, + self.RECORDS, + self.HTML, + self.STATES, + self.ENV_FILES, + self.RESULTS, + ] + for d in dirs: + d.mkdir(exist_ok=True) @property def OUTPUT_DIR(self): @@ -56,15 +63,3 @@ class DirManager: @property def RESULTS(self): return self.SESSION / "results" - - @staticmethod - def create_dirs(dirs: Path | list[Path] | dict[str, Path], exist_ok=False): - match dirs: - case Path(): - dirs.mkdir(exist_ok=exist_ok) - case list(): - for d in dirs: - d.mkdir(exist_ok=exist_ok) - case dict(): - for d in dirs.values(): - d.mkdir(exist_ok=exist_ok) -- 2.47.2 From dbe968bc5e9ba53391f927dd786b14b105c3f7ca Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Dec 2023 16:34:24 +0100 Subject: [PATCH 28/28] replace pytest.mark.xfail with pytest.raises --- src/tests_wordpress/setup_wordpress.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tests_wordpress/setup_wordpress.py b/src/tests_wordpress/setup_wordpress.py index 725964b..4feca93 100644 --- a/src/tests_wordpress/setup_wordpress.py +++ b/src/tests_wordpress/setup_wordpress.py @@ -4,16 +4,14 @@ from playwright.sync_api import BrowserContext, Page, expect from src.dir_manager import DirManager -@pytest.mark.xfail(reason="wordpress sso login has not been generated") def test_visit_from_domain(authentik_admin_context: BrowserContext, dotenv_config: dict[str, str]): """visit wordpress directly with admin_session, expect not to be logged in""" page = authentik_admin_context.new_page() url = "https://" + dotenv_config["DOMAIN"] page.goto(url) - # look for content wrapper - expect(page.locator("#wpcontent")).to_be_visible(timeout=3_000) - # look for admin bar - expect(page.locator("#wpadminbar")).to_be_visible(timeout=3_000) + with pytest.raises(AssertionError): + # look for admin bar + expect(page.locator("#wpadminbar")).to_be_visible(timeout=3_000) def setup_wordpress_admin_session(authentik_admin_page: Page, DIR: DirManager): -- 2.47.2