* tests: enable flake8-pytest-style (PT) ruff rules
Enable the `PT` ruff rule set and fix the resulting violations across the
test suite:
- PT006: pass parametrize argument names as tuples instead of a single
comma-separated string.
- PT022: switch fixtures that have no teardown from `yield` to `return`
so the lack of cleanup is obvious at a glance.
- PT011: add `match=` to broad `pytest.raises(ValueError)` blocks so the
expected error is anchored to a specific message.
- PT012: hoist setup (patches, branching) out of `pytest.raises()`
blocks so only the call that is expected to raise remains inside.
- PT013: replace `from pytest import X` with `import pytest` and access
attributes via the module.
- PT015: replace `try/except` + `assert False` patterns with
`pytest.raises(...)`.
- PT017: replace `assert` on exceptions inside `except` blocks with
`pytest.raises(...) as exc_info` and assert on `exc_info.value`.
No behavioral changes to the tests; the full suite still passes.
* tests: address review feedback on PT ruff rule enablement
- Fix fixture return-type annotations after switching `yield` to `return`
in tests/conftest.py: drop the `Generator[...]`/`AsyncGenerator[...]`
wrapper for `dns_manager_service`, `supervisor_internet`, `websession`,
and `mock_update_data` so the annotation matches what the fixture
actually returns.
- Correct the return-type annotation of `fixture_ip6config_service` from
`IP4ConfigService` to `IP6ConfigService`.
- Fix recurring "excepiton" typo in tests/utils/test_exception_helper.py.
* tests: verify backup cleanup on permission error
After `test_new_backup_permission_error` raises `BackupPermissionError`,
assert that no tarfile was left behind and `tmp_path` is empty. The
previous version only checked that the exception was raised, which
missed any regression where a partial tarfile would survive the failed
create.
* tests: rename DNS_GOOD_V6 to DNS_V6_UNSUPPORTED
The constant was named "good" but its tests assert that the URLs are
rejected by the DNS validator. The IPv6 URLs are well-formed but
currently rejected because IPv6 doesn't work with the Docker network
(see `dns_url` in supervisor/validate.py). Rename the constant and the
related test to make the intent obvious.
* apps: log container exit code when app exits non-zero
Issue #6840 reports that stopping an app whose process exits 143 (SIGTERM
default disposition) leaves the app in AppState.ERROR. ERROR is the right
state for that — Docker itself treats any non-zero exit as a failure
(e.g. `--restart on-failure`), and 143 specifically means the SIGTERM
grace period was wasted because the app never installed a handler. But
Supervisor previously logged nothing about it, leaving authors with no
hint that their image is misbehaving.
Plumb the exit code through DockerContainerStateEvent and log it from
App.container_state_changed on transitions to FAILED: a warning for 143
nudging the author to trap SIGTERM and exit 0, and an error for any
other non-zero code (crashes, SIGKILL after grace, app's own error
exit).
Refactor _container_state_from_model to return (state, exit_code) so
the docker event monitor and DockerInterface.attach feed the same exit
code through one code path instead of re-reading State.ExitCode in the
caller.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* apps: address review feedback on exit-code logging
- Replace bare 143 with EXIT_CODE_SIGTERM_DEFAULT (128 + signal.SIGTERM)
in supervisor/docker/const.py so the reasoning is documented in code,
not just in the log string.
- Stop populating exit_code on STOPPED transitions. Previously the
refactor made DockerInterface.attach emit exit_code=0 for cleanly
stopped containers, while the monitor only emitted an exit code for
abnormal exits. Align both paths so exit_code is only set on FAILED.
- Add test_app_failed_logs_exit_code covering the three new branches
(warning on 143, error on other non-zero, silent when None) and
extend test_attach_existing_container to assert the event's exit_code
field per state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docker/monitor: flatten exit_code branch to satisfy pylint
The previous if/else inside the `die` branch pushed the function over
pylint's too-many-nested-blocks threshold (6/5). Collapse it back into
a pair of conditional expressions: container_state via ternary on the
exit code, exit_code via `die_exit_code or None` so 0 stays None.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Update supervisor/apps/app.py
Co-authored-by: Mike Degatano <michael.degatano@gmail.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Mike Degatano <michael.degatano@gmail.com>
* Migrate info and events to aiodocker
* Migrate container logs to aiodocker
* Fix dns plugin loop test
* Fix mocking for docker info
* Fixes from feedback
* Harden monitor error handling
* Deleted failing tests because they were not useful
* Migrate all docker container interactions to aiodocker
* Remove containers_legacy since its no longer used
* Add back remove color logic
* Revert accidental invert of conditional in setup_network
* Fix typos found by copilot
* Apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Revert "Apply suggestions from code review"
This reverts commit 0a475433ea.
---------
Co-authored-by: Stefan Agner <stefan@agner.ch>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Docker events based watchdog
* Separate monitor from DockerAPI since it needs coresys
* Move monitor into dockerAPI
* Fix properties on coresys
* Add watchdog tests
* Added tests
* pylint issue
* Current state failures test
* Thread-safe event processing
* Use labels property