-
Notifications
You must be signed in to change notification settings - Fork 83
feat(integration-tests): Test the startup and teardown of the clp-text and clp-json packages.
#1437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
8e75e15
44ee20e
bbe0575
5cd47f8
c5375eb
2be837f
bf14b5e
27b7f5b
e041f0e
75672fc
0822a79
2df9515
63f3ae4
0011447
0ff9465
cdcfaee
53e7343
796ffe3
bae12de
9c9ef74
0f3dcd5
f9865a8
865e9ed
09d5200
5fffc32
571f313
e348be0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| 3.9 | ||
| 3.10 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have a specific reason why we are moving to
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when I tried to run the tests the very first time, and the tests tried to start the package, I received some error message saying and I figured out that was because the package had been built/compiled for python 3.10, and the tests were using 3.9. changing to 3.10 fixed the issue. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,7 @@ readme = "README.md" | |
| authors = [ | ||
| { name = "YScope Inc.", email = "[email protected]" } | ||
| ] | ||
| requires-python = ">=3.9" | ||
| requires-python = ">=3.10" | ||
|
|
||
| [project.scripts] | ||
| integration-tests = "integration_tests:main" | ||
|
|
@@ -21,6 +21,8 @@ dev = [ | |
| "ruff>=0.11.12", | ||
| "pytest>=8.4.1", | ||
| "pytest-env>=1.1.5", | ||
| "PyYAML>=6.0", | ||
| "types-PyYAML>=6.0.12.20240808", | ||
| ] | ||
|
|
||
| [tool.mypy] | ||
|
|
@@ -46,8 +48,10 @@ ignore = [ | |
| "D400", # First line of docstrings may not end in period | ||
| "D401", # Docstrings should be written in present tense (not imperative) | ||
| "D415", # First line of docstrings may not end in a period, question mark, or exclamation point | ||
| "EM102", # Exception must not use an f-string literal, assign to variable first | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "FBT", # Allow bool positional parameters since other value positions are allowed | ||
| "FIX002", # Allow todo statements | ||
| "G004", # Logging statement uses f-string | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "PERF401", # Allow for loops when creating lists | ||
| "PERF403", # Allow for loops when creating dicts | ||
| "S311", # Allow usage of `random` package | ||
|
|
@@ -56,6 +60,7 @@ ignore = [ | |
| "SIM300", # Skip Yoda-condition format fixes | ||
| "TD002", # Author unnecessary for todo statement | ||
| "TD003", # Issue link unnecessary for todo statement | ||
| "TRY003", # Avoid specifying long messages outside the exception class | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "UP015", # Explicit open modes are helpful | ||
| ] | ||
| isort.order-by-type = false | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| """Define test packages fixtures.""" | ||
|
|
||
| import logging | ||
| import subprocess | ||
| from collections.abc import Iterator | ||
| from typing import Literal | ||
|
|
||
| import pytest | ||
|
|
||
| from tests.utils.config import ( | ||
| PackageConfig, | ||
| PackageRun, | ||
| ) | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| def clp_package( | ||
| package_config: PackageConfig, | ||
| ) -> Iterator[PackageRun]: | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """Fixture that starts up an instance of clp, and stops the package after yield.""" | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| mode: Literal["clp-text", "clp-json"] = "clp-text" | ||
| instance = _start_clp_package(package_config, mode) | ||
|
|
||
| yield instance | ||
| _stop_clp_package(instance) | ||
|
|
||
|
|
||
| def _start_clp_package( | ||
| package_config: PackageConfig, | ||
| mode: Literal["clp-text", "clp-json"], | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) -> PackageRun: | ||
| """Starts up an instance of clp.""" | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| logger.info(f"Starting up the {mode} package...") | ||
|
|
||
| start_script_path = package_config.clp_package_dir / "sbin" / "start-clp.sh" | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| try: | ||
| # fmt: off | ||
| start_cmd = [ | ||
| start_script_path | ||
| ] | ||
| # fmt: on | ||
| subprocess.run(start_cmd, check=True) | ||
| except Exception as e: | ||
| err_msg = f"Failed to start an instance of the {mode} package." | ||
| raise RuntimeError(err_msg) from e | ||
|
|
||
| package_run = PackageRun( | ||
| package_config=package_config, | ||
| mode=mode, | ||
| ) | ||
|
|
||
| logger.info( | ||
| f"An instance of the {package_run.mode} package was started successfully." | ||
| f" Its instance ID is '{package_run.clp_instance_id}'" | ||
| ) | ||
|
|
||
| return package_run | ||
|
|
||
|
|
||
| def _stop_clp_package( | ||
| instance: PackageRun, | ||
| ) -> None: | ||
| """Stops an instance of clp.""" | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| mode = instance.mode | ||
| instance_id = instance.clp_instance_id | ||
| logger.info(f"Now stopping the {mode} package with instance ID '{instance_id}'...") | ||
|
|
||
| stop_script_path = instance.package_config.clp_package_dir / "sbin" / "stop-clp.sh" | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| try: | ||
| # fmt: off | ||
| stop_cmd = [ | ||
| stop_script_path | ||
| ] | ||
| # fmt: on | ||
| subprocess.run(stop_cmd, check=True) | ||
| except Exception as e: | ||
| err_msg = f"Failed to stop an instance of the {mode} package." | ||
| raise RuntimeError(err_msg) from e | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| logger.info(f"The {mode} package with instance ID '{instance_id}' was stopped successfully.") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| """Integration tests verifying that the CLP package can be started and stopped.""" | ||
|
|
||
| import logging | ||
| import shutil | ||
| import subprocess | ||
|
|
||
| import pytest | ||
|
|
||
| from tests.utils.config import ( | ||
| PackageRun, | ||
| ) | ||
|
|
||
| pytestmark = pytest.mark.package | ||
|
|
||
|
|
||
| package_configurations = pytest.mark.parametrize( | ||
| "test_package_fixture", | ||
| [ | ||
| "clp_package", | ||
| ], | ||
| ) | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| @pytest.mark.package | ||
| @package_configurations | ||
| def test_clp_package( | ||
| request: pytest.FixtureRequest, | ||
| test_package_fixture: str, | ||
| ) -> None: | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """ | ||
| Validate that all of the components of the clp package start up successfully. The package is | ||
| started up in whatever configuration is currently described in clp-config.yml; default is | ||
| clp-text. | ||
| :param request: | ||
| :param test_package_fixture: | ||
| """ | ||
| package_run: PackageRun = request.getfixturevalue(test_package_fixture) | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| assert _is_package_running(package_run) | ||
|
|
||
|
|
||
| def _is_package_running(package_run: PackageRun) -> bool: | ||
| """Checks that the package specified in package_run is running correctly.""" | ||
| mode = package_run.mode | ||
| instance_id = package_run.clp_instance_id | ||
|
|
||
| component_basenames = [ | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "clp-database", | ||
| "clp-queue", | ||
| "clp-redis", | ||
| "clp-results_cache", | ||
| "clp-compression_scheduler", | ||
| "clp-query_scheduler", | ||
| "clp-compression_worker", | ||
| "clp-query_worker", | ||
| "clp-reducer", | ||
| "clp-webui", | ||
| "clp-garbage_collector", | ||
| ] | ||
|
|
||
| logger.info( | ||
| "Checking if all components of %s package with instance ID '%s' are running properly.", | ||
| mode, | ||
| instance_id, | ||
| ) | ||
|
|
||
| docker_bin = shutil.which("docker") | ||
| if docker_bin is None: | ||
| error_msg = "docker not found in PATH" | ||
| raise RuntimeError(error_msg) | ||
|
|
||
| for component in component_basenames: | ||
| name = f"{component}-{instance_id}" | ||
|
|
||
| proc = subprocess.run( | ||
| [docker_bin, "inspect", "-f", "{{.State.Running}}", name], | ||
quinntaylormitchell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| capture_output=True, | ||
| text=True, | ||
| check=False, | ||
| ) | ||
|
|
||
| if proc.returncode != 0: | ||
| err = (proc.stderr or proc.stdout or "").strip() | ||
| if "No such object" in err: | ||
| logger.error("Component container not found: %s", name) | ||
| return False | ||
| error_msg = f"Error inspecting container {name}: {err}" | ||
| raise RuntimeError(error_msg) | ||
|
|
||
| status = (proc.stdout or "").strip().lower() | ||
| if status != "true": | ||
| logger.error("Component container not running: %s (status=%s)", name, status) | ||
| return False | ||
|
|
||
| logger.info( | ||
| "All components of the %s package with instance ID '%s' are running properly.", | ||
| mode, | ||
| instance_id, | ||
| ) | ||
| return True | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious. Are there tests that will result in status other than the default pass/fail?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so; I just added this so that there is a test summary that shows up when all the tests that the user requested have finished running. is there a better way to do that?