Task · SFL-0031

tests: the CLI backfill success path is entirely uncovered - org identity and argument wiring can regress silently

Status
To Do
Labels
followup, phase-3
Milestone
Test-coverage backlog
Updated
2026-08-14

Description

What

The success path of the sf2loki backfill subcommand in src/sf2loki/cli.py has zero test coverage. Full-suite coverage confirms it:

$ uv run --with pytest-cov pytest tests/ --cov=sf2loki.cli --cov-report=term-missing -q
Name                 Stmts   Miss  Cover   Missing
--------------------------------------------------
src/sf2loki/cli.py      98     16    84%   24-25, 198-200, 210-218, 222-229, 263, 269-270
1045 passed, 1 skipped

(pytest-cov is not a dev dependency; the --with pytest-cov form above reproduces the numbers without changing the lockfile.)

The uncovered region cli.py:210-241 is everything the CLI does after a successful config load:

The only CLI-level backfill invocation in the suite is tests/test_cli.py:304, inside test_check_and_run_and_backfill_share_one_config_error_exit_code. That test’s config sets private_key_file: /does/not/exist.pem, so load() at cli.py:209 raises ConfigError from _resolve_salesforce_secrets (config.py:1514-1521) and only the except arm at cli.py:219-221 executes. It asserts an exit code, nothing else.

run_backfill’s own org semantics are pinned, but only with literal arguments handed in by the test: tests/test_backfill.py:949-959 (org_name="orgA", legacy_fallback=True), tests/test_backfill.py:966-976 (org_name="orgB", legacy_fallback=False), tests/test_backfill.py:1011-1021. Those tests are indifferent to how the CLI computes those values.

An extra, invisible constraint lives in the ordering. as_single_org_view (config.py:1466-1474) copies with update={"salesforce": ..., "sources": ..., "orgs": []}, so after cli.py:218 the config’s resolved_orgs() returns one org whose name is "" — the org identity is unrecoverable. The derivation at cli.py:215-217 therefore must run before line 218, and the comment at cli.py:211-214 says so, but no test enforces it.

Why it matters

Every mutation in this region ships green:

The failure mode is silent in production: the backfill exits 0 and reports success while writing less history than requested. This is a multi-org data-loss class that has already shipped once (#40).

Proposed approach

Add CLI-level tests to tests/test_cli.py that monkeypatch sf2loki.backfill.run_backfill with a recorder coroutine and assert the derived arguments. This works because cli.py:203 imports run_backfill at call time inside main, so patching the module attribute before invoking main is intercepted (verified: main([...]) returned 0 with the recorder capturing org_name="emea", legacy_fallback=False, event_types=["a", "b"] from --event-types "a, b,").

Add a _valid_multi_org_config(tmp_path) helper alongside the existing _valid_config (tests/test_cli.py:12-30), writing a two-org YAML (verified to load):

orgs:
  - name: prod
    salesforce:
      client_id: cid
      username: svc@example.com
      private_key_file: <tmp key.pem>
    sources:
      pubsub:
        enabled: false
  - name: emea
    salesforce:
      client_id: cid2
      username: svc2@example.com
      private_key_file: <tmp key.pem>
    sources:
      pubsub:
        enabled: false
sink:
  loki:
    url: http://loki:3100/loki/api/v1/push

Recorder shape:

captured: dict[str, object] = {}

async def _recorder(cfg, **kwargs):
    captured["cfg"] = cfg
    captured.update(kwargs)
    return 0

monkeypatch.setattr("sf2loki.backfill.run_backfill", _recorder)

Assert on captured after main([...]) returns 0. The single-org case reuses _valid_config and expects org_name == "".


Imported from GitHub issue #115 on 2026-08-14, when this repo migrated from GitHub Issues to Backlog.md. The original issue has been deleted; its verbatim body, labels and comments are preserved in archive/issues-dump.json (jq '.[] | select(.number == 115)' archive/issues-dump.json).

Filed from the 2026-07-30 full-repo audit (11 finder lanes + adversarial verification per finding).

Acceptance Criteria

Definition of Done

References

View the source file on GitHub