blob: a5f39777ac55de6a6c10356d11df7caf1c722d18 [file] [log] [blame]
Sergiusz Bazanski325e9472019-09-27 02:49:47 +02001package main
2
3import (
4 "context"
5 "regexp"
6 "testing"
7 "time"
8)
9
10func makeDut() (*dispatcher, context.CancelFunc, context.Context) {
11 dut := newDispatcher()
12
13 ctx := context.Background()
14 ctxC, cancelCtx := context.WithCancel(ctx)
15 go dut.run(ctxC)
16
17 return dut, cancelCtx, ctx
18}
19
20func expectReceived(t *testing.T, s *sms, data chan *sms) {
21 ticker := time.NewTicker(100 * time.Millisecond)
22 defer ticker.Stop()
23 select {
24 case d := <-data:
25 if d.from != s.from {
26 t.Errorf("Received SMS from %q, wanted %q", d.from, s.from)
27 }
28 if d.body != s.body {
29 t.Errorf("Received SMS body %q, wanted %q", d.body, s.body)
30 }
31 if d.timestamp != s.timestamp {
32 t.Errorf("Received SMS timestamp %v, wanted %v", d.timestamp, s.timestamp)
33 }
34 case <-ticker.C:
35 t.Fatalf("Timed out waiting for message")
36 }
37}
38
39func expectEmpty(t *testing.T, data chan *sms) {
40 ticker := time.NewTicker(1 * time.Millisecond)
41 defer ticker.Stop()
42 select {
43 case <-data:
44 t.Fatalf("Received unwanted message")
45 case <-ticker.C:
46 }
47}
48
49func TestDispatcher(t *testing.T) {
50 dut, cancelDut, _ := makeDut()
51 defer cancelDut()
52
53 data := make(chan *sms)
54 cancel := make(chan struct{})
55
56 dut.subscribe(&subscriber{
57 re: regexp.MustCompile(".*"),
58 data: data,
59 cancel: cancel,
60 })
61
62 in := &sms{
63 from: "+4821372137",
64 body: "foo",
65 timestamp: time.Now(),
66 }
67 dut.publish(in)
68
69 // Make sure we ge the message.
70 expectReceived(t, in, data)
71
72 // Make sure we don't receive the message again.
73 expectEmpty(t, data)
74
75 // Publish a new message, but this time close our subscriber.
76 close(cancel)
77 // Hack: yield.
78 time.Sleep(1 * time.Millisecond)
79
80 dut.publish(in)
81 expectEmpty(t, data)
82}
83
84type testSubscriber struct {
85 re *regexp.Regexp
86 data chan *sms
87 cancel chan struct{}
88}
89
90func TestDispatcherFilters(t *testing.T) {
91 dut, cancelDut, _ := makeDut()
92 defer cancelDut()
93
94 subscribers := []*testSubscriber{
95 {re: regexp.MustCompile(".*")},
96 {re: regexp.MustCompile("foo")},
97 {re: regexp.MustCompile("bar")},
98 }
99
100 for _, s := range subscribers {
101 s.data = make(chan *sms)
102 s.cancel = make(chan struct{})
103 dut.subscribe(&subscriber{
104 re: s.re,
105 data: s.data,
106 cancel: s.cancel,
107 })
108 defer func(c chan struct{}) {
109 close(c)
110 }(s.cancel)
111 }
112
113 in := &sms{
114 from: "+4821372137",
115 body: "foo",
116 timestamp: time.Now(),
117 }
118 dut.publish(in)
119 expectReceived(t, in, subscribers[0].data)
120 expectReceived(t, in, subscribers[1].data)
121 expectEmpty(t, subscribers[2].data)
122
123 in = &sms{
124 from: "+4821372137",
125 body: "bar",
126 timestamp: time.Now(),
127 }
128 dut.publish(in)
129 expectReceived(t, in, subscribers[0].data)
130 expectEmpty(t, subscribers[1].data)
131 expectReceived(t, in, subscribers[2].data)
132
133 in = &sms{
134 from: "+4821372137",
135 body: "foobar",
136 timestamp: time.Now(),
137 }
138 dut.publish(in)
139 expectReceived(t, in, subscribers[0].data)
140 expectReceived(t, in, subscribers[1].data)
141 expectReceived(t, in, subscribers[2].data)
142}
143
144func TestDispatcherMany(t *testing.T) {
145 dut, cancelDut, _ := makeDut()
146 defer cancelDut()
147
148 subscribers := make([]*testSubscriber, 10000)
149
150 for i, _ := range subscribers {
151 s := &testSubscriber{
152 re: regexp.MustCompile(".*"),
153 data: make(chan *sms),
154 cancel: make(chan struct{}),
155 }
156 subscribers[i] = s
157 dut.subscribe(&subscriber{
158 re: s.re,
159 data: s.data,
160 cancel: s.cancel,
161 })
162 defer func(c chan struct{}) {
163 close(c)
164 }(s.cancel)
165 }
166
167 in := &sms{
168 from: "+4821372137",
169 body: "foo",
170 timestamp: time.Now(),
171 }
172 dut.publish(in)
173
174 for _, s := range subscribers {
175 expectReceived(t, in, s.data)
176 }
177}
178
179func TestDispatcherHammer(t *testing.T) {
180 dut, cancelDut, _ := makeDut()
181 defer cancelDut()
182
183 for i := 0; i < 1000000; i += 1 {
184 s := &testSubscriber{
185 re: regexp.MustCompile(".*"),
186 data: make(chan *sms),
187 cancel: make(chan struct{}),
188 }
189
190 dut.subscribe(&subscriber{
191 re: s.re,
192 data: s.data,
193 cancel: s.cancel,
194 })
195
196 in := &sms{
197 from: "+4821372137",
198 body: "foo",
199 timestamp: time.Now(),
200 }
201 dut.publish(in)
202 expectReceived(t, in, s.data)
203
204 close(s.cancel)
205 }
206}