eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1package bot
2
3import (
4 "net/http"
5 "net/http/httptest"
6 "net/url"
7 "strings"
8 "testing"
9)
10
11func TestFeedLinksFromHTML(t *testing.T) {
12 base, _ := url.Parse("https://news.example/section/home")
13 html := `<!doctype html><html><head>
14 <link rel="alternate" type="application/rss+xml" href="/feeds/all.xml" title="Everything">
15 <LINK REL="alternate" TYPE="application/atom+xml" HREF="https://news.example/atom">
16 <link type="application/rss+xml" rel='alternate' href='also-relative.rss'>
17 <link rel="alternate" type="application/rss+xml" href="/feeds/all.xml">
18 <link rel="stylesheet" href="/style.css">
19 <link rel="alternate" type="text/html" href="/mobile">
20 </head><body></body></html>`
21 feeds := feedLinksFromHTML(html, base)
22 want := []string{
23 "https://news.example/feeds/all.xml",
24 "https://news.example/atom",
25 "https://news.example/section/also-relative.rss", // resolved against the page URL
26 }
27 if len(feeds) != len(want) {
28 t.Fatalf("got %v, want %v", feeds, want)
29 }
30 for i := range want {
31 if feeds[i] != want[i] {
32 t.Errorf("feed %d: got %q, want %q", i, feeds[i], want[i])
33 }
34 }
35 if got := feedLinksFromHTML("<p>no links here</p>", base); len(got) != 0 {
36 t.Errorf("linkless page: got %v", got)
37 }
38}
39
40func TestDiscoverFeeds(t *testing.T) {
41 t.Setenv("LCHAT_BOT_ALLOW_PRIVATE_FETCH", "1")
42 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
43 w.Header().Set("Content-Type", "text/html")
44 w.Write([]byte(`<html><head><link rel="alternate" type="application/rss+xml" href="/rss.xml"></head></html>`))
45 }))
46 defer srv.Close()
47
48 feeds, err := discoverFeeds(srv.URL)
49 if err != nil {
50 t.Fatalf("discover: %v", err)
51 }
52 if len(feeds) != 1 || feeds[0] != srv.URL+"/rss.xml" {
53 t.Fatalf("got %v", feeds)
54 }
55
56 // The tool wrapper formats for a tool_result and surfaces failures as text.
57 if out := runDiscoverFeeds(map[string]any{"site": srv.URL}); !strings.Contains(out, "/rss.xml") {
58 t.Fatalf("tool output: %q", out)
59 }
60 if out := runDiscoverFeeds(map[string]any{"site": ""}); !strings.Contains(out, "discovery failed") {
61 t.Fatalf("empty site should fail as text: %q", out)
62 }
63}
64
65// Without the test escape hatch, discovery refuses non-https and (via the
66// dialer guard) private addresses — the member named a site, not our LAN.
67func TestDiscoverFeedsBlocksPrivate(t *testing.T) {
68 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
69 w.Write([]byte("secret"))
70 }))
71 defer srv.Close()
72 if _, err := discoverFeeds(srv.URL); err == nil {
73 t.Fatal("loopback http discovery must be refused outside test mode")
74 }
75}
76
77func TestSameSiteHost(t *testing.T) {
78 ok := [][2]string{{"bbc.com", "bbc.com"}, {"www.bbc.com", "bbc.com"}, {"bbc.com", "www.bbc.com"}}
79 for _, p := range ok {
80 if !sameSiteHost(p[0], p[1]) {
81 t.Errorf("%s vs %s should be the same site", p[0], p[1])
82 }
83 }
84 bad := [][2]string{{"bbc.com", "bbc.co.uk"}, {"www.bbc.com", "www.npr.org"}, {"evil-bbc.com", "bbc.com"}}
85 for _, p := range bad {
86 if sameSiteHost(p[0], p[1]) {
87 t.Errorf("%s vs %s should NOT be the same site", p[0], p[1])
88 }
89 }
90}
91
92func TestHostLabelAndJoinAnd(t *testing.T) {
93 for in, want := range map[string]string{
94 "bbc.com": "bbc.com",
95 "https://www.bbc.com/": "bbc.com",
96 "http://npr.org/feeds?x=1": "npr.org",
97 " theguardian.com/uk ": "theguardian.com",
98 } {
99 if got := hostLabel(in); got != want {
100 t.Errorf("hostLabel(%q) = %q, want %q", in, got, want)
101 }
102 }
103 if got := joinAnd([]string{"a"}); got != "a" {
104 t.Errorf("joinAnd one: %q", got)
105 }
106 if got := joinAnd([]string{"a", "b"}); got != "a and b" {
107 t.Errorf("joinAnd two: %q", got)
108 }
109 if got := joinAnd([]string{"a", "b", "c"}); got != "a, b and c" {
110 t.Errorf("joinAnd three: %q", got)
111 }
112}
113