tinyrelayfile
tinyrelay/internal/daemon/git_outbox_test.go/

internal/daemon/git_outbox_test.go raw
1package daemon
2
3import (
4 "context"
5 "fmt"
6 "testing"
7
8 "github.com/FelineStateMachine/tinyrelay/internal/event"
9)
10
11type gitOutboxTransport struct {
12 queries map[string][]event.Event
13 errors map[string]error
14}
15
16func (t gitOutboxTransport) Query(_ context.Context, target string, _ event.Filter) ([]event.Event, error) {
17 if err := t.errors[target]; err != nil {
18 return nil, err
19 }
20 if items := t.queries[target]; items != nil {
21 return items, nil
22 }
23 return nil, nil
24}
25
26func TestGitOutboxFilterIncludesProfilesRelayListsAndRepositoryRelayLists(t *testing.T) {
27 key := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
28 filter := gitOutboxFilter(key, 10002)
29 if len(filter.Authors) != 1 || filter.Authors[0] != key {
30 t.Fatalf("authors = %#v", filter.Authors)
31 }
32 if !containsGitKind(filter.Kinds, 10002) || len(filter.Kinds) != 1 {
33 t.Fatalf("kinds = %#v", filter.Kinds)
34 }
35 if filter.Limit == nil || *filter.Limit != 1 {
36 t.Fatalf("limit = %#v", filter.Limit)
37 }
38}
39
40func TestGitOutboxAuthorsAndRelaysAreDeduplicatedAndBounded(t *testing.T) {
41 key := "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
42 authors := make([]string, 0, gitOutboxAuthorLimit+2)
43 for i := 0; i < gitOutboxAuthorLimit+2; i++ {
44 authors = append(authors, key)
45 }
46 if got := boundedGitAuthors(authors); len(got) != 1 {
47 t.Fatalf("authors = %#v", got)
48 }
49 relays := boundedGitRelays([]string{"https://Relay.EXAMPLE/", "wss://relay.example"}, false, nil)
50 if len(relays) != 1 || relays[0] != "wss://relay.example" {
51 t.Fatalf("relays = %#v", relays)
52 }
53}
54
55func TestGitOutboxPrivateDiscoveryNeverUsesUnconfiguredRelay(t *testing.T) {
56 if gitOutboxAllowedRelay("wss://other.example", true, []string{"https://peer.example/git"}) {
57 t.Fatal("unconfigured private relay was allowed")
58 }
59 if !gitOutboxAllowedRelay("wss://peer.example/git", true, []string{"https://peer.example/git"}) {
60 t.Fatal("configured private relay was rejected")
61 }
62}
63
64func TestGitOutboxRelayTagsUseWriteCapableNIP65Entries(t *testing.T) {
65 list := event.Event{Kind: 10002, Tags: [][]string{{"r", "wss://read.example", "read"}, {"r", "wss://write.example", "write"}, {"r", "wss://both.example"}}}
66 got := gitOutboxRelayTags(list)
67 if len(got) != 2 || got[0] != "wss://write.example" || got[1] != "wss://both.example" {
68 t.Fatalf("relays = %#v", got)
69 }
70}
71
72func TestGitOutboxRelayTagsUseGroupEntriesForKind10317(t *testing.T) {
73 list := event.Event{Kind: 10317, Tags: [][]string{{"r", "wss://wrong.example"}, {"g", "wss://group.example"}}}
74 got := gitOutboxRelayTags(list)
75 if len(got) != 1 || got[0] != "wss://group.example" {
76 t.Fatalf("relays = %#v", got)
77 }
78}
79
80func TestGitConversationAuthorsAreLimitedToAdmittedParticipants(t *testing.T) {
81 owner := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
82 maintainer := "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
83 participant := "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
84 authors := gitConversationAuthors([]event.Event{{Kind: event.KIND_GIT_ISSUE, PubKey: participant}, {Kind: event.KIND_PROFILE, PubKey: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"}}, owner, []string{maintainer})
85 if len(authors) != 3 || authors[0] != owner || authors[1] != maintainer || authors[2] != participant {
86 t.Fatalf("authors = %#v", authors)
87 }
88}
89
90func TestGitConversationAuthorsDoesNotDropParticipantsBeforeBatching(t *testing.T) {
91 events := make([]event.Event, 40)
92 for i := range events {
93 events[i] = event.Event{Kind: event.KIND_GIT_ISSUE, PubKey: fmt.Sprintf("%064x", i+1)}
94 }
95 if got := gitConversationAuthors(events, "", nil); len(got) != len(events) {
96 t.Fatalf("authors = %d, want %d", len(got), len(events))
97 }
98}
99
100func TestGitOutboxAuthorBatchRotatesPastLimit(t *testing.T) {
101 events := make([]event.Event, 40)
102 for i := range events {
103 events[i] = event.Event{Kind: event.KIND_GIT_ISSUE, PubKey: fmt.Sprintf("%064x", i+1)}
104 }
105 authors := gitConversationAuthors(events, "", nil)
106 first := boundedGitAuthorsFrom(authors, 0)
107 second := boundedGitAuthorsFrom(authors, gitOutboxAuthorLimit)
108 if len(first) != gitOutboxAuthorLimit || len(second) != len(authors)-gitOutboxAuthorLimit {
109 t.Fatalf("batch sizes = %d and %d", len(first), len(second))
110 }
111 if first[0] == second[0] {
112 t.Fatal("rotated batch repeated its first author")
113 }
114}
115
116func TestRotateGitRelaysChangesStartingPoint(t *testing.T) {
117 input := []string{"wss://one.example", "wss://two.example", "wss://three.example"}
118 got := rotateGitRelays(input, 1)
119 if len(got) != 3 || got[0] != input[1] || got[2] != input[0] {
120 t.Fatalf("rotated relays = %#v", got)
121 }
122 if input[0] != "wss://one.example" {
123 t.Fatal("rotation modified input")
124 }
125}
126
127func TestDiscoverGitOutboxesRequiresTransport(t *testing.T) {
128 _, err := discoverGitOutboxes(context.Background(), gitOutboxOptions{}, []string{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"})
129 if err == nil || err.Error() != "GRASP-03: outbox transport is required" {
130 t.Fatalf("error = %v", err)
131 }
132}
133
134func TestDiscoverGitOutboxesIsolatesUnavailableSeeds(t *testing.T) {
135 secret, err := event.GenerateKey()
136 if err != nil {
137 t.Fatal(err)
138 }
139 item := event.Event{Kind: 10002, CreatedAt: 1, Tags: [][]string{{"r", "wss://outbox.example"}}}
140 if err := event.Sign(&item, secret); err != nil {
141 t.Fatal(err)
142 }
143 if err := event.Validate(item); err != nil {
144 t.Fatal(err)
145 }
146 if got := gitOutboxRelayTags(item); len(got) != 1 {
147 t.Fatalf("item relays = %#v", got)
148 }
149 transport := gitOutboxTransport{
150 queries: map[string][]event.Event{"wss://healthy.example": {item}},
151 errors: map[string]error{"wss://down.example": fmt.Errorf("connection refused")},
152 }
153 authors := []string{item.PubKey}
154 if got := boundedGitRelays([]string{"wss://down.example", "wss://healthy.example"}, false, nil); len(got) != 2 {
155 t.Fatalf("seed relays = %#v", got)
156 }
157 got, err := discoverGitOutboxes(context.Background(), gitOutboxOptions{Transport: transport, Seeds: []string{"wss://down.example", "wss://healthy.example"}}, authors)
158 if err == nil {
159 t.Fatal("expected isolated seed error to be reported")
160 }
161 if len(got) != 1 || got[0] != "wss://outbox.example" {
162 t.Fatalf("relays = %#v, err = %v", got, err)
163 }
164}
165
166func containsGitKind(kinds []int, wanted int) bool {
167 for _, kind := range kinds {
168 if kind == wanted {
169 return true
170 }
171 }
172 return false
173}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

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

Refs