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