testing-workflow
GitHub提供在 devcontainer 中运行测试的完整工作流,涵盖环境检查、全量/快速测试执行、特定用例调试、API Token 获取及跨测试污染排查,确保测试环境正确与结果可靠。
Trigger Scenarios
Install
npx skills add netalertx/NetAlertX --skill testing-workflow -g -y
SKILL.md
Frontmatter
{
"name": "testing-workflow",
"description": "Read before running tests. Detailed instructions for single tests, full suites, authentication, obtaining the API Token, and a real cross-test pollution pitfall. Use this when asked to run tests, check failures, or debug failing tests."
}
Testing Workflow
Crucial: Tests MUST be run inside the devcontainer to access the correct runtime environment (DB, config, dependencies).
0. Pre-requisites: Environment Check
Before running any tests, verify you are inside the development container:
ls -d /workspaces/NetAlertX
If this directory does not exist, you are likely on the host machine — load the devcontainer-management skill (or its .github/.gemini equivalents) to enter the container or run commands inside it.
1. Check for Pre-Existing Failures First
Before attributing any failure to your own changes, see what was already broken:
cd /workspaces/NetAlertX; pytest test/ --tb=no -q 2>&1 | tail -20
Do not fix pre-existing failures unless that is the explicit goal.
2. Full Test Suite (default)
Unless the user explicitly asks for "fast"/"quick" tests, run the full suite. Don't optimize for time — comprehensive coverage is the priority.
cd /workspaces/NetAlertX; pytest test/
3. Fast Unit Tests (only when explicitly requested)
Excludes tests marked docker or feature_complete:
cd /workspaces/NetAlertX; pytest test/ -m 'not docker and not feature_complete'
4. Running Specific Tests
cd /workspaces/NetAlertX; pytest test/<path_to_test>
# e.g. pytest test/api_endpoints/test_mcp_extended_endpoints.py
# or a single test: pytest test/plugins/test_adguard_export.py::TestManagedNames::test_round_trip
PYTHONPATH
Pre-configured with:
/app— primary location where Python runs in production/app/server,/app/server/plugins— symlinks to/workspaces/NetAlertX/server[/plugins]/opt/venv/lib/pythonX.Y/site-packages,/usr/lib/pythonX.Y/site-packages/workspaces/NetAlertX,/workspaces/NetAlertX/server,/workspaces/NetAlertX/test
Authentication & Environment Reset
After making code changes, reset the environment to pick up the new code and get a fresh API_TOKEN:
bash /workspaces/NetAlertX/.devcontainer/scripts/setup.sh
sleep 5 # let nginx/python server/etc. stabilize
python3 -c "from helper import get_setting_value; print(get_setting_value('API_TOKEN'))"
Use the retrieved token for any subsequent authenticated API/test calls.
Troubleshooting 403 Forbidden / empty token
- Confirm the server is running; re-run
setup.shif needed. - Verify config loaded:
cat /data/config/app.conf, orget_setting_value("API_TOKEN")returns non-empty.
Docker Test Image
If the Dockerfile or dependencies changed, rebuild before running tests:
docker buildx build -t netalertx-test .
~30 seconds normally, ~90 seconds if the venv stage changed.
Pitfall: sys.modules Stubbing Leaks Across Test Files
Some plugin tests (e.g. test/plugins/test_ntfy_custom_headers.py) stub NetAlertX
modules (conf, helper, models.notification_instance, etc.) via
sys.modules[name] = fake_module so the plugin script can be imported standalone,
outside the container. Because sys.modules is a single process-wide cache shared
by the whole pytest session, a fake module inserted by one test file silently
shadows the real module for every other test file collected afterwards — pytest
imports all test files during collection, before any test runs, so this can happen
regardless of alphabetical/directory order.
Symptom: AttributeError: <module 'models.notification_instance'> does not have the attribute 'get_setting_value' (or similar) in an unrelated test file, where
the module repr has no from '<path>' suffix — a giveaway that a stub, not the
real module, was resolved.
Fix pattern: track which module names your stub actually inserted, and pop them
back out of sys.modules immediately after the one-time import that needed them
(the already-imported script keeps its bound names regardless):
_stubbed_module_names = []
def _stub(name, **attrs):
if name not in sys.modules:
mod = types.ModuleType(name)
for k, v in attrs.items():
setattr(mod, k, v)
sys.modules[name] = mod
_stubbed_module_names.append(name)
# ... _stub(...) calls, then the one-time import ...
import ntfy
for _name in _stubbed_module_names:
sys.modules.pop(_name, None)
Reproduce cross-file pollution locally by running the suspect file together with the affected one in a single pytest invocation (order matters less than you'd think — collection happens for all files first):
pytest test/plugins/test_ntfy_custom_headers.py test/backend/test_notification_templates.py -v
Version History
- a686a01 Current 2026-09-03 06:46


