You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
4.8 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package rssbot
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "io/ioutil"
  7. "net/http"
  8. "strings"
  9. "sync"
  10. "testing"
  11. "time"
  12. "github.com/matrix-org/go-neb/database"
  13. "github.com/matrix-org/go-neb/testutils"
  14. "github.com/matrix-org/go-neb/types"
  15. "maunium.net/go/mautrix"
  16. mevt "maunium.net/go/mautrix/event"
  17. "maunium.net/go/mautrix/id"
  18. )
  19. const rssFeedXML = `
  20. <?xml version="1.0" encoding="UTF-8"?>
  21. <rss version="2.0"
  22. xmlns:content="http://purl.org/rss/1.0/modules/content/"
  23. xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  24. xmlns:dc="http://purl.org/dc/elements/1.1/"
  25. xmlns:atom="http://www.w3.org/2005/Atom"
  26. xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
  27. xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  28. >
  29. <channel>
  30. <title>Mask Shop</title>
  31. <item>
  32. <title>New Item: Majora&#8217;s Mask</title>
  33. <link>http://go.neb/rss/majoras-mask</link>
  34. <author>The Skullkid!</author>
  35. </item>
  36. </channel>
  37. </rss>`
  38. func createRSSClient(t *testing.T, feedURL string) *Service {
  39. database.SetServiceDB(&database.NopStorage{})
  40. // Replace the cachingClient with a mock so we can intercept RSS requests
  41. rssTrans := testutils.NewRoundTripper(func(req *http.Request) (*http.Response, error) {
  42. if req.URL.String() != feedURL {
  43. return nil, errors.New("Unknown test URL")
  44. }
  45. return &http.Response{
  46. StatusCode: 200,
  47. Body: ioutil.NopCloser(bytes.NewBufferString(rssFeedXML)),
  48. }, nil
  49. })
  50. cachingClient = &http.Client{Transport: rssTrans}
  51. // Create the RSS service
  52. srv, err := types.CreateService("id", "rssbot", "@happy_mask_salesman:hyrule", []byte(
  53. `{"feeds": {"`+feedURL+`":{}}}`, // no config yet
  54. ))
  55. if err != nil {
  56. t.Fatal(err)
  57. }
  58. rssbot := srv.(*Service)
  59. // Configure the service to force OnPoll to query the RSS feed and attempt to send results
  60. // to the right room.
  61. f := rssbot.Feeds[feedURL]
  62. f.Rooms = []id.RoomID{"!linksroom:hyrule"}
  63. f.NextPollTimestampSecs = time.Now().Unix()
  64. rssbot.Feeds[feedURL] = f
  65. return rssbot
  66. }
  67. func TestHTMLEntities(t *testing.T) {
  68. feedURL := "https://thehappymaskshop.hyrule"
  69. rssbot := createRSSClient(t, feedURL)
  70. // Create the Matrix client which will send the notification
  71. wg := sync.WaitGroup{}
  72. wg.Add(1)
  73. matrixTrans := struct{ testutils.MockTransport }{}
  74. matrixTrans.RT = func(req *http.Request) (*http.Response, error) {
  75. if strings.HasPrefix(req.URL.Path, "/_matrix/client/r0/rooms/!linksroom:hyrule/send/m.room.message") {
  76. // Check content body to make sure it is decoded
  77. var msg mevt.MessageEventContent
  78. if err := json.NewDecoder(req.Body).Decode(&msg); err != nil {
  79. t.Fatal("Failed to decode request JSON: ", err)
  80. return nil, errors.New("Error handling matrix client test request")
  81. }
  82. want := "New Item: Majora\u2019s Mask" // 0x2019 = 8217
  83. if !strings.Contains(msg.Body, want) {
  84. t.Errorf("TestHTMLEntities: want '%s' in body, got '%s'", want, msg.Body)
  85. }
  86. wg.Done()
  87. return &http.Response{
  88. StatusCode: 200,
  89. Body: ioutil.NopCloser(bytes.NewBufferString(`
  90. {"event_id":"$123456:hyrule"}
  91. `)),
  92. }, nil
  93. }
  94. return nil, errors.New("Unhandled matrix client test request")
  95. }
  96. matrixClient, _ := mautrix.NewClient("https://hyrule", "@happy_mask_salesman:hyrule", "its_a_secret")
  97. matrixClient.Client = &http.Client{Transport: matrixTrans}
  98. // Invoke OnPoll to trigger the RSS feed update
  99. _ = rssbot.OnPoll(matrixClient)
  100. // Check that the Matrix client sent a message
  101. wg.Wait()
  102. }
  103. func TestFeedItemFiltering(t *testing.T) {
  104. feedURL := "https://thehappymaskshop.hyrule"
  105. // Create rssbot client
  106. rssbot := createRSSClient(t, feedURL)
  107. feed := rssbot.Feeds[feedURL]
  108. feed.MustInclude.Title = []string{"Zelda"}
  109. rssbot.Feeds[feedURL] = feed
  110. _, items, _ := rssbot.queryFeed(feedURL)
  111. // Expect that we get no items if we filter for 'Zelda' in title
  112. if len(items) != 0 {
  113. t.Errorf("Expected 0 items, got %v", items)
  114. }
  115. // Recreate rssbot client
  116. rssbot = createRSSClient(t, feedURL)
  117. feed = rssbot.Feeds[feedURL]
  118. feed.MustInclude.Title = []string{"Majora"}
  119. rssbot.Feeds[feedURL] = feed
  120. _, items, _ = rssbot.queryFeed(feedURL)
  121. // Expect one item if we filter for 'Majora' in title
  122. if len(items) != 1 {
  123. t.Errorf("Expected 1 item, got %d", len(items))
  124. }
  125. // Recreate rssbot client
  126. rssbot = createRSSClient(t, feedURL)
  127. feed = rssbot.Feeds[feedURL]
  128. feed.MustNotInclude.Author = []string{"kid"}
  129. rssbot.Feeds[feedURL] = feed
  130. _, items, _ = rssbot.queryFeed(feedURL)
  131. // 'kid' does not match an entire word in the author name, so it's not filtered
  132. if len(items) != 1 {
  133. t.Errorf("Expected 1 item, got %d", len(items))
  134. }
  135. // Recreate rssbot client
  136. rssbot = createRSSClient(t, feedURL)
  137. feed = rssbot.Feeds[feedURL]
  138. feed.MustNotInclude.Author = []string{"Skullkid"}
  139. rssbot.Feeds[feedURL] = feed
  140. _, items, _ = rssbot.queryFeed(feedURL)
  141. // Expect no items if we filter for 'Skullkid' not in author name
  142. if len(items) != 0 {
  143. t.Errorf("Expected 0 items, got %v", items)
  144. }
  145. }