Artifact 02bdd91e8fae94d2602f902b72cb5785a0dc9bebf7a5923f8aa05754db28b6a9:
- File
internal/sync/sparse_prepared_cache_test.go
— part of check-in
[632e7349e6]
at
2026-10-21 01:03:54
on branch feat/submanifest-reader
— fix(sync): isolate prepared fallback cache and cancellation
Never share RID-keyed cache state across prepared service transactions: protocol-fatal responses can roll back after expansion while returning a nil Go error. Reject canceled contexts before acquiring a transaction and propagate observer cancellation instead of serving densely.
Reproduce rollback, RID reuse and incorrect content under the replacement hash; verify cancellation and deadline responses do no dense work. Exercise newly shunned payload and basis suppression after prepared-proof invalidation. (user: [email protected], size: 2608) [annotate] [blame] [check-ins using] [more...]
package sync import ( "context" "testing" "github.com/danmestas/go-libfossil/internal/blob" "github.com/danmestas/go-libfossil/internal/content" libfossil "github.com/danmestas/go-libfossil/internal/fsltype" "github.com/danmestas/go-libfossil/internal/hash" "github.com/danmestas/go-libfossil/internal/xfer" ) // The fatal sequence card rolls back with a nil Go error, after gimme has // expanded a newly pushed artifact. A later committed blob reuses its RID. func TestPreparedSparseServiceRollbackDoesNotPoisonCache(t *testing.T) { r := setupSyncTestRepo(t) if _, err := r.DB().Exec("UPDATE user SET cap='goix' WHERE login='nobody'"); err != nil { t.Fatal(err) } cache := content.NewCache(1 << 20) service, err := prepareSparseService(context.Background(), r, HandleOpts{ContentCache: cache}) if err != nil { t.Fatal(err) } defer service.Close() var nextRID libfossil.FslID if err := r.DB().QueryRow("SELECT coalesce(max(rid),0)+1 FROM blob").Scan(&nextRID); err != nil { t.Fatal(err) } a := []byte("artifact A is rolled back") aUUID := hash.SHA1(a) cards := []xfer.Card{versionPragma("client-version"), &xfer.PullCard{ServerCode: "test", ProjectCode: testPC}, &xfer.PushCard{ServerCode: "test", ProjectCode: testPC}, &xfer.FileCard{UUID: aUUID, Content: a}, &xfer.GimmeCard{UUID: aUUID}, &xfer.CloneCard{Version: 3, SeqNo: 0, SeqNoIsDecimal: true}} transport := &preparedSparseTransport{service: service} resp, err := transport.Exchange(context.Background(), &xfer.Message{Cards: cards}) if err != nil { t.Fatal(err) } fatal := false for _, card := range resp.Cards { if _, ok := card.(*xfer.ErrorCard); ok { fatal = true } } if !fatal { t.Fatal("fixture did not hit protocol fatal") } if _, exists := blob.Exists(r.DB(), aUUID); exists { t.Fatal("protocol fatal did not actually roll back A") } b := []byte("artifact B reuses the uncommitted RID") bRID, bUUID, err := blob.Store(r.DB(), b) if err != nil { t.Fatal(err) } if bRID != nextRID { t.Fatalf("RID not reused: got %d want %d", bRID, nextRID) } resp, err = transport.Exchange(context.Background(), &xfer.Message{Cards: []xfer.Card{ versionPragma("client-version"), &xfer.PullCard{ServerCode: "test", ProjectCode: testPC}, &xfer.GimmeCard{UUID: bUUID}}}) if err != nil { t.Fatal(err) } for _, card := range resp.Cards { if c, ok := card.(*xfer.FileCard); ok && c.UUID == bUUID { if string(c.Content) != string(b) || hash.SHA3(c.Content) != bUUID { t.Fatalf("RID cache returned %q under B hash", c.Content) } return } } t.Fatal("B not returned") }