Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

ref_test.gno

5.45 Kb · 155 lines
  1package forge
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nt/uassert/v0"
  7	"gno.land/p/nt/urequire/v0"
  8)
  9
 10func TestSetRefCompareAndSwap(t *testing.T) {
 11	_, r := newRepo(t)
 12
 13	// Create: the expectation is "this ref does not exist".
 14	e, err := r.SetRef(carol, 101, "refs/heads/main", "", oid("a"), "initial import")
 15	urequire.NoError(t, err)
 16	uassert.Equal(t, KindCreate, e.Kind)
 17	uassert.Equal(t, int64(0), e.Seq)
 18	uassert.Equal(t, "", e.OldOID)
 19	uassert.Equal(t, oid("a"), r.Ref("refs/heads/main").OID)
 20	uassert.Equal(t, carol.String(), r.Ref("refs/heads/main").UpdatedBy.String())
 21
 22	// Creating twice is a mistake, not an overwrite.
 23	_, err = r.SetRef(carol, 102, "refs/heads/main", "", oid("b"), "")
 24	uassert.ErrorIs(t, err, ErrRefExists)
 25
 26	// A stale expectation is exactly the lost-push case --force-with-lease
 27	// exists to catch, and here the lease is held by consensus.
 28	_, err = r.SetRef(carol, 102, "refs/heads/main", oid("9"), oid("b"), "")
 29	uassert.ErrorIs(t, err, ErrStaleRef)
 30
 31	// A fresh expectation succeeds and chains onto the previous entry.
 32	e2, err := r.SetRef(carol, 103, "refs/heads/main", oid("a"), oid("b"), "fix the thing")
 33	urequire.NoError(t, err)
 34	uassert.Equal(t, KindUpdate, e2.Kind)
 35	uassert.Equal(t, oid("a"), e2.OldOID)
 36	uassert.Equal(t, EntryDigest(e.Digest, e2), e2.Digest, "digest commits to its predecessor")
 37	uassert.Equal(t, e2.Digest, r.LogHead())
 38
 39	// No-op writes are rejected: they would cost a deposit and record nothing.
 40	_, err = r.SetRef(carol, 104, "refs/heads/main", oid("b"), oid("b"), "")
 41	uassert.ErrorIs(t, err, ErrSameOID)
 42
 43	// Updating a ref that does not exist is not a create.
 44	_, err = r.SetRef(carol, 104, "refs/heads/other", oid("a"), oid("b"), "")
 45	uassert.ErrorIs(t, err, ErrRefNotFound)
 46}
 47
 48func TestSetRefAuthorizationAndValidation(t *testing.T) {
 49	_, r := newRepo(t)
 50
 51	_, err := r.SetRef(eve, 101, "refs/heads/main", "", oid("a"), "")
 52	uassert.ErrorIs(t, err, ErrUnauthorized, "a stranger cannot move a ref")
 53	_, err = r.SetRef(dave, 101, "refs/heads/main", "", oid("a"), "")
 54	uassert.ErrorIs(t, err, ErrUnauthorized, "a reader cannot move a ref")
 55
 56	_, err = r.SetRef(carol, 101, "main", "", oid("a"), "")
 57	uassert.ErrorIs(t, err, ErrInvalidRefName)
 58	_, err = r.SetRef(carol, 101, "refs/heads/main", "", "deadbeef", "")
 59	uassert.ErrorIs(t, err, ErrInvalidOID)
 60	_, err = r.SetRef(carol, 101, "refs/heads/main", "", oid("a"), "two\nlines")
 61	uassert.ErrorIs(t, err, ErrInvalidText, "a note is one line: it is a digest field")
 62}
 63
 64func TestForceAndDelete(t *testing.T) {
 65	_, r := newRepo(t)
 66	_, err := r.SetRef(carol, 101, "refs/heads/main", "", oid("a"), "initial")
 67	urequire.NoError(t, err)
 68	_, err = r.SetRef(carol, 102, "refs/heads/wip", "", oid("c"), "wip")
 69	urequire.NoError(t, err)
 70
 71	// A writer cannot force. A maintainer can, and it is on the record forever.
 72	_, err = r.ForceSetRef(carol, 103, "refs/heads/main", oid("d"), "rewrite")
 73	uassert.ErrorIs(t, err, ErrUnauthorized)
 74	e, err := r.ForceSetRef(bob, 103, "refs/heads/main", oid("d"), "drop the bad commit")
 75	urequire.NoError(t, err)
 76	uassert.Equal(t, KindForce, e.Kind)
 77	uassert.Equal(t, oid("a"), e.OldOID, "the abandoned tip stays in the log")
 78
 79	// Delete is compare-and-swap too, and the default branch is not deletable.
 80	_, err = r.DeleteRef(bob, 104, "refs/heads/main", oid("d"), "")
 81	uassert.ErrorIs(t, err, ErrUnauthorized)
 82	_, err = r.DeleteRef(bob, 104, "refs/heads/wip", oid("9"), "")
 83	uassert.ErrorIs(t, err, ErrStaleRef)
 84	_, err = r.DeleteRef(carol, 104, "refs/heads/wip", oid("c"), "")
 85	uassert.ErrorIs(t, err, ErrUnauthorized)
 86	de, err := r.DeleteRef(bob, 104, "refs/heads/wip", oid("c"), "merged")
 87	urequire.NoError(t, err)
 88	uassert.Equal(t, KindDelete, de.Kind)
 89	uassert.Equal(t, "", de.NewOID)
 90	uassert.Equal(t, 1, r.RefCount(), "the ref is gone")
 91	uassert.Equal(t, 4, r.LogSize(), "the history of it is not")
 92
 93	_, err = r.DeleteRef(bob, 105, "refs/heads/wip", "", "")
 94	uassert.ErrorIs(t, err, ErrRefNotFound)
 95}
 96
 97func TestLogChainVerifies(t *testing.T) {
 98	_, r := newRepo(t)
 99	urequire.Equal(t, "", r.LogHead())
100
101	for i, o := range []string{"a", "b", "c", "d"} {
102		expected := ""
103		if i > 0 {
104			expected = r.Ref("refs/heads/main").OID
105		}
106		_, err := r.SetRef(carol, int64(100+i), "refs/heads/main", expected, oid(o), "step")
107		urequire.NoError(t, err)
108	}
109	uassert.Equal(t, 4, r.LogSize())
110
111	ok, bad := r.VerifyLog()
112	uassert.True(t, ok, "an untouched log verifies")
113	uassert.Equal(t, int64(-1), bad)
114
115	// Rewrite history the only way it can be rewritten here: reaching into the
116	// package's own memory, and the chain detects it at the doctored entry.
117	r.LogEntryAt(1).NewOID = oid("f")
118	ok, bad = r.VerifyLog()
119	uassert.False(t, ok, "a doctored entry breaks the chain")
120	uassert.Equal(t, int64(1), bad)
121}
122
123func TestLogIteration(t *testing.T) {
124	_, r := newRepo(t)
125	for i, o := range []string{"a", "b", "c"} {
126		expected := ""
127		if i > 0 {
128			expected = r.Ref("refs/heads/main").OID
129		}
130		_, err := r.SetRef(carol, int64(100+i), "refs/heads/main", expected, oid(o), "")
131		urequire.NoError(t, err)
132	}
133
134	var fwd []string
135	r.IterateLog(0, 0, func(e *LogEntry) bool {
136		fwd = append(fwd, e.NewOID[:1])
137		return false
138	})
139	uassert.Equal(t, "a,b,c", join(fwd))
140
141	var rev []string
142	r.IterateLogReverse(0, 2, func(e *LogEntry) bool {
143		rev = append(rev, e.NewOID[:1])
144		return false
145	})
146	uassert.Equal(t, "c,b", join(rev), "newest-first, paginated")
147
148	var names []string
149	r.IterateRefs(func(ref *Ref) bool {
150		names = append(names, ref.Name)
151		return false
152	})
153	uassert.Equal(t, "refs/heads/main", join(names))
154	uassert.True(t, r.LogEntryAt(99) == nil)
155}