Skip to content

Commit a713c62

Browse files
bgagentclaude
andcommitted
test(linear): address PR #87 re-review nice-to-have items
- test_config: cover the BotoCoreError branch of `resolve_linear_api_token` with an `EndpointConnectionError` case. The PR-#87 split into ClientError + BotoCoreError branches previously had no test on the BotoCoreError path. - test_linear_reactions: new `test_sweep_preserves_just_posted_eyes_via_exclude_id` exercises the `exclude_id` filter — the existing sweep test never collided prior reaction ids with the newly posted one, so the branch was effectively dead code in tests. The new test plants the just- posted 👀 in the prior reactions list and asserts it survives the sweep while an older ❌ is deleted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f4633be commit a713c62

2 files changed

Lines changed: 52 additions & 0 deletions

File tree

agent/tests/test_config.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,22 @@ def test_other_client_error_logged_at_warn(self, monkeypatch):
156156
assert resolve_linear_api_token() == ""
157157
assert mock_log.call_count == 1
158158
assert mock_log.call_args[0][0] == "WARN"
159+
160+
def test_botocore_error_logged_at_warn(self, monkeypatch):
161+
"""The handler is split into ClientError + BotoCoreError branches.
162+
BotoCoreError covers transient connectivity / endpoint problems —
163+
log WARN and degrade gracefully rather than crashing the agent."""
164+
monkeypatch.delenv("LINEAR_API_TOKEN", raising=False)
165+
monkeypatch.setenv("LINEAR_API_TOKEN_SECRET_ARN", "arn:aws:sm:::secret/linear")
166+
167+
from botocore.exceptions import EndpointConnectionError
168+
169+
fake_client = MagicMock()
170+
fake_client.get_secret_value.side_effect = EndpointConnectionError(
171+
endpoint_url="https://secretsmanager.us-east-1.amazonaws.com",
172+
)
173+
with patch("boto3.client", return_value=fake_client), patch("config.log") as mock_log:
174+
assert resolve_linear_api_token() == ""
175+
assert mock_log.call_count == 1
176+
assert mock_log.call_args[0][0] == "WARN"
177+
assert "EndpointConnectionError" in mock_log.call_args[0][1]

agent/tests/test_linear_reactions.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,39 @@ def test_viewer_id_cached_across_calls(self, monkeypatch):
378378
# Only one viewer query across both calls.
379379
assert sum("Viewer" in q for q in queries) == 1
380380

381+
def test_sweep_preserves_just_posted_eyes_via_exclude_id(self, monkeypatch):
382+
"""If Linear's reactions query happens to return our just-posted 👀
383+
(e.g. on a tight retry where the prior run's reaction id was reused
384+
by Linear), the sweep MUST NOT delete it — exclude_id is what keeps
385+
the new marker safe. Tests would otherwise pass with exclude_id=None
386+
because the prior reaction ids never collide with the new one."""
387+
monkeypatch.setenv("LINEAR_API_TOKEN", "lin_api_test")
388+
new_rid = "r-new-eyes"
389+
prior_reactions = [
390+
# The just-posted 👀 — sweep must SKIP this one.
391+
{"id": new_rid, "emoji": EMOJI_STARTED, "user": {"id": "viewer-bot"}},
392+
# An older bgagent ❌ from a prior run — sweep MUST delete this.
393+
{"id": "r-old-x", "emoji": EMOJI_FAILURE, "user": {"id": "viewer-bot"}},
394+
]
395+
with patch(
396+
"linear_reactions.requests.post",
397+
side_effect=[
398+
_ok_response(reaction_id=new_rid),
399+
_viewer_response("viewer-bot"),
400+
_reactions_response(prior_reactions),
401+
_ok_delete_response(), # only one delete expected
402+
],
403+
) as post:
404+
react_task_started("linear", {"linear_issue_id": "issue-1"})
405+
_join_sweep_thread()
406+
delete_ids = [
407+
call.kwargs["json"]["variables"]["id"]
408+
for call in post.call_args_list
409+
if "reactionDelete" in call.kwargs["json"]["query"]
410+
]
411+
# The new 👀 must NOT be deleted; only the old ❌ should be.
412+
assert delete_ids == ["r-old-x"]
413+
381414

382415
class TestAuthCircuitBreaker:
383416
"""The circuit breaker in `_graphql` flips open after

0 commit comments

Comments
 (0)