tinyrelayfile
tinyrelay/internal/daemon/room_edit_history_test.go/

internal/daemon/room_edit_history_test.go raw
1package daemon
2
3import (
4 "strconv"
5 "testing"
6 "time"
7
8 "github.com/FelineStateMachine/tinyrelay/internal/event"
9 "github.com/FelineStateMachine/tinyrelay/internal/relay"
10)
11
12func TestBrowseThreadReturnsNewestAuthorEditsOutsideCursor(t *testing.T) {
13 h := newRoomHarness(t)
14 h.must("alice", event.KIND_CREATE_GROUP, [][]string{{"h", "general"}}, "")
15 root := h.must("alice", event.KIND_THREAD, [][]string{{"h", "general"}}, "original root")
16 reply := h.must("bob", event.KIND_THREAD_REPLY, [][]string{{"h", "general"}, {"e", root.ID}}, "original reply")
17
18 cursor := collaborationCursor(collaborationItemFrom(reply))
19
20 publishAt := func(who string, createdAt int64, target event.Event, content string) event.Event {
21 e := h.sign(who, event.KIND_CONTENT_EDIT, [][]string{{"h", "general"}, {"e", target.ID}}, content)
22 e.CreatedAt = createdAt
23 if err := event.Sign(&e, h.secrets[who]); err != nil {
24 t.Fatal(err)
25 }
26 if _, err := h.tenant.router.Publish(h.ctx, e, relay.Session{PubKeys: []string{h.keys[who]}, RelayURL: h.tenant.RelayURL()}); err != nil {
27 t.Fatal(err)
28 }
29 return e
30 }
31 old := publishAt("alice", time.Now().Unix()+1, root, "root v1")
32 newest := publishAt("alice", old.CreatedAt+1, root, "root v2")
33 replyEdit := publishAt("bob", newest.CreatedAt+1, reply, "reply v1")
34
35 page, err := h.browse("bob", "browsethread", map[string]any{"id": "general", "event": root.ID, "cursor": cursor, "limit": 1})
36 if err != nil {
37 t.Fatal(err)
38 }
39 edits, ok := page["edits"].([]any)
40 if !ok {
41 t.Fatalf("edits = %#v", page["edits"])
42 }
43 found := map[string]bool{}
44 for _, raw := range edits {
45 row := raw.(map[string]any)
46 found[row["id"].(string)] = true
47 }
48 if !found[newest.ID] || found[replyEdit.ID] || found[old.ID] {
49 t.Fatalf("edits = %#v, want newest visible root only", edits)
50 }
51
52 forged := h.sign("alice", event.KIND_CONTENT_EDIT, [][]string{{"h", "general"}, {"e", reply.ID}}, "wrong author")
53 // The target belongs to Bob, so the author filter must exclude this edit.
54 if _, err := h.tenant.router.Publish(h.ctx, forged, relay.Session{PubKeys: []string{h.keys["alice"]}, RelayURL: h.tenant.RelayURL()}); err != nil {
55 t.Fatal(err)
56 }
57 page, err = h.browse("bob", "browsethread", map[string]any{"id": "general", "event": root.ID})
58 if err != nil {
59 t.Fatal(err)
60 }
61 found = map[string]bool{}
62 for _, raw := range page["edits"].([]any) {
63 found[raw.(map[string]any)["id"].(string)] = true
64 if raw.(map[string]any)["content"] == "wrong author" {
65 t.Fatal("forged edit was returned")
66 }
67 }
68 if !found[replyEdit.ID] || !found[newest.ID] {
69 t.Fatalf("unpaged edits = %#v, want root and reply", page["edits"])
70 }
71}
72
73func TestRoomEditsKeepIndependentTargetsAndUseLastReference(t *testing.T) {
74 h := newRoomHarness(t)
75 h.must("alice", event.KIND_CREATE_GROUP, [][]string{{"h", "general"}}, "")
76 first := h.must("alice", event.KIND_CHAT, [][]string{{"h", "general"}}, "first")
77 second := h.must("alice", event.KIND_CHAT, [][]string{{"h", "general"}}, "second")
78 wanted := h.must("alice", event.KIND_CONTENT_EDIT, [][]string{{"h", "general"}, {"e", first.ID}}, "first replacement")
79 var latest event.Event
80 for i := 0; i < 105; i++ {
81 // The first reference is context; only the last reference is edited.
82 latest = signedEvent(t, h.secrets["alice"], event.KIND_CONTENT_EDIT, first.CreatedAt+int64(i)+1, [][]string{{"h", "general"}, {"e", first.ID}, {"e", second.ID}}, "second replacement "+strconv.Itoa(i))
83 if err := publishAs(t, h.tenant, latest); err != nil {
84 t.Fatal(err)
85 }
86 }
87 edits, err := h.tenant.roomEdits(h.ctx, h.keys["alice"], "general", []event.Event{first, second})
88 if err != nil {
89 t.Fatal(err)
90 }
91 found := map[string]bool{}
92 for _, edit := range edits {
93 found[edit.ID] = true
94 }
95 if len(edits) != 2 || !found[wanted.ID] || !found[latest.ID] {
96 t.Fatalf("lost independent target edit: %+v", edits)
97 }
98}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs