|
| 1 | +import shutil |
| 2 | +from pathlib import Path |
| 3 | + |
| 4 | +import luigi |
| 5 | +import pytest |
| 6 | + |
| 7 | +from exasol_integration_test_docker_environment.lib.base.docker_base_task import ( |
| 8 | + DockerBaseTask, |
| 9 | +) |
| 10 | +from exasol_integration_test_docker_environment.lib.base.run_task import ( |
| 11 | + generate_root_task, |
| 12 | +) |
| 13 | +from exasol_integration_test_docker_environment.lib.docker import ContextDockerClient |
| 14 | +from exasol_integration_test_docker_environment.lib.models.config.build_config import ( |
| 15 | + set_build_config, |
| 16 | +) |
| 17 | +from exasol_integration_test_docker_environment.lib.models.config.docker_config import ( |
| 18 | + set_docker_repository_config, |
| 19 | +) |
| 20 | +from exasol_integration_test_docker_environment.lib.models.data.container_info import ( |
| 21 | + ContainerInfo, |
| 22 | +) |
| 23 | +from exasol_integration_test_docker_environment.lib.models.data.test_container_content_description import ( |
| 24 | + TestContainerContentDescription, |
| 25 | +) |
| 26 | +from exasol_integration_test_docker_environment.lib.test_environment.parameter.test_container_parameter import ( |
| 27 | + TestContainerParameter, |
| 28 | +) |
| 29 | +from exasol_integration_test_docker_environment.lib.test_environment.prepare_network_for_test_environment import ( |
| 30 | + PrepareDockerNetworkForTestEnvironment, |
| 31 | +) |
| 32 | +from exasol_integration_test_docker_environment.lib.test_environment.spawn_test_container import ( |
| 33 | + SpawnTestContainer, |
| 34 | +) |
| 35 | +from exasol_integration_test_docker_environment.test.get_test_container_content import ( |
| 36 | + TEST_CONTAINER_REUSE_ROOT_PATH, |
| 37 | +) |
| 38 | +from exasol_integration_test_docker_environment.testing import luigi_utils |
| 39 | + |
| 40 | + |
| 41 | +class TestTask(DockerBaseTask, TestContainerParameter): |
| 42 | + reuse = luigi.BoolParameter() |
| 43 | + attempt = luigi.IntParameter() |
| 44 | + |
| 45 | + def run_task(self): |
| 46 | + docker_network_task_1 = self.create_child_task( |
| 47 | + task_class=PrepareDockerNetworkForTestEnvironment, |
| 48 | + environment_name="test_environment_TestContainerReuseTest", |
| 49 | + network_name="docker_network_TestContainerReuseTest", |
| 50 | + test_container_name="test_container_TestContainerReuseTest", |
| 51 | + db_container_name="db_container_TestContainerReuseTest", |
| 52 | + reuse=self.reuse, |
| 53 | + no_cleanup_after_success=True, |
| 54 | + no_cleanup_after_failure=False, |
| 55 | + attempt=self.attempt, |
| 56 | + ) |
| 57 | + self.docker_network_future_1 = yield from self.run_dependencies( |
| 58 | + docker_network_task_1 |
| 59 | + ) |
| 60 | + |
| 61 | + test_container_task_1 = self.create_child_task( |
| 62 | + task_class=SpawnTestContainer, |
| 63 | + environment_name="test_environment_TestContainerReuseTest", |
| 64 | + test_container_name="test_container_TestContainerReuseTest", |
| 65 | + network_info=self.docker_network_future_1.get_output(), |
| 66 | + ip_address_index_in_subnet=2, |
| 67 | + attempt=self.attempt, |
| 68 | + reuse_test_container=self.reuse, |
| 69 | + no_test_container_cleanup_after_success=True, |
| 70 | + no_test_container_cleanup_after_failure=False, |
| 71 | + test_container_content=self.test_container_content, |
| 72 | + ) |
| 73 | + test_container_future_1 = yield from self.run_dependencies( |
| 74 | + test_container_task_1 |
| 75 | + ) |
| 76 | + container_info: ContainerInfo = test_container_future_1.get_output() # type: ignore |
| 77 | + with ContextDockerClient() as docker_client: |
| 78 | + container = docker_client.containers.get(container_info.container_name) |
| 79 | + self.return_object( |
| 80 | + {"container_id": container.id, "image_id": container.image.id} |
| 81 | + ) |
| 82 | + |
| 83 | + |
| 84 | +def _setup_luigi_config(output_directory: Path, docker_repository_name: str): |
| 85 | + set_build_config( |
| 86 | + force_rebuild=False, |
| 87 | + force_pull=False, |
| 88 | + force_rebuild_from=(), |
| 89 | + log_build_context_content=False, |
| 90 | + output_directory=str(output_directory), |
| 91 | + cache_directory="", |
| 92 | + build_name="", |
| 93 | + temporary_base_directory="/tmp", |
| 94 | + ) |
| 95 | + set_docker_repository_config( |
| 96 | + docker_password=None, |
| 97 | + docker_repository_name=docker_repository_name, |
| 98 | + docker_username=None, |
| 99 | + tag_prefix="", |
| 100 | + kind="target", |
| 101 | + ) |
| 102 | + |
| 103 | + |
| 104 | +@pytest.fixture |
| 105 | +def working_directory(tmp_path_factory): |
| 106 | + resource_directory = TEST_CONTAINER_REUSE_ROOT_PATH |
| 107 | + |
| 108 | + temp_directory = tmp_path_factory.mktemp("container") |
| 109 | + output_directory = tmp_path_factory.mktemp("output") |
| 110 | + working_directory = shutil.copytree( |
| 111 | + resource_directory, temp_directory / "test_test_container_reuse" |
| 112 | + ) |
| 113 | + docker_repository_name = "test_test_container_reuse" |
| 114 | + luigi_utils.clean(docker_repository_name) |
| 115 | + _setup_luigi_config( |
| 116 | + output_directory=output_directory, docker_repository_name=docker_repository_name |
| 117 | + ) |
| 118 | + yield working_directory |
| 119 | + luigi_utils.clean(docker_repository_name) |
| 120 | + |
| 121 | + |
| 122 | +def _dockerfile(working_directory: Path): |
| 123 | + return working_directory / "tests" / "Dockerfile" |
| 124 | + |
| 125 | + |
| 126 | +def _get_test_container_content( |
| 127 | + working_directory: Path, |
| 128 | +) -> TestContainerContentDescription: |
| 129 | + return TestContainerContentDescription( |
| 130 | + docker_file=str(_dockerfile(working_directory)), |
| 131 | + build_files_and_directories=[], |
| 132 | + runtime_mappings=[], |
| 133 | + ) |
| 134 | + |
| 135 | + |
| 136 | +def run1(working_directory: Path): |
| 137 | + task = generate_root_task( |
| 138 | + task_class=TestTask, |
| 139 | + reuse=False, |
| 140 | + attempt=1, |
| 141 | + test_container_content=_get_test_container_content(working_directory), |
| 142 | + ) |
| 143 | + try: |
| 144 | + success = luigi.build([task], workers=1, local_scheduler=True, log_level="INFO") |
| 145 | + if success: |
| 146 | + result = task.get_result() |
| 147 | + task.cleanup(True) |
| 148 | + return result |
| 149 | + else: |
| 150 | + raise Exception("Task failed") |
| 151 | + except Exception as e: |
| 152 | + task.cleanup(False) |
| 153 | + raise RuntimeError("Error spawning test environment") from e |
| 154 | + |
| 155 | + |
| 156 | +def run2(working_directory: Path): |
| 157 | + task = generate_root_task( |
| 158 | + task_class=TestTask, |
| 159 | + reuse=True, |
| 160 | + attempt=2, |
| 161 | + test_container_content=_get_test_container_content(working_directory), |
| 162 | + ) |
| 163 | + try: |
| 164 | + success = luigi.build([task], workers=1, local_scheduler=True, log_level="INFO") |
| 165 | + |
| 166 | + if success: |
| 167 | + return task.get_result() |
| 168 | + else: |
| 169 | + raise Exception("Task failed") |
| 170 | + except Exception as e: |
| 171 | + task.cleanup(False) |
| 172 | + raise RuntimeError("Error spawning test environment") from e |
| 173 | + |
| 174 | + |
| 175 | +def test_test_container_no_reuse_after_change(working_directory): |
| 176 | + p1 = run1(working_directory) |
| 177 | + with _dockerfile(working_directory).open("a") as f: |
| 178 | + f.write("\n#Test\n") |
| 179 | + p2 = run2(working_directory) |
| 180 | + assert "container_id" in p1 |
| 181 | + assert "image_id" in p1 |
| 182 | + assert "container_id" in p2 |
| 183 | + assert "image_id" in p2 |
| 184 | + print(p1) |
| 185 | + print(p2) |
| 186 | + assert p1 != p2 |
| 187 | + |
| 188 | + |
| 189 | +def test_test_container_reuse(working_directory): |
| 190 | + p1 = run1(working_directory) |
| 191 | + p2 = run2(working_directory) |
| 192 | + assert "container_id" in p1 |
| 193 | + assert "image_id" in p1 |
| 194 | + print(p1) |
| 195 | + print(p2) |
| 196 | + assert p1 == p2 |
0 commit comments