diff --git a/.gemini/skills/testing-workflow/SKILL.md b/.gemini/skills/testing-workflow/SKILL.md index 52cd04c2..a81c8bb4 100644 --- a/.gemini/skills/testing-workflow/SKILL.md +++ b/.gemini/skills/testing-workflow/SKILL.md @@ -1,26 +1,28 @@ --- name: testing-workflow -description: Guide for running tests within the NetAlertX environment. Detailed instructions for standard unit tests (fast), full suites (slow), and handling authentication. +description: Read before running tests. Detailed instructions for single, astandard unit tests (fast), full suites (slow), and handling authentication. Tests must be run when a job is complete. --- # Testing Workflow +After code is developed, tests must be run to ensure the integrity of the final result. **Crucial:** Tests MUST be run inside the container to access the correct runtime environment (DB, Config, Dependencies). -## 1. Standard Unit Tests (Recommended) -By default, run the standard unit test suite. This **excludes** slow tests marked with `docker` (requires socket access) or `feature_complete` (extended coverage). +## 1. Full Test Suite (MANDATORY DEFAULT) + +Unless the user **explicitly** requests "fast" or "quick" tests, you **MUST** run the full test suite. **Do not** optimize for time. Comprehensive coverage is the priority over speed. ```bash -docker exec bash -c "cd /workspaces/NetAlertX && pytest -m 'not docker and not feature_complete'" +cd /workspaces/NetAlertX; pytest test/ ``` -## 2. Full Test Suite (Slow) +## 2. Fast Unit Tests (Conditional) -To run **all** tests, including integration tests that require Docker socket access and extended feature coverage: +**ONLY** use this if the user explicitly asks for "fast tests", "quick tests", or "unit tests only". This **excludes** slow tests marked with `docker` or `feature_complete`. ```bash -docker exec bash -c "cd /workspaces/NetAlertX && pytest" +cd /workspaces/NetAlertX; pytest test/ -m 'not docker and not feature_complete' ``` ## 3. Running Specific Tests @@ -28,12 +30,12 @@ docker exec bash -c "cd /workspaces/NetAlertX && pytest" To run a specific file or folder: ```bash -docker exec bash -c "cd /workspaces/NetAlertX && pytest " +cd /workspaces/NetAlertX; pytest test/ ``` *Example:* ```bash -docker exec bash -c "cd /workspaces/NetAlertX && pytest test/api_endpoints/test_mcp_extended_endpoints.py" +cd /workspaces/NetAlertX; pytest test/api_endpoints/test_mcp_extended_endpoints.py ``` ## Authentication in Tests @@ -41,12 +43,12 @@ docker exec bash -c "cd /workspaces/NetAlertX && pytest test/api_ The test environment uses `API_TOKEN`. The most reliable way to retrieve the current token from a running container is: ```bash -docker exec python3 -c "from helper import get_setting_value; print(get_setting_value('API_TOKEN'))" +python3 -c "from helper import get_setting_value; print(get_setting_value('API_TOKEN'))" ``` ### Troubleshooting If tests fail with 403 Forbidden or empty tokens: 1. Verify server is running and use the setup script (`/workspaces/NetAlertX/.devcontainer/scripts/setup.sh`) if required. -2. Verify `app.conf` inside the container: `docker exec cat /data/config/app.conf` -3. Verify Python can read it: `docker exec python3 -c "from helper import get_setting_value; print(get_setting_value('API_TOKEN'))"` \ No newline at end of file +2. Verify `app.conf` inside the container: `cat /data/config/app.conf` +3. Verify Python can read it: `python3 -c "from helper import get_setting_value; print(get_setting_value('API_TOKEN'))"` \ No newline at end of file diff --git a/test/docker_tests/test_container_environment.py b/test/docker_tests/test_container_environment.py index 906c4951..1ca1eb01 100644 --- a/test/docker_tests/test_container_environment.py +++ b/test/docker_tests/test_container_environment.py @@ -945,14 +945,14 @@ def test_missing_app_conf_triggers_seed(tmp_path: pathlib.Path) -> None: "docker", "run", "--rm", "-v", f"{vol}:/data", "alpine:3.22", "cat", "/data/config/app.conf" ], - capture_output=True, text=True + capture_output=True, text=True, timeout=SUBPROCESS_TIMEOUT_SECONDS ) - if check_conf.returncode == 0: - match = re.search(r"SCAN_SUBNETS\s*=\s*(.*)", check_conf.stdout) - if match: - val = match.group(1) - assert "interface=" in val, f"SCAN_SUBNETS should have interface: {val}" - assert val != "['--localnet']", "SCAN_SUBNETS should not be default localnet" + assert check_conf.returncode == 0, f"Failed to read config. Stderr: {check_conf.stderr}, Stdout: {check_conf.stdout}" + match = re.search(r"SCAN_SUBNETS\s*=\s*(.*)", check_conf.stdout) + if match: + val = match.group(1) + assert "interface=" in val, f"SCAN_SUBNETS should have interface: {val}" + assert val != "['--localnet']", "SCAN_SUBNETS should not be default localnet" finally: _docker_volume_rm(vol) @@ -962,7 +962,6 @@ def test_missing_app_conf_triggers_seed(tmp_path: pathlib.Path) -> None: # test passes if the config file was created. Full startup success is tested elsewhere. - def test_first_run_dynamic_subnet(tmp_path: pathlib.Path) -> None: """Test dynamic subnet detection during first run config generation. @@ -972,11 +971,13 @@ def test_first_run_dynamic_subnet(tmp_path: pathlib.Path) -> None: paths = _setup_mount_tree(tmp_path, "dynamic_subnet", seed_config=False) mount_args = _build_volume_args_for_keys(paths, CONTAINER_TARGETS.keys()) - _run_container( + result_container = _run_container( "dyn-subnet", volumes=mount_args, sleep_seconds=15, + user="0:0", ) + assert result_container.returncode == 0, f"Container failed: {result_container.output}" # Use docker to read the file to avoid permission issues (file is 600 root:root) # paths["app_config"] is the host absolute path @@ -986,10 +987,10 @@ def test_first_run_dynamic_subnet(tmp_path: pathlib.Path) -> None: "alpine:3.22", "cat", "/mnt/app.conf" ] - result = subprocess.run(cmd, capture_output=True, text=True) - - assert result.returncode == 0, f"Could not read app.conf. Stderr: {result.stderr}" - content = result.stdout + read_result = subprocess.run(cmd, capture_output=True, text=True, timeout=SUBPROCESS_TIMEOUT_SECONDS) + + assert read_result.returncode == 0, f"Could not read app.conf. Stderr: {read_result.stderr}, Stdout: {read_result.stdout}" + content = read_result.stdout # Check that SCAN_SUBNETS was set to something other than the default fallback # The default fallback in the script is ['--localnet'] if no interfaces found.