Artifact 317abc4a120a8d09415085786b94b5ecb790d0750b121555084452b98126e64c:
- File
conformance/sync_client_cases_test.go
— part of check-in
[600861484f]
at
2026-10-13 15:55:30
on branch main
— test(conformance): re-pin the -01 drafts with the 2026-10-13 errata (#430)
* test(conformance): re-pin the -01 drafts with the 2026-10-13 errata
Re-pin the repo-state and sync-protocol drafts to zit check-in 5a1b741b25d8, which applies five more -01 errata: repo-state §5.3, §7.3 and §8.3, sync-protocol §9.4/§9.5 and §10.1. zit now keeps each -01 text under the -00 file name; the copies keep their -01 names and conformance/rfcs/README.md records the zit path and check-in. The new errata are pinned, and the requirement tables are re-read against every changed hunk.
The §7.3 and §8.3 cases that were deviations now pass as written, and new cases cover a date tag's arrival order (§5.3), untagged leaves and a merge parent's recheck (§7.3).
The sync server answers each guard-passing ci-lock with pragma avoid-delta-manifests while forbid-delta-manifests is on, defaulting to on as the draft and fossil 2.29 do (fossil 2.28 defaults it off). The client leaves its transfer unchanged on that pragma. A file or cfile whose content does not match its hash now fails the client's round, in a pull and a clone: the reply rolls back, prefix included, and no further round starts.
The leaf table is still recomputed per crosslink batch, so a parent whose untagged child arrives in a later batch loses the verdict §7.3 keeps; that case is marked as a gap, tracked in #426.
* fix(sync): continue after a uvfile content error; renumber the avoid-delta-manifests row
A uvfile whose content does not match its HASH is a handler-reported content error: warn, commit the prefix and follow ordinary continuation (sync-protocol-01 10.1). The avoid-delta-manifests client row is SP-9.5-7 now that share-links took SP-9.5-5 and SP-9.5-6. Older unreleased changelog entries drop the pending-erratum wording. (user: [email protected], size: 3249) [annotate] [blame] [check-ins using]
package conformance import ( "os" "testing" ) // syncClientCase is a scripted exchange and what the draft says a client // does in it. type syncClientCase struct { Case op clientOp setup []string // SQL on the client's copy of F // replies are the scripted replies' card lines; see syncFixture.body. replies [][]string // raw, when set, builds the reply entities instead, for cases about // framing. raw func(fx *syncFixture) [][]byte ctype string // the replies' media type; uncompressed unless set want clientCheck // fc also runs fossil(1)'s client against the script, whose requests // must meet want. fc bool // fossil is set only when fossil(1)'s client does not do what the // case expects, and says why the case follows the draft. fossil string // deviates, for a case marked Deviation, is what go-libfossil does // instead; a run that is neither is fatal. deviates clientCheck } func (c syncClientCase) peer(fx *syncFixture) *scriptedPeer { p := &scriptedPeer{fx: fx, ctype: c.ctype} if p.ctype == "" { p.ctype = typeUncompressed } if c.raw != nil { p.replies = c.raw(fx) return p } for _, reply := range c.replies { p.replies = append(p.replies, fx.body(reply...)) } return p } // run runs fossil(1)'s client, for an fc case, then go-libfossil's. fatal // is a fossil(1) disagreement or a harness failure; problem is // go-libfossil's departure from the case. func (c syncClientCase) run(fx *syncFixture, ref *fossilReference, dir string) (fatal, problem error) { if ref != nil && c.fc { run, err := ref.runFossilClient(fx, c.op, c.setup, c.peer(fx), dir) if err != nil { return err, nil } if err := fossilAgrees(c.want(run), c.fossil); err != nil { return expectf("%v (fossil output %.300q)", err, run.output), nil } } run, err := runGoClient(fx, c.op, c.setup, c.peer(fx), dir) if err != nil { return nil, err } problem = c.want(run) if problem != nil && c.deviates != nil { if err := c.deviates(run); err != nil { return expectf("not the deviation the case names: %v", err), nil } } return nil, problem } func TestSyncClient(t *testing.T) { ref := newFossilReference(t) top := t.TempDir() fx := newSyncFixture(t, top) for _, c := range syncClientCases() { c.Case = markSync(c.Case) checkSync(t, c.Case, func() (error, error) { dir, err := os.MkdirTemp(top, "case") if err != nil { return err, nil } return c.run(fx, ref, dir) }) } } func syncClientCases() []syncClientCase { var all []syncClientCase for _, group := range [][]syncClientCase{ clientRoundCases(), clientPhantomCases(), clientGimmeCases(), clientTerminationCases(), clientFramingCases(), clientPayloadCases(), clientCardCases(), clientCardNameCases(), clientAuthCases(), clientFileCases(), clientCFileCases(), clientUVFileCases(), clientDeltaCases(), clientPrivateCases(), clientCloneCases(), clientCloneStallCases(), clientCloneErrorCases(), clientUVCases(), clientUVStatusCases(), clientMessageCases(), clientGateCases(), clientAdmissionCases(), clientPullOnlyCases(), clientShortUVIGotCases(), clientRefusalCases(), clientCloneBadCardCases(), clientLinkCases(), clientIntegrityCases(), } { all = append(all, group...) } return all }