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.

relay_test.gno

8.02 Kb · 245 lines
  1package relay
  2
  3import (
  4	"strings"
  5	"testing"
  6
  7	"gno.land/p/g1magld5ptgzaktqcexxq0pgq5lmdf0kz6re8hlv/agents/msg/v0"
  8	"gno.land/p/g1magld5ptgzaktqcexxq0pgq5lmdf0kz6re8hlv/x/daily/ringbuffer/v0"
  9	"gno.land/p/nt/testutils/v0"
 10	"gno.land/p/nt/uassert/v0"
 11)
 12
 13var (
 14	alice = testutils.TestAddress("alice")
 15	bob   = testutils.TestAddress("bob")
 16)
 17
 18// reset puts the realm back to its init() state. Realm globals persist for the
 19// whole test binary and examples run after every Test, so every test that
 20// writes starts here and ExampleRender builds its own state.
 21func reset() {
 22	log = ringbuffer.New(Slots)
 23	seq = 0
 24	seen = 0
 25}
 26
 27func TestPostAssignsSeqAndAuthor(cur realm, t *testing.T) {
 28	reset()
 29	testing.SetRealm(testing.NewUserRealm(alice))
 30	got := Post(cross(cur), "agent-a", "build", "note", "pr/1", "first")
 31
 32	uassert.Equal(t, uint64(1), got)
 33	uassert.Equal(t, 1, Len())
 34	uassert.Equal(t, 1, Seen())
 35
 36	e := Latest(0)[0]
 37	uassert.Equal(t, uint64(1), e.Msg.Seq)
 38	uassert.Equal(t, "agent-a", e.Msg.From)
 39	uassert.Equal(t, alice.String(), e.Author.String())
 40}
 41
 42func TestSeqIsMonotonicAcrossAuthors(cur realm, t *testing.T) {
 43	reset()
 44	testing.SetRealm(testing.NewUserRealm(alice))
 45	Post(cross(cur), "agent-a", "build", "", "", "one")
 46	testing.SetRealm(testing.NewUserRealm(bob))
 47	Post(cross(cur), "agent-b", "build", "", "", "two")
 48
 49	all := Latest(0) // newest first
 50	uassert.Equal(t, uint64(2), all[0].Msg.Seq)
 51	uassert.Equal(t, bob.String(), all[0].Author.String())
 52	uassert.Equal(t, uint64(1), all[1].Msg.Seq)
 53	uassert.Equal(t, alice.String(), all[1].Author.String())
 54}
 55
 56func TestRingDropsTheOldestAndSeenKeepsCounting(cur realm, t *testing.T) {
 57	reset()
 58	testing.SetRealm(testing.NewUserRealm(alice))
 59	for i := 0; i < Slots+5; i++ {
 60		Post(cross(cur), "agent-a", "build", "", "", "body")
 61	}
 62	uassert.Equal(t, Slots, Len())
 63	uassert.Equal(t, Slots+5, Seen())
 64
 65	// The five oldest fell off the back; the newest is the last one posted.
 66	all := Latest(0)
 67	uassert.Equal(t, uint64(Slots+5), all[0].Msg.Seq)
 68	uassert.Equal(t, uint64(6), all[len(all)-1].Msg.Seq)
 69}
 70
 71func TestSinceAndTopicFilter(cur realm, t *testing.T) {
 72	reset()
 73	testing.SetRealm(testing.NewUserRealm(alice))
 74	Post(cross(cur), "agent-a", "build", "", "", "b1")
 75	Post(cross(cur), "agent-a", "deploy", "", "", "d1")
 76	Post(cross(cur), "agent-a", "build", "", "", "b2")
 77
 78	since := Since(1) // oldest first
 79	uassert.Equal(t, 2, len(since))
 80	uassert.Equal(t, uint64(2), since[0].Msg.Seq)
 81	uassert.Equal(t, uint64(3), since[1].Msg.Seq)
 82	uassert.Equal(t, 0, len(Since(3)))
 83
 84	build := Topic("build") // newest first
 85	uassert.Equal(t, 2, len(build))
 86	uassert.Equal(t, "b2", build[0].Msg.Body)
 87	uassert.Equal(t, 0, len(Topic("nothing-here")))
 88}
 89
 90func TestLatestRespectsN(cur realm, t *testing.T) {
 91	reset()
 92	testing.SetRealm(testing.NewUserRealm(alice))
 93	for i := 0; i < 5; i++ {
 94		Post(cross(cur), "agent-a", "build", "", "", "body")
 95	}
 96	uassert.Equal(t, 2, len(Latest(2)))
 97	uassert.Equal(t, 5, len(Latest(0)))
 98	uassert.Equal(t, 5, len(Latest(-1)))
 99}
100
101func TestPostRejectsInvalidFields(cur realm, t *testing.T) {
102	reset()
103	testing.SetRealm(testing.NewUserRealm(alice))
104	uassert.AbortsWithMessage(t, cur, "empty topic", func() {
105		Post(cross(cur), "agent-a", "", "", "", "body")
106	})
107	uassert.AbortsWithMessage(t, cur, "topic must be lowercase a-z, 0-9, dash or dot", func() {
108		Post(cross(cur), "agent-a", "Build", "", "", "body")
109	})
110	uassert.AbortsWithMessage(t, cur, "empty body", func() {
111		Post(cross(cur), "agent-a", "build", "", "", "")
112	})
113	uassert.Equal(t, 0, Len())
114	uassert.Equal(t, 0, Seen())
115}
116
117// TestBodySurvivesTheEncoding is the regression test for the framing: a body
118// that looks like the encoding, or ends in the digits a length prefix is made
119// of, must come back unchanged with its author still attached.
120func TestBodySurvivesTheEncoding(cur realm, t *testing.T) {
121	reset()
122	testing.SetRealm(testing.NewUserRealm(alice))
123	nasty := []string{
124		"ends in 40",
125		"3:abc",
126		"has\na newline",
127		msg.Msg{Seq: 9, Height: 9, From: "x", Topic: "y", Kind: "z", Ref: "w", Body: "v"}.Encode(),
128		"| breaks | a | table |",
129	}
130	for _, body := range nasty {
131		Post(cross(cur), "agent-a", "build", "", "", body)
132	}
133	got := Latest(0) // newest first
134	for i, body := range nasty {
135		e := got[len(nasty)-1-i]
136		uassert.Equal(t, body, e.Msg.Body)
137		uassert.Equal(t, alice.String(), e.Author.String())
138	}
139}
140
141// TestRenderEscapesACallersString pins what guard-untrusted-render exists for:
142// a pipe in a body must not open a column in the rendered table.
143func TestRenderEscapesACallersString(cur realm, t *testing.T) {
144	reset()
145	testing.SetRealm(testing.NewUserRealm(alice))
146	Post(cross(cur), "agent-a", "build", "", "", "a | b")
147
148	out := Render("")
149	uassert.False(t, strings.Contains(out, "| a | b |"),
150		"an unescaped pipe opened a column in the rendered table")
151}
152
153// TestRenderEscapesABodyExactlyOnce is the regression test for the v0 bug.
154// ui.Cell(ui.Excerpt(s)) escaped twice, so a hyphen reached mainnet as
155// backslash-backslash-backslash-hyphen. Over-escaping is not a security hole,
156// which is exactly why the pipe test above passed while this was broken: a
157// doubly escaped pipe is still safe and still wrong.
158func TestRenderEscapesABodyExactlyOnce(cur realm, t *testing.T) {
159	reset()
160	testing.SetRealm(testing.NewUserRealm(alice))
161	Post(cross(cur), "agent-a", "build", "", "", "evicting in-call")
162
163	out := Render("")
164	uassert.True(t, strings.Contains(out, `evicting in\-call`),
165		"a hyphen in a short body should be escaped once")
166	uassert.False(t, strings.Contains(out, `in\\-call`),
167		"the body was escaped more than once")
168}
169
170// TestRenderEscapesALongBodyExactlyOnce covers the other branch of
171// excerptCell, where the body is cut before it is escaped.
172func TestRenderEscapesALongBodyExactlyOnce(cur realm, t *testing.T) {
173	reset()
174	testing.SetRealm(testing.NewUserRealm(alice))
175	long := "evicting in-call"
176	for len(long) < 200 {
177		long += " and-again"
178	}
179	Post(cross(cur), "agent-a", "build", "", "", long)
180
181	out := Render("")
182	uassert.True(t, strings.Contains(out, `evicting in\-call`),
183		"a hyphen in a cut body should be escaped once")
184	uassert.False(t, strings.Contains(out, `in\\-call`),
185		"the cut body was escaped more than once")
186}
187
188// TestPostRecordsNoSessionForAMasterKey pins the empty-session branch. A test
189// signs as a plain user realm, never through a session, so isSession is false
190// and Session must stay empty rather than inherit the author.
191func TestPostRecordsNoSessionForAMasterKey(cur realm, t *testing.T) {
192	reset()
193	testing.SetRealm(testing.NewUserRealm(alice))
194	Post(cross(cur), "agent-a", "build", "", "", "body")
195
196	e := Latest(0)[0]
197	uassert.Equal(t, alice.String(), e.Author.String())
198	uassert.Equal(t, "", e.Session.String())
199}
200
201// TestWireRoundTripsThroughAReader walks the wire format exactly as an
202// off-chain reader must: unframe one entry at a time, then unframe the author
203// and the session off the front, then decode the message. The bodies are the
204// ones that break a qeval parser.
205func TestWireRoundTripsThroughAReader(cur realm, t *testing.T) {
206	reset()
207	testing.SetRealm(testing.NewUserRealm(alice))
208	bodies := []string{
209		`a body with " string),( in it`,
210		"ends in 40",
211		"has\na newline",
212		"| and | pipes |",
213	}
214	for _, b := range bodies {
215		Post(cross(cur), "agent-a", "build", "k", "r", b)
216	}
217
218	rest := Wire(0)
219	for i, want := range bodies {
220		framed, tail, ok := msg.Unframe(rest)
221		uassert.True(t, ok, "entry did not unframe")
222		rest = tail
223
224		author, r2, ok := msg.Unframe(framed)
225		uassert.True(t, ok, "author did not unframe")
226		session, r3, ok := msg.Unframe(r2)
227		uassert.True(t, ok, "session did not unframe")
228		m, ok := msg.Decode(r3)
229		uassert.True(t, ok, "message did not decode")
230
231		uassert.Equal(t, want, m.Body)
232		uassert.Equal(t, uint64(i+1), m.Seq)
233		uassert.Equal(t, alice.String(), author)
234		uassert.Equal(t, "", session)
235	}
236	uassert.Equal(t, "", rest, "the wire had trailing bytes")
237}
238
239func TestWireIsEmptyWhenNothingIsNewer(cur realm, t *testing.T) {
240	reset()
241	testing.SetRealm(testing.NewUserRealm(alice))
242	Post(cross(cur), "agent-a", "build", "", "", "one")
243	uassert.Equal(t, "", Wire(1))
244	uassert.True(t, Wire(0) != "", "Wire(0) should carry the only entry")
245}