Artifact bd7194d67d5c4d83b4a906af7f01534859c950e3188163b4e48ad138e944aeae:
- File
internal/tag/receipt_test.go
— part of check-in
[4add332299]
at
2026-10-18 20:30:31
on branch feat/submanifest-reader
— fix: record one rcvfrom row per receipt, as fossil does
Fossil records each arrival of content (a commit, a tag, a sync or clone, a request its server answers, an unversioned add) as one rcvfrom row, made by content_rcvid_init when the first content arrives, and points every blob and unversioned file it stores at that row. go-libfossil seeded a single row at creation and pointed every blob at rcvid 1.
db.Receipt is that row: it is made lazily on first use, with the time as a Julian day, and remade if the transaction that made it rolled back. A transaction records content under the receipt it is given, and repo.WithReceipt gives one to every transaction, bound ones included, of a commit, tag, sync, clone or served request. The client credits its local user and the peer's address, as fossil's client records g.zIpAddr; the server credits nobody until a login card names a user, then that user and the card's nonce, from the request's address. Phantoms keep rcvid 0, and an applied unversioned deletion keeps its row's rcvid, as in fossil.
A new repository no longer starts with a placeholder row; an existing one keeps it. (user: [email protected], size: 1587) [annotate] [blame] [check-ins using] [more...]
package tag_test import ( "testing" "github.com/danmestas/go-libfossil/internal/manifest" "github.com/danmestas/go-libfossil/internal/tag" ) // A tag's control artifact is a receipt of its own, as `fossil tag add` // records one rcvfrom row, credited to the tagging user. func TestAddTagRecordsOneReceipt(t *testing.T) { r := setupTestRepo(t) rid, _, err := manifest.Checkin(r, manifest.CheckinOpts{ Files: []manifest.File{{Name: "hello.txt", Content: []byte("hello")}}, Comment: "initial commit", User: "testuser", }) if err != nil { t.Fatalf("Checkin: %v", err) } if _, err := r.DB().Exec("INSERT INTO user(login, pw, cap, info) VALUES('tagger', '', 'i', '')"); err != nil { t.Fatalf("add tagger: %v", err) } tagRid, err := tag.AddTag(r, tag.TagOpts{ TargetRID: rid, TagName: "label", TagType: tag.TagSingleton, User: "tagger", }) if err != nil { t.Fatalf("AddTag: %v", err) } var n int if err := r.DB().QueryRow("SELECT count(*) FROM rcvfrom").Scan(&n); err != nil { t.Fatalf("count rcvfrom: %v", err) } if n != 2 { t.Fatalf("rcvfrom rows = %d, want 2 (the check-in and the tag)", n) } var login string var blobs int if err := r.DB().QueryRow("SELECT user.login,"+ " (SELECT count(*) FROM blob b WHERE b.rcvid=rcvfrom.rcvid)"+ " FROM blob JOIN rcvfrom USING(rcvid) JOIN user ON user.uid=rcvfrom.uid"+ " WHERE blob.rid=?", tagRid).Scan(&login, &blobs); err != nil { t.Fatalf("tag receipt: %v", err) } if login != "tagger" || blobs != 1 { t.Fatalf("tag receipt credits %q with %d blobs, want \"tagger\" with 1", login, blobs) } }