package crawler import ( "os" "testing" "git.smesh.lol/nostr/pkg/event" "git.smesh.lol/nostr/pkg/kind" "git.smesh.lol/nostr/pkg/signer/p8k" "git.smesh.lol/nostr/pkg/tag" "git.smesh.lol/morly/pkg/store" ) // openTmp opens a store in a fresh directory. The caller owns both: defer // os.RemoveAll(dir) and defer eng.Close(). A t.Cleanup closure would have to // capture eng, which Moxie closures do not do. func openTmp(t *testing.T) (p *store.Engine, dir string) { t.Helper() dir, derr := os.MkdirTemp("", "moxie-crawler") if derr != nil { t.Fatal(derr) } eng, err := store.Open(dir) if err != nil { t.Fatal(err) } return eng, dir } func makeRelayList(t *testing.T, s *p8k.Signer, relays ...string) (p *event.E) { t.Helper() kind.Ensure() tags := tag.NewSWithCap(len(relays)) for _, r := range relays { // tags is a *tag.S, whose element slice is T; pushing onto the struct // itself is `push on non-slice type` (stage4 used to emit IR for it // instead of the error, which read as an IR-emit bug). tags.T = push(tags.T, tag.NewFromBytesSlice([]byte("r"), []byte(r))) } ev := &event.E{ CreatedAt: 1700000000, Kind: kind.RelayListMetadata.K, Tags: tags, } if err := ev.Sign(s); err != nil { t.Fatal(err) } return ev } func TestDiscoverRelays(t *testing.T) { eng, dir := openTmp(t) defer os.RemoveAll(dir) defer eng.Close() s := p8k.MustNew() if err := s.Generate(); err != nil { t.Fatal(err) } ev := makeRelayList(t, s, "wss://relay.example.com", "wss://another.relay") if err := eng.SaveEvent(ev); err != nil { t.Fatal(err) } c := New(eng) relays := c.Discover() if len(relays) != 2 { t.Fatalf("expected 2 relays, got %d", len(relays)) } urls := map[string]bool{} for _, r := range relays { urls[r.URL] = true // No hint means both read+write if !r.Read || !r.Write { t.Errorf("relay %s should be read+write", r.URL) } } if !urls["wss://relay.example.com"] || !urls["wss://another.relay"] { t.Error("missing expected relay URLs") } } func TestDiscoverDedup(t *testing.T) { eng, dir := openTmp(t) defer os.RemoveAll(dir) defer eng.Close() s1 := p8k.MustNew() if err := s1.Generate(); err != nil { t.Fatal(err) } s2 := p8k.MustNew() if err := s2.Generate(); err != nil { t.Fatal(err) } // Two users list the same relay if err := eng.SaveEvent(makeRelayList(t, s1, "wss://shared.relay")); err != nil { t.Fatal(err) } if err := eng.SaveEvent(makeRelayList(t, s2, "wss://shared.relay")); err != nil { t.Fatal(err) } c := New(eng) relays := c.Discover() if len(relays) != 1 { t.Fatalf("expected 1 deduplicated relay, got %d", len(relays)) } } func TestDiscoverURLs(t *testing.T) { eng, dir := openTmp(t) defer os.RemoveAll(dir) defer eng.Close() s := p8k.MustNew() if err := s.Generate(); err != nil { t.Fatal(err) } if err := eng.SaveEvent(makeRelayList(t, s, "wss://relay.one")); err != nil { t.Fatal(err) } c := New(eng) urls := c.DiscoverURLs() if len(urls) != 1 || urls[0] != "wss://relay.one" { t.Fatalf("expected [wss://relay.one], got %v", urls) } }