tinyrelayfile
tinyrelay/internal/daemon/chat_activity_test.go/

internal/daemon/chat_activity_test.go raw
1package daemon
2
3import (
4 "encoding/json"
5 "github.com/FelineStateMachine/tinyrelay/internal/event"
6 "testing"
7)
8
9func TestChatActivitySharesApprovalStateAndScopesRooms(t *testing.T) {
10 h := newRoomHarness(t)
11 request := h.must("alice", 5000, [][]string{{"h", "main"}, {"p", h.keys["bob"]}, {"subject", "Build preview"}}, "Build preview")
12 h.must("bob", 7000, [][]string{{"h", "main"}, {"e", request.ID}, {"p", h.keys["alice"]}, {"status", "processing", "Running checks"}}, "2 of 3 checks complete")
13 decision := h.must("alice", 9, [][]string{{"h", "main"}, {"request", "approve"}, {"p", h.keys["bob"]}, {"subject", "Publish preview"}}, "Publish it?")
14 read := func(who, room string) map[string]any {
15 t.Helper()
16 raw, err := h.tenant.Execute(h.ctx, h.keys[who], "browsechatactivity", []json.RawMessage{rawJSON(map[string]string{"room": room})})
17 if err != nil {
18 t.Fatal(err)
19 }
20 return raw.(map[string]any)
21 }
22 data := read("bob", "main")
23 jobs := data["jobs"].([]jobItem)
24 if len(jobs) != 1 || jobs[0].Status != "processing" {
25 t.Fatalf("jobs=%v", jobs)
26 }
27 approvals := data["approvals"].([]approvalItem)
28 if len(approvals) != 1 || approvals[0].State != "open" {
29 t.Fatalf("approvals=%v", approvals)
30 }
31 h.must("bob", 7, [][]string{{"h", "main"}, {"e", decision.ID}, {"p", h.keys["alice"]}}, "+")
32 data = read("bob", "main")
33 if data["approvals"].([]approvalItem)[0].State != "answered" {
34 t.Fatal("inline approval not settled")
35 }
36 detail, err := h.tenant.Execute(h.ctx, h.keys["bob"], "browseapproval", []json.RawMessage{rawJSON(map[string]string{"id": decision.ID})})
37 if err != nil {
38 t.Fatal(err)
39 }
40 if detail.(map[string]any)["item"].(approvalItem).State != "answered" {
41 t.Fatal("Approvals disagrees")
42 }
43 h.must("alice", event.KIND_CREATE_GROUP, [][]string{{"h", "private-chat"}, {"name", "Private"}, {"visibility", "members"}}, "")
44 private := h.must("alice", 5000, [][]string{{"h", "private-chat"}, {"p", h.keys["alice"]}}, "Private work")
45 if _, err := h.tenant.Execute(h.ctx, h.keys["bob"], "browsechatactivity", []json.RawMessage{rawJSON(map[string]string{"room": "private-chat"})}); err == nil {
46 t.Fatal("outsider read private activity")
47 }
48 for _, job := range read("bob", "main")["jobs"].([]jobItem) {
49 if job.ID == private.ID {
50 t.Fatal("private job leaked")
51 }
52 }
53 if _, err := h.publish("alice", 7000, [][]string{{"e", private.ID}, {"p", h.keys["alice"]}, {"status", "processing"}}, "private progress"); err == nil {
54 t.Fatal("unscoped progress accepted for a private room task")
55 }
56}
57func TestChatPresenceIsEphemeralAndRoomAuthorized(t *testing.T) {
58 h := newRoomHarness(t)
59 h.must("alice", event.KIND_CREATE_GROUP, [][]string{{"h", "private-chat"}, {"visibility", "members"}}, "")
60 for _, kind := range []int{20001, 20002} {
61 e := h.must("alice", kind, [][]string{{"h", "private-chat"}}, "typing")
62 if rows := h.query("alice", event.Filter{IDs: []string{e.ID}}); len(rows) != 0 {
63 t.Fatal("presence persisted")
64 }
65 if _, err := h.publish("bob", kind, [][]string{{"h", "private-chat"}}, "typing"); err == nil {
66 t.Fatal("outsider presence accepted")
67 }
68 }
69}
70
71func TestChatActivityIncludesParentOnlyRequestsInCanonicalThread(t *testing.T) {
72 h := newRoomHarness(t)
73 root := h.must("alice", 9, [][]string{{"h", "main"}}, "Root")
74 parent := h.must("bob", 9, [][]string{{"h", "main"}, {"e", root.ID, "", "reply"}}, "Parent")
75 approval := h.must("alice", 9, [][]string{{"h", "main"}, {"e", parent.ID, "", "reply"}, {"request", "approve"}, {"p", h.keys["bob"]}}, "Approve the nested action?")
76 job := h.must("alice", 5000, [][]string{{"h", "main"}, {"e", parent.ID}, {"p", h.keys["bob"]}}, "Nested job")
77 other := h.must("alice", 9, [][]string{{"h", "main"}}, "Another root")
78 h.must("alice", 9, [][]string{{"h", "main"}, {"e", other.ID, "", "root"}, {"request", "approve"}, {"p", h.keys["bob"]}}, "Unrelated action")
79 raw, err := h.tenant.Execute(h.ctx, h.keys["bob"], "browsechatactivity", []json.RawMessage{rawJSON(map[string]string{"room": "main", "root": root.ID})})
80 if err != nil {
81 t.Fatal(err)
82 }
83 data := raw.(map[string]any)
84 approvals, jobs := data["approvals"].([]approvalItem), data["jobs"].([]jobItem)
85 if len(approvals) != 1 || approvals[0].ID != approval.ID || len(jobs) != 1 || jobs[0].ID != job.ID {
86 t.Fatalf("activity omitted nested request or included another thread: %v", data)
87 }
88}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

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

Refs