]> git.scottworley.com Git - reliable-chat/blame - server/server_test.go
Test message drops due to hitting the limit
[reliable-chat] / server / server_test.go
CommitLineData
520c21fd
SW
1/* reliable-chat - multipath chat
2 * Copyright (C) 2012 Scott Worley <sworley@chkno.net>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation, either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
cc9bd370
SW
18package main
19
20import "testing"
ca612dcb 21import "runtime"
d69a32e6 22import "strconv"
cc9bd370
SW
23import "time"
24
1c425518
SW
25func expectMessage(t *testing.T, m *Message, at time.Time, id, say string) {
26 if m.Time != at {
27 t.Fail()
28 }
29 if m.ID != id {
30 t.Fail()
31 }
32 if m.Text != say {
33 t.Fail()
34 }
35}
36
cc9bd370 37func TestMessageInsertAndRetreive(t *testing.T) {
b199796a 38 id := "1"
ca612dcb 39 say := "'Ello, Mister Polly Parrot!"
cc9bd370
SW
40 at := time.Now()
41 var zero_time time.Time
42 store := start_store()
70a65c05
SW
43 defer func() {
44 close(store.Get)
45 close(store.Add)
46 }()
47
b199796a 48 store.Add <- &Message{at, id, say}
cc9bd370 49 messages_from_store := make(chan []Message, 1)
fa5e7c1b 50 store.Get <- &StoreRequest{zero_time, messages_from_store}
cc9bd370
SW
51 messages := <-messages_from_store
52 if len(messages) != 1 {
d69a32e6 53 t.FailNow()
cc9bd370 54 }
1c425518 55 expectMessage(t, &messages[0], at, id, say)
cc9bd370 56}
ca612dcb
SW
57
58func TestFetchBlocksUntilSpeak(t *testing.T) {
59 start_fetch_wait_count := fetch_wait_count.String()
b199796a 60 id := "2"
ca612dcb
SW
61 say := "I've got a lovely fresh cuttle fish for you"
62 at := time.Now()
63 var zero_time time.Time
64 store := start_store()
70a65c05
SW
65 defer func() {
66 close(store.Get)
67 close(store.Add)
68 }()
69
ca612dcb
SW
70 messages_from_store := make(chan []Message, 1)
71 store.Get <- &StoreRequest{zero_time, messages_from_store}
72 for start_fetch_wait_count == fetch_wait_count.String() {
73 runtime.Gosched()
74 }
b199796a 75 store.Add <- &Message{at, id, say}
ca612dcb
SW
76 messages := <-messages_from_store
77 if len(messages) != 1 {
d69a32e6 78 t.FailNow()
ca612dcb 79 }
1c425518 80 expectMessage(t, &messages[0], at, id, say)
ca612dcb 81}
d4039f63
SW
82
83func TestMultipleListeners(t *testing.T) {
b199796a 84 id := "3"
d4039f63
SW
85 say := "This is your nine o'clock alarm call!"
86 at := time.Now()
87 var zero_time time.Time
88 store := start_store()
70a65c05
SW
89 defer func() {
90 close(store.Get)
91 close(store.Add)
92 }()
93
d4039f63
SW
94 const num_clients = 13
95 var messages_from_store [num_clients]chan []Message
96 for i := 0; i < num_clients; i++ {
97 messages_from_store[i] = make(chan []Message, 1)
98 store.Get <- &StoreRequest{zero_time, messages_from_store[i]}
99 }
b199796a 100 store.Add <- &Message{at, id, say}
d4039f63
SW
101 for i := 0; i < num_clients; i++ {
102 messages := <-messages_from_store[i]
103 if len(messages) != 1 {
d69a32e6 104 t.FailNow()
d4039f63 105 }
67dc084d 106 expectMessage(t, &messages[0], at, id, say)
d4039f63 107 }
d4039f63 108}
d69a32e6
SW
109
110func parseDuration(s string) time.Duration {
111 d, err := time.ParseDuration(s)
112 if err != nil {
113 panic(err)
114 }
115 return d
116}
117
118func atoi(s string) int {
119 i, err := strconv.Atoi(s)
120 if err != nil {
121 panic(err)
122 }
123 return i
124}
125
126func TestPartialRetreive(t *testing.T) {
127 start_speak_count := atoi(speak_count.String())
b199796a
SW
128 id1 := "4"
129 id2 := "5"
130 id3 := "6"
d69a32e6
SW
131 say1 := "No, no.....No, 'e's stunned!"
132 say2 := "You stunned him, just as he was wakin' up!"
133 say3 := "Norwegian Blues stun easily, major."
134 base := time.Now()
135 at1 := base.Add(parseDuration("-4m"))
136 since := base.Add(parseDuration("-3m"))
137 at2 := base.Add(parseDuration("-2m"))
138 at3 := base.Add(parseDuration("-1m"))
139 store := start_store()
70a65c05
SW
140 defer func() {
141 close(store.Get)
142 close(store.Add)
143 }()
144
b199796a
SW
145 store.Add <- &Message{at1, id1, say1}
146 store.Add <- &Message{at2, id2, say2}
147 store.Add <- &Message{at3, id3, say3}
d69a32e6
SW
148 for atoi(speak_count.String()) != start_speak_count+3 {
149 runtime.Gosched()
150 }
151 messages_from_store := make(chan []Message, 1)
152 store.Get <- &StoreRequest{since, messages_from_store}
153 messages := <-messages_from_store
154 if len(messages) != 2 {
155 t.FailNow()
156 }
1c425518
SW
157 expectMessage(t, &messages[0], at2, id2, say2)
158 expectMessage(t, &messages[1], at3, id3, say3)
d69a32e6 159}
6e7f760f
SW
160
161func TestPrecisePartialRetreive(t *testing.T) {
162 start_speak_count := atoi(speak_count.String())
b199796a
SW
163 id1 := "7"
164 id2 := "8"
165 id3 := "9"
6e7f760f
SW
166 say1 := "Well, he's...he's, ah...probably pining for the fjords."
167 say2 := "PININ' for the FJORDS?!?!?!?"
168 say3 := "look, why did he fall flat on his back the moment I got 'im home?"
169 base := time.Now()
170 at1 := base.Add(parseDuration("-3m"))
171 at2 := base.Add(parseDuration("-2m"))
172 at3 := base.Add(parseDuration("-1m"))
173 since := at2
174 store := start_store()
70a65c05
SW
175 defer func() {
176 close(store.Get)
177 close(store.Add)
178 }()
179
b199796a
SW
180 store.Add <- &Message{at1, id1, say1}
181 store.Add <- &Message{at2, id2, say2}
182 store.Add <- &Message{at3, id3, say3}
6e7f760f
SW
183 for atoi(speak_count.String()) != start_speak_count+3 {
184 runtime.Gosched()
185 }
186 messages_from_store := make(chan []Message, 1)
187 store.Get <- &StoreRequest{since, messages_from_store}
188 messages := <-messages_from_store
189 if len(messages) != 1 {
190 t.FailNow()
191 }
1c425518 192 expectMessage(t, &messages[0], at3, id3, say3)
6e7f760f
SW
193}
194
195func TestTypicalFlow(t *testing.T) {
b199796a
SW
196 id1 := "10"
197 id2 := "11"
6e7f760f
SW
198 say1 := "The Norwegian Blue prefers kippin' on it's back!"
199 say2 := "Remarkable bird, innit, squire? Lovely plumage!"
200 store := start_store()
70a65c05
SW
201 defer func() {
202 close(store.Get)
203 close(store.Add)
204 }()
6e7f760f
SW
205
206 // A waiting zero-time fetch.
207 var zero_time time.Time
208 prev_fetch_wait_count := fetch_wait_count.String()
209 fetch1 := make(chan []Message, 1)
210 store.Get <- &StoreRequest{zero_time, fetch1}
211 for prev_fetch_wait_count == fetch_wait_count.String() {
212 runtime.Gosched()
213 }
214
215 // Someone speaks. This triggers delivery.
216 at1 := time.Now()
b199796a 217 store.Add <- &Message{at1, id1, say1}
6e7f760f
SW
218 messages1 := <-fetch1
219 if len(messages1) != 1 {
220 t.FailNow()
221 }
1c425518 222 expectMessage(t, &messages1[0], at1, id1, say1)
6e7f760f
SW
223
224 // Upon recipt, client blocks on fetch with since=at1
225 prev_fetch_wait_count = fetch_wait_count.String()
226 fetch2 := make(chan []Message, 1)
227 store.Get <- &StoreRequest{at1, fetch2}
228 for prev_fetch_wait_count == fetch_wait_count.String() {
229 runtime.Gosched()
230 }
231
232 // Someone speaks again. This triggers another delivery.
233 at2 := time.Now()
234 if !at2.After(at1) {
235 t.Fail()
236 }
b199796a 237 store.Add <- &Message{at2, id2, say2}
6e7f760f
SW
238 messages2 := <-fetch2
239 if len(messages2) != 1 {
240 t.FailNow()
241 }
1c425518 242 expectMessage(t, &messages2[0], at2, id2, say2)
6e7f760f 243}
5295c28c
SW
244
245func TestExpiryDueToLimit(t *testing.T) {
246 previous_limit := *max_messages
247 defer func() { *max_messages = previous_limit }()
248 *max_messages = 2
249
250 start_speak_count := atoi(speak_count.String())
251 start_drop_count := atoi(drop_due_to_limit_count.String())
252 id1 := "12"
253 id2 := "13"
254 id3 := "14"
255 say1 := "'E's passed on!"
256 say2 := "This parrot is no more!"
257 say3 := "He has ceased to be!"
258 base := time.Now()
259 at1 := base.Add(parseDuration("-3m"))
260 at2 := base.Add(parseDuration("-2m"))
261 at3 := base.Add(parseDuration("-1m"))
262 store := start_store()
263 defer func() {
264 close(store.Get)
265 close(store.Add)
266 }()
267
268 store.Add <- &Message{at1, id1, say1}
269 store.Add <- &Message{at2, id2, say2}
270 store.Add <- &Message{at3, id3, say3}
271 for atoi(speak_count.String()) != start_speak_count+3 {
272 runtime.Gosched()
273 }
274 if atoi(drop_due_to_limit_count.String()) != start_drop_count+1 {
275 t.Fail()
276 }
277 messages_from_store := make(chan []Message, 1)
278 var zero_time time.Time
279 store.Get <- &StoreRequest{zero_time, messages_from_store}
280 messages := <-messages_from_store
281 if len(messages) != 2 {
282 t.FailNow()
283 }
284 expectMessage(t, &messages[0], at2, id2, say2)
285 expectMessage(t, &messages[1], at3, id3, say3)
286}