Each removed test either asserts nothing reachable or repeats another test's exact body: - auxiliary_client empty-base_url: body only writes config.yaml; a merge (890bbbda1f) restored the header of a testb3d4f67b20had purged. The non-Anthropic-host test beside it drives the same default fallback. - background_review no-session-db: _record_review_usage_to_parent swallows every exception and there is no DB to observe, so removing the guard still passes; the path has no observable effect to pin. - code_execution Windows "would have failed" pair: every branch returns, skips or passes; they exercise CPython defaults, not Hermes code. - cron test_should_use_direct_api_call_*: byte-identical copy of the test in tests/agent/test_cron_inline_api_call.py (0213b8b77bhad to edit both). - cron liveness no-multiplexer: identical body to test_no_lock_no_pids_is_false; its multiplexer patch is never reached. - browser console/get_images "private URLs allowed": identical to the local-backend test in each file; both mock the predicate the name promises. - hermes_state TestTitleUniqueness: the duplicate-title case is a strict subset of TestSessionTitleLineage::test_unrelated_session_still_conflicts; the NULL-title case never writes a title.
150 lines
4.7 KiB
Python
150 lines
4.7 KiB
Python
"""Background-review usage attribution (issue #87250).
|
||
|
||
Background-review forks run with ``_session_db = None`` (persistence
|
||
isolation), so their provider-billed API calls were never recorded in
|
||
``session_model_usage``. ``_record_review_usage_to_parent`` closes that gap
|
||
by snapshotting the fork's in-memory counters and recording them against the
|
||
parent session via the aux-accounting chokepoint.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import logging
|
||
from unittest.mock import patch
|
||
|
||
import pytest
|
||
|
||
from agent import background_review
|
||
from hermes_state import SessionDB
|
||
|
||
@pytest.fixture
|
||
def db(tmp_path):
|
||
return SessionDB(tmp_path / "state.db")
|
||
|
||
def _usage_rows(db, session_id):
|
||
with db._lock:
|
||
rows = db._conn.execute(
|
||
"SELECT * FROM session_model_usage WHERE session_id = ? ORDER BY task",
|
||
(session_id,),
|
||
).fetchall()
|
||
return [dict(r) for r in rows]
|
||
|
||
class _FakeParent:
|
||
def __init__(self, session_db, session_id="sess-parent"):
|
||
self._session_db = session_db
|
||
self.session_id = session_id
|
||
|
||
def _usage(**overrides):
|
||
base = {
|
||
"model": "test-model",
|
||
"provider": "test-provider",
|
||
"base_url": "https://example.invalid/v1",
|
||
"input_tokens": 12000,
|
||
"output_tokens": 2400,
|
||
"cache_read_tokens": 190000,
|
||
"cache_write_tokens": 0,
|
||
"reasoning_tokens": 0,
|
||
"api_calls": 5,
|
||
"estimated_cost_usd": 0.05,
|
||
}
|
||
base.update(overrides)
|
||
return base
|
||
|
||
def test_records_fork_usage_against_parent_session(db):
|
||
db.create_session("sess-parent", source="cli")
|
||
|
||
background_review._record_review_usage_to_parent(_FakeParent(db), _usage())
|
||
|
||
rows = _usage_rows(db, "sess-parent")
|
||
assert len(rows) == 1
|
||
r = rows[0]
|
||
assert r["task"] == "background_review"
|
||
assert r["model"] == "test-model"
|
||
assert r["billing_provider"] == "test-provider"
|
||
assert r["input_tokens"] == 12000
|
||
assert r["output_tokens"] == 2400
|
||
assert r["cache_read_tokens"] == 190000
|
||
assert r["api_call_count"] == 5
|
||
assert r.get("estimated_cost_usd") == 0.05
|
||
|
||
def test_accumulates_repeated_forks_same_model(db):
|
||
db.create_session("sess-parent", source="cli")
|
||
parent = _FakeParent(db)
|
||
|
||
background_review._record_review_usage_to_parent(parent, _usage(api_calls=5))
|
||
background_review._record_review_usage_to_parent(parent, _usage(api_calls=7))
|
||
|
||
rows = _usage_rows(db, "sess-parent")
|
||
assert len(rows) == 1
|
||
assert rows[0]["input_tokens"] == 24000
|
||
assert rows[0]["api_call_count"] == 12
|
||
|
||
def test_noop_when_fork_made_no_calls(db):
|
||
db.create_session("sess-parent", source="cli")
|
||
|
||
background_review._record_review_usage_to_parent(
|
||
_FakeParent(db),
|
||
_usage(
|
||
input_tokens=0,
|
||
output_tokens=0,
|
||
cache_read_tokens=0,
|
||
cache_write_tokens=0,
|
||
reasoning_tokens=0,
|
||
api_calls=0,
|
||
),
|
||
)
|
||
|
||
assert _usage_rows(db, "sess-parent") == []
|
||
|
||
def test_noop_when_parent_has_no_session_id(db):
|
||
db.create_session("sess-parent", source="cli")
|
||
|
||
background_review._record_review_usage_to_parent(
|
||
_FakeParent(db, session_id=""), _usage()
|
||
)
|
||
|
||
assert _usage_rows(db, "sess-parent") == []
|
||
|
||
def test_survives_accounting_failure():
|
||
class _BoomDB:
|
||
def record_auxiliary_usage(self, *args, **kwargs):
|
||
raise RuntimeError("simulated accounting failure")
|
||
|
||
background_review._record_review_usage_to_parent(_FakeParent(_BoomDB()), _usage())
|
||
|
||
def test_classify_review_result():
|
||
assert background_review._classify_review_result([]) == "none"
|
||
assert background_review._classify_review_result(["Memory updated"]) == "memory"
|
||
assert background_review._classify_review_result(["Skill 'x' patched"]) == "skill"
|
||
assert (
|
||
background_review._classify_review_result(
|
||
["Memory updated", "Skill 'x' created"]
|
||
)
|
||
== "skill+memory"
|
||
)
|
||
# Prefix-based — free-text "skill"/"memory" elsewhere must not misclassify.
|
||
assert (
|
||
background_review._classify_review_result(
|
||
["Skipped: no skill worth saving"]
|
||
)
|
||
== "none"
|
||
)
|
||
assert (
|
||
background_review._classify_review_result(
|
||
["📝 Skill 'deploy' patched: \"a\" → \"b\""]
|
||
)
|
||
== "skill"
|
||
)
|
||
assert (
|
||
background_review._classify_review_result(["User profile ➕ prefers terse"])
|
||
== "memory"
|
||
)
|
||
|
||
def test_enabled_config_failure_logs_warning(caplog):
|
||
with patch(
|
||
"hermes_cli.config.load_config_readonly",
|
||
side_effect=RuntimeError("boom"),
|
||
), caplog.at_level(logging.WARNING, logger="agent.background_review"):
|
||
assert background_review.load_background_review_settings()[0] is True
|
||
assert any(r.levelno >= logging.WARNING for r in caplog.records)
|