Artifact 47fea0a164d13e75e98d988b12a4e05bfa9d31406aced01474c12510e79d091c:
- File
conformance/sync_test.go
— part of check-in
[8cc3d7c5e4]
at
2026-10-13 02:23:50
on branch test/conformance-01-drafts
— test(conformance): check the -01 drafts of artifact, repo-state and sync
Re-pin the conformance suite to draft-fossil-artifact-format-01, draft-fossil-repo-state-01 and draft-fossil-sync-protocol-01, copied byte for byte from zit check-in 100351e26c. The delta format has no -01 and stays on -00. The -00 errata are folded into -01 and are no longer pinned; the six -01 errata are pinned for the fossil 2.28 behavior they record. conformance/rfcs/README.md records where each copy came from.
The requirement tables are re-read against -01, and new cases cover the date tag's event time (repo-state ยง4.2 step 6), the Julian-day grammar, a delta manifest naming a delta, dropped reserved F cards, the trailing-punctuation retry, truncated payloads, errors N, a file card after a refused push, the end of a request after a failed login, and the answer to a gimme for private content.
No library behavior changes. Where -01 departs from fossil 2.28 and go-libfossil follows fossil (a cancelled, unparsable or 0 date tag), the cases are marked as deviations. The non-conformances the re-pin exposes are marked as gaps, tracked in #370, #371, #372, #373, #374 and #375. (user: [email protected], size: 3084) [annotate] [blame] [check-ins using] [more...]
package conformance import ( "fmt" "io" "log/slog" "testing" ) // The sync suite checks draft-fossil-sync-protocol-01. It drives the real // code end to end, with nothing mocked but the far end of the wire: // // - a server case is raw request bytes sent to Repo.XferHandler, and the // same request sent to fossil(1) through `fossil http`, each on its own // copy of the fixture repository; // - a client case is a scripted peer answering the public Sync and Clone // through a FramedTransport; for the cases marked fc, fossil(1)'s // client talks to the same script over HTTP; // - an HTTP case is a scripted httptest server, for redirects, status // codes and media types; // - an interop case is a whole session between go-libfossil and fossil(1). // // Every expectation is checked against fossil(1) on every run where it can // be, so a case cannot drift from fossil unnoticed, and a disagreement is // fatal whatever the case's mark; a case that knowingly differs from // fossil, or cannot be sent to it, says why in its fossil or notSent // field. Each case's input // differs from an exchange another case shows to be handled normally in // one respect, and each refusal names its reason, so a case fails when // something other than its rule decides the outcome. // checkSync runs one sync case as a subtest. run returns two problems: // fatal, which fails the case whatever its mark (fossil(1) disagreeing // with the case, a deviation other than the one named, or the harness // itself failing), and conforms, go-libfossil's own departure from the // case, which the mark judges as check does. func checkSync(t *testing.T, c Case, run func() (fatal, conforms error)) { t.Helper() t.Run(c.ID, func(t *testing.T) { t.Helper() fatal, conforms := run() if fatal != nil { t.Fatalf("%s [%s]: %v", c.ID, c.Req, fatal) } result, message := judge(c, conforms) switch result { case outcomePass: case outcomeFail: t.Fatal(message) case outcomeSkip: t.Skip(message) default: panic(fmt.Sprintf("conformance: unknown outcome %d", result)) } }) } // quietLogs discards the slog output of go-libfossil's server for the rest // of a test: it logs every request it refuses, and many cases are refused // requests. func quietLogs(t *testing.T) { t.Helper() previous := slog.Default() slog.SetDefault(slog.New(slog.NewTextHandler(io.Discard, nil))) t.Cleanup(func() { slog.SetDefault(previous) }) } // markSync sets a case's Gap or Deviation from the suite's maps. func markSync(c Case) Case { c.Gap = syncGaps[c.ID] c.Deviation = syncDeviations[c.ID] return c } // syncSuiteCases is what the coverage test audits for this suite. func syncSuiteCases() []Case { var all []Case for _, c := range syncServerCases() { all = append(all, markSync(c.Case)) } for _, c := range syncClientCases() { all = append(all, markSync(c.Case)) } for _, c := range syncHTTPCases() { all = append(all, markSync(c.Case)) } for _, c := range syncInteropCases() { all = append(all, markSync(c.Case)) } return all }