main_test.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. package main
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "io/ioutil"
  7. "net/http"
  8. "net/http/httptest"
  9. "os"
  10. "strings"
  11. "sync"
  12. "sync/atomic"
  13. "syscall"
  14. "testing"
  15. "time"
  16. log "github.com/go-pkgz/lgr"
  17. "github.com/stretchr/testify/assert"
  18. "github.com/stretchr/testify/require"
  19. "git.lattuga.net/boyska/rss2twitter/app/rss"
  20. )
  21. func TestMain(t *testing.T) {
  22. var n int32
  23. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  24. log.Printf("req %+v", r)
  25. fnum := atomic.AddInt32(&n, int32(1))
  26. if fnum > 2 {
  27. fnum = 2
  28. }
  29. data, err := ioutil.ReadFile(fmt.Sprintf("rss/testdata/f%d.xml", fnum))
  30. require.NoError(t, err)
  31. w.WriteHeader(200)
  32. w.Write(data)
  33. }))
  34. defer ts.Close()
  35. os.Args = []string{"app", "--feed=" + ts.URL + "/rss", "--dry", "--dbg", "--refresh=100ms"}
  36. go func() {
  37. time.Sleep(500 * time.Millisecond)
  38. err := syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
  39. require.Nil(t, err, "kill")
  40. }()
  41. wg := sync.WaitGroup{}
  42. wg.Add(1)
  43. go func() {
  44. st := time.Now()
  45. main()
  46. require.True(t, time.Since(st).Seconds() < 1, "should take about 500msec")
  47. wg.Done()
  48. }()
  49. wg.Wait()
  50. }
  51. func TestSetupDry(t *testing.T) {
  52. o := opts{Feed: "http://example.com", Dry: true}
  53. n, p, err := setup(o)
  54. require.NoError(t, err)
  55. assert.NotNil(t, n)
  56. assert.Equal(t, "publisher.Stdout", fmt.Sprintf("%T", p))
  57. }
  58. func TestSetupFull(t *testing.T) {
  59. o := opts{Feed: "http://example.com", Dry: false,
  60. ConsumerKey: "1", ConsumerSecret: "1", AccessToken: "1", AccessSecret: "1"}
  61. n, p, err := setup(o)
  62. require.NoError(t, err)
  63. assert.NotNil(t, n)
  64. assert.Equal(t, "publisher.Twitter", fmt.Sprintf("%T", p))
  65. }
  66. func TestSetupFailed(t *testing.T) {
  67. o := opts{Feed: "http://example.com", Dry: false,
  68. ConsumerKey: "1", ConsumerSecret: "1"}
  69. _, _, err := setup(o)
  70. assert.NotNil(t, err)
  71. }
  72. func TestDo(t *testing.T) {
  73. pub := pubMock{buf: bytes.Buffer{}}
  74. notif := notifierMock{delay: 100 * time.Millisecond, events: []rss.Event{
  75. {GUID: "1", Title: "t1", Link: "l1", Text: "ttt2"},
  76. {GUID: "2", Title: "t2", Link: "l2", Text: "ttt2"},
  77. {GUID: "3", Title: "t4", Link: "l3", Text: "ttt3"},
  78. }}
  79. ctx, cancel := context.WithCancel(context.Background())
  80. do(ctx, &notif, &pub, "{{.Title}} - {{.Link}}")
  81. cancel()
  82. assert.Equal(t, "t1 - l1\nt2 - l2\nt4 - l3\n", pub.buf.String())
  83. }
  84. func TestDoCanceled(t *testing.T) {
  85. pub := pubMock{buf: bytes.Buffer{}}
  86. notif := notifierMock{delay: 100 * time.Millisecond, events: []rss.Event{
  87. {GUID: "1", Title: "t1", Link: "l1", Text: "ttt2"},
  88. {GUID: "2", Title: "t2", Link: "l2", Text: "ttt2"},
  89. {GUID: "3", Title: "t4", Link: "l3", Text: "ttt3"},
  90. }}
  91. ctx, cancel := context.WithCancel(context.Background())
  92. time.AfterFunc(time.Millisecond*150, func() { cancel() })
  93. do(ctx, &notif, &pub, "{{.Title}} - {{.Link}} {{.Text}}")
  94. assert.Equal(t, "t1 - l1 ttt2\n", pub.buf.String())
  95. }
  96. func TestFormat(t *testing.T) {
  97. tbl := []struct {
  98. inp string
  99. out string
  100. size int
  101. }{
  102. {"blah", "blah", 100},
  103. {"blah <p>xyx</p>", "blah xyx", 100},
  104. {"blah <p>xyx</p> something 122 abcdefg 12345 qwer", "blah xyx ...", 15},
  105. {"blah <p>xyx</p> something 122 abcdefg 12345 qwerty", "blah xyx something ...", 20},
  106. {"<p>xyx</p><title>", "xyx", 20},
  107. }
  108. for i, tt := range tbl {
  109. t.Run(fmt.Sprintf("check-%d", i), func(t *testing.T) {
  110. out := format(tt.inp, tt.size)
  111. assert.Equal(t, tt.out, out)
  112. })
  113. }
  114. }
  115. func TestGetDump(t *testing.T) {
  116. dump := getDump()
  117. assert.True(t, strings.Contains(dump, "goroutine"))
  118. assert.True(t, strings.Contains(dump, "[running]"))
  119. assert.True(t, strings.Contains(dump, "app/main.go"))
  120. log.Printf("\n dump: %s", dump)
  121. }
  122. type pubMock struct {
  123. buf bytes.Buffer
  124. }
  125. func (m *pubMock) Publish(event rss.Event, formatter func(rss.Event) string) error {
  126. _, err := m.buf.WriteString(formatter(event) + "\n")
  127. return err
  128. }
  129. type notifierMock struct {
  130. events []rss.Event
  131. delay time.Duration
  132. }
  133. func (m *notifierMock) Go(ctx context.Context) <-chan rss.Event {
  134. ch := make(chan rss.Event)
  135. go func() {
  136. for _, e := range m.events {
  137. select {
  138. case <-ctx.Done():
  139. break
  140. case <-time.After(m.delay):
  141. ch <- e
  142. }
  143. }
  144. close(ch)
  145. }()
  146. return ch
  147. }