Skip to content

ci: give CI an oplog, so the HA tests stop being skipped in silence - #47

Merged
kzangeli merged 2 commits into
mainfrom
ci/mongo-replica-set
Sep 2, 2026
Merged

ci: give CI an oplog, so the HA tests stop being skipped in silence#47
kzangeli merged 2 commits into
mainfrom
ci/mongo-replica-set

Conversation

@kzangeli

@kzangeli kzangeli commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Depends on SEAMWARE/corLibs#6 (merged) — publishes quay.io/seamware/mongo-rs:2026-09-02-c1b6cba, verified to pull anonymously.

The problem

The HA cache sync watches a mongo change stream, a change stream reads the oplog, and a standalone mongod has none. corTestParams.sh knows this and detects it — so on a standalone, ha_cache_sync.test leaves the run set.

Not reported as skipped. Nothing in the log says the HA paths went unexercised.

Every job here has run a standalone mongo:8.0 since the workflows existed, so 108 lines and 10 functions of the broker were never entered in CI — and the nightly's published coverage figure reported them as untested code rather than as an environment nobody had stood up. Worth −0.34 pp lines, −0.73 pp functions, −0.26 pp branches against a local run (see #46).

Why an image

A services: block passes docker-create options but not a command, so --replSet cannot be added from a workflow — and the job container has mongosh but no mongod of its own to start instead. The image is mongo:8.0 with that command line and nothing else.

Why a script

Initiating the set is the consumer's job: a member is addressed by the name its clients use, which the image cannot know. Three jobs need it, and three copies of a retry loop are three copies that drift.

.github/scripts/mongo-rs-init.sh:

  • idempotent — a re-run against an already-initiated service is a no-op, not AlreadyInitialized
  • waits for a PRIMARY — initiated is not usable; a write before the election lands gets NotWritablePrimary, which the suite would read as a broker bug
  • asserts setName is rs0 — the exact probe the harness makes to decide whether the HA tests are in the run set

Verified against a local rs0 (took the already-initiated path correctly); the initiate path is exercised by corLibs#6's verify step and by this PR's own run.

In ci.yml the mongo half of "Wait for the databases" moves into the script, since initiating has to wait for mongod anyway and two waits would only disagree.

Who gets it, and who deliberately does not

Job Replica set Why
ci.yml functest matrix runs the suite
nightly coverage publishes the figure this is about
nightly valgrind runs the suite
nightly perf compares against recorded history — an oplog under every write moves the baseline, and the comparison would measure a change of database topology rather than the broker
nightly ETSI no HA test; nothing needs a change stream

Both exclusions now say so in place.

Tag hygiene

Only mongo-rs is adopted at the new tag. The same run republished coraine-ci and coraine-ci-nightly, but neither Dockerfile changed, so those stay on 2026-08-24-814ad08 / 2026-08-26-dd3bf56. Bump what changed — it does mean the workflows name two different date-shas.

Shard boundaries are left alone: one 6.4s test shifts every index after it by one, which is true of every functest ever added.

What to watch on this run

ha_cache_sync should appear in the mongoc shard that covers it, and the "Initiate the mongo replica set" step should print replica set rs0 is PRIMARY.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TGatXwrHx1CreL49sCuS37

kzangeli and others added 2 commits September 2, 2026 12:22
Both suites green on e0a5427 - 627/627 mongoc, 577/577 corDB - and every
headline number rose: 82.7% -> 82.9% lines, 95.1% -> 95.7% functions,
64.3% -> 64.6% branches on mongoc.

Almost none of that is the four new tests. It is corRest, 73.6% -> 76.5% on
lines and 85.6% -> 92.9% on functions without gaining a test of its own,
because 253 uncovered lines were DELETED from it. A rise can be dead code
removed rather than behaviour newly tested, and the headline cannot tell you
which - so the file now says so where the numbers are.

The correction that matters is the HA one. Every earlier revision described
the HA cache-sync paths as untested code "needing a replica set the harness
does not stand up". The harness stands it up perfectly well: corTestParams.sh
probes isMaster.setName, and on a replica set ha_cache_sync.test is simply in
the run set. This machine has run mongod --replSet rs0 since 2026-08-30, so
those paths are 108/149 lines and 10/10 functions covered here.

What does not stand it up is our CI, which runs a standalone mongo:8.0 - and
the nightly is what publishes the figure. So the sentence was describing our
own workflows while reading as a property of the broker. It is now a section
of its own, with what the gap costs the published number (-0.34 pp lines,
-0.73 pp functions, -0.26 pp branches) and a sixth entry in the reproduction
list. corLibs#6 is the other half of the fix.

The uncovered-line classification is redone across all FOUR repositories
rather than coraine/src alone - the file has been carrying "2732 lines in the
libs have never been classified at all" as an open item since the measurement
widened. Of 5393 uncovered lines, 154 - under 3% - are the fault-injection
cases. The largest group is ordinary behaviour nobody tested, and it is now
named with counts taken from this run rather than described in the abstract.

The never-entered bucket needs no heuristic and is exact: 59 functions, 527
lines. Two findings in it are worth acting on separately - ldDatasetIdDedup
and its four helpers (43 lines) are in corNgsild's public header and its
README with no caller anywhere in the four repos, which is the shape corRest
just deleted; ringSelfIntersects and its four (51 lines) are deliberately
parked with the reason at the call site, which is not the same thing at all.

The old hand-sampled percentages are gone rather than carried forward with a
warning. They measured a denominator that no longer exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TGatXwrHx1CreL49sCuS37
The HA cache sync watches a mongo CHANGE STREAM, a change stream reads the
oplog, and a standalone mongod has none. corTestParams.sh knows that and
detects it - so on a standalone, ha_cache_sync.test leaves the run set. Not
reported as skipped. Nothing in the log says the HA paths went unexercised.

Every job here has run a standalone mongo:8.0 since the workflows existed, so
108 lines and 10 functions of the broker were never entered in CI - and the
nightly's PUBLISHED coverage figure reported them as untested code rather than
as an environment nobody had stood up. That is worth -0.34 pp of lines,
-0.73 pp of functions and -0.26 pp of branches against a local run.

The image is quay.io/seamware/mongo-rs (corLibs c1b6cba): mongo:8.0 with
--replSet on the command line, and nothing else. It has to be an image because
a `services:` block passes docker-create OPTIONS but not a COMMAND, and the job
container has mongosh but no mongod of its own to start instead.

Initiating the set is the consumer's job - a member is addressed by the name
its CLIENTS use, which the image cannot know - so that is a script rather than
a third copy of the same retry loop. It is idempotent: a re-run against an
already-initiated service is a no-op, not AlreadyInitialized. It waits for a
PRIMARY too, because initiated is not the same as usable and a write before the
election lands gets NotWritablePrimary, which the suite would read as a broker
bug. Its last act is to assert setName is rs0 - the exact probe the harness
makes to decide whether the HA tests are in the run set.

In ci.yml the mongo half of "Wait for the databases" moves into the script,
since initiating the set has to wait for mongod anyway and two waits would only
disagree with each other.

Three jobs get it: ci.yml's functest matrix, and the nightly's coverage and
valgrind jobs. Two deliberately do NOT, and now say so in place:

  - perf compares against RECORDED HISTORY. A replica set puts every write
    through an oplog, so the baseline would move under it and the comparison
    would measure the change of database topology rather than the broker.
  - the ETSI job has no HA test, so nothing there needs a change stream.

Only mongo-rs is adopted at the new tag. The same run republished coraine-ci
and coraine-ci-nightly, but Dockerfile.ci and Dockerfile.ci-nightly did not
change, so those two stay on 2026-08-24-814ad08 / 2026-08-26-dd3bf56: bump what
changed.

The shard boundaries in ci.yml are left alone. One 6.4s test shifts every index
after it by one; that is true of every functest ever added, and recalibrating
is worth doing when the drift costs real wall-clock, not per test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TGatXwrHx1CreL49sCuS37
@read-the-docs-community

Copy link
Copy Markdown

Documentation build overview

📚 coraine | 🛠️ Build #34350625 | 📁 Comparing 3c43806 against latest (e0a5427)

  🔍 Preview build  

1 file changed
± coverage.html

@kzangeli
kzangeli merged commit b5c2a98 into main Sep 2, 2026
7 checks passed
@kzangeli
kzangeli deleted the ci/mongo-replica-set branch September 2, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant