Fixes all seven bugs that the test audit (#66) pinned with KNOWN BUG docstrings. Each pinned test now asserts the fixed behaviour instead of the defect.
#
Bug
Fix
1
qbit-maid.py read ignored_tags from config["ignored_domains"], so the [ignored_tags] section was dead
read config["ignored_tags"]
2
is_ignored_tag matched substrings, so ipt matched iptorrents and save matched unsaved
split the comma-separated tag string and compare whole tags
3
the login-error path called pushover.send_message(), which does not exist, so an auth failure raised AttributeError instead of notifying
new tor_notify_error() sends through the Pushover client built by tor_notify(); logs only when pushover is off, and never lets a notification failure abort the run
4
list_first_tor indexed torrent_list[0] unconditionally, so zero torrents aborted the run before any summary
return early on an empty list
5
build_tor_list tagged blank-tag torrents twice (once in the blank-tag block, again in the tracker branch)
new torrent_tag_for() helper; one tagging pass, then sorting only
6
AppriseClient.__init__ had a bare except: that swallowed the DOCKERKeyError and skipped the rest of the block, so toml_path was ignored unless DOCKER was set
plain os.environ.get() guards
7
setup_logging removed old handlers without closing them, leaking a file descriptor per call
handler.close() after removeHandler()
Also adds the missing [telemetry] section to config.toml.example — qbit-maid.py requires config["telemetry"]["enable_telemetry"], so a config copied from the example crashed with KeyError on startup.
Verification
140 unit tests + 15 test_komodo_deploy pass.
Coverage still 100% on all five first-party modules (453 stmts, 0 miss).
Mutation check: reverting each of the seven fixes in a scratch copy makes the suite fail (7/7 caught).
Each fix also verified directly against the real code paths (config load, tag matching, error notification, empty list, single tagging call, toml_path without DOCKER, closed handler stream).
Merge order
Stacked on #66 (dev-test-suite-audit) because the pinned tests live there. Merge #66 first, then retarget this PR to main.
Not changed
qprocess.py still uses substring matching for the app's own ipt/public tags (is_protected_under_ratio, is_not_protected_tor). Those tags are written by qbit-maid itself, so a collision is unlikely; left alone to keep this change targeted.
Fixes all seven bugs that the test audit (#66) pinned with `KNOWN BUG` docstrings. Each pinned test now asserts the fixed behaviour instead of the defect.
| # | Bug | Fix |
|---|-----|-----|
| 1 | `qbit-maid.py` read `ignored_tags` from `config["ignored_domains"]`, so the `[ignored_tags]` section was dead | read `config["ignored_tags"]` |
| 2 | `is_ignored_tag` matched substrings, so `ipt` matched `iptorrents` and `save` matched `unsaved` | split the comma-separated tag string and compare whole tags |
| 3 | the login-error path called `pushover.send_message()`, which does not exist, so an auth failure raised `AttributeError` instead of notifying | new `tor_notify_error()` sends through the `Pushover` client built by `tor_notify()`; logs only when pushover is off, and never lets a notification failure abort the run |
| 4 | `list_first_tor` indexed `torrent_list[0]` unconditionally, so zero torrents aborted the run before any summary | return early on an empty list |
| 5 | `build_tor_list` tagged blank-tag torrents twice (once in the blank-tag block, again in the tracker branch) | new `torrent_tag_for()` helper; one tagging pass, then sorting only |
| 6 | `AppriseClient.__init__` had a bare `except:` that swallowed the `DOCKER` `KeyError` and skipped the rest of the block, so `toml_path` was ignored unless `DOCKER` was set | plain `os.environ.get()` guards |
| 7 | `setup_logging` removed old handlers without closing them, leaking a file descriptor per call | `handler.close()` after `removeHandler()` |
Also adds the missing `[telemetry]` section to `config.toml.example` — `qbit-maid.py` requires `config["telemetry"]["enable_telemetry"]`, so a config copied from the example crashed with `KeyError` on startup.
### Verification
- 140 unit tests + 15 `test_komodo_deploy` pass.
- Coverage still 100% on all five first-party modules (453 stmts, 0 miss).
- Mutation check: reverting each of the seven fixes in a scratch copy makes the suite fail (7/7 caught).
- Each fix also verified directly against the real code paths (config load, tag matching, error notification, empty list, single tagging call, `toml_path` without `DOCKER`, closed handler stream).
### Merge order
Stacked on #66 (`dev-test-suite-audit`) because the pinned tests live there. Merge #66 first, then retarget this PR to `main`.
### Not changed
`qprocess.py` still uses substring matching for the app's own `ipt`/`public` tags (`is_protected_under_ratio`, `is_not_protected_tor`). Those tags are written by qbit-maid itself, so a collision is unlikely; left alone to keep this change targeted.
trexBot
changed target branch from dev-test-suite-audit to main2026-11-03 16:47:05 -06:00
- read [ignored_tags] instead of [ignored_domains], so tag-based ignoring
actually works
- match ignored tags as whole tags, not substrings ('ipt' no longer matches
'iptorrents')
- send the login-error notification through the Pushover client instead of
the non-existent module-level send_message()
- handle an empty torrent list instead of raising IndexError before any
summary is sent
- tag a new torrent once instead of once per code path
- honour toml_path without DOCKER in AppriseClient
- close replaced log handlers so the file descriptor is released
Also add the missing [telemetry] section to config.toml.example, which
qbit-maid.py requires at startup.
The tests that pinned each bug now assert the fixed behaviour, and the
suite still reports 100% coverage.
trexBot
merged commit cc2d75c777 into main2026-11-03 16:47:29 -06:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes all seven bugs that the test audit (#66) pinned with
KNOWN BUGdocstrings. Each pinned test now asserts the fixed behaviour instead of the defect.qbit-maid.pyreadignored_tagsfromconfig["ignored_domains"], so the[ignored_tags]section was deadconfig["ignored_tags"]is_ignored_tagmatched substrings, soiptmatchediptorrentsandsavematchedunsavedpushover.send_message(), which does not exist, so an auth failure raisedAttributeErrorinstead of notifyingtor_notify_error()sends through thePushoverclient built bytor_notify(); logs only when pushover is off, and never lets a notification failure abort the runlist_first_torindexedtorrent_list[0]unconditionally, so zero torrents aborted the run before any summarybuild_tor_listtagged blank-tag torrents twice (once in the blank-tag block, again in the tracker branch)torrent_tag_for()helper; one tagging pass, then sorting onlyAppriseClient.__init__had a bareexcept:that swallowed theDOCKERKeyErrorand skipped the rest of the block, sotoml_pathwas ignored unlessDOCKERwas setos.environ.get()guardssetup_loggingremoved old handlers without closing them, leaking a file descriptor per callhandler.close()afterremoveHandler()Also adds the missing
[telemetry]section toconfig.toml.example—qbit-maid.pyrequiresconfig["telemetry"]["enable_telemetry"], so a config copied from the example crashed withKeyErroron startup.Verification
test_komodo_deploypass.toml_pathwithoutDOCKER, closed handler stream).Merge order
Stacked on #66 (
dev-test-suite-audit) because the pinned tests live there. Merge #66 first, then retarget this PR tomain.Not changed
qprocess.pystill uses substring matching for the app's ownipt/publictags (is_protected_under_ratio,is_not_protected_tor). Those tags are written by qbit-maid itself, so a collision is unlikely; left alone to keep this change targeted.- read [ignored_tags] instead of [ignored_domains], so tag-based ignoring actually works - match ignored tags as whole tags, not substrings ('ipt' no longer matches 'iptorrents') - send the login-error notification through the Pushover client instead of the non-existent module-level send_message() - handle an empty torrent list instead of raising IndexError before any summary is sent - tag a new torrent once instead of once per code path - honour toml_path without DOCKER in AppriseClient - close replaced log handlers so the file descriptor is released Also add the missing [telemetry] section to config.toml.example, which qbit-maid.py requires at startup. The tests that pinned each bug now assert the fixed behaviour, and the suite still reports 100% coverage.