]> git.scottworley.com Git - reliable-chat/blame - server/server_test.go
Link to the IRC,Better diagram in the README
[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()
b199796a 43 store.Add <- &Message{at, id, say}
cc9bd370 44 messages_from_store := make(chan []Message, 1)
fa5e7c1b 45 store.Get <- &StoreRequest{zero_time, messages_from_store}
cc9bd370
SW
46 messages := <-messages_from_store
47 if len(messages) != 1 {
d69a32e6 48 t.FailNow()
cc9bd370 49 }
1c425518 50 expectMessage(t, &messages[0], at, id, say)
c282d878
SW
51 close(store.Get)
52 close(store.Add)
cc9bd370 53}
ca612dcb
SW
54
55func TestFetchBlocksUntilSpeak(t *testing.T) {
56 start_fetch_wait_count := fetch_wait_count.String()
b199796a 57 id := "2"
ca612dcb
SW
58 say := "I've got a lovely fresh cuttle fish for you"
59 at := time.Now()
60 var zero_time time.Time
61 store := start_store()
62 messages_from_store := make(chan []Message, 1)
63 store.Get <- &StoreRequest{zero_time, messages_from_store}
64 for start_fetch_wait_count == fetch_wait_count.String() {
65 runtime.Gosched()
66 }
b199796a 67 store.Add <- &Message{at, id, say}
ca612dcb
SW
68 messages := <-messages_from_store
69 if len(messages) != 1 {
d69a32e6 70 t.FailNow()
ca612dcb 71 }
1c425518 72 expectMessage(t, &messages[0], at, id, say)
ca612dcb
SW
73 close(store.Get)
74 close(store.Add)
75}
d4039f63
SW
76
77func TestMultipleListeners(t *testing.T) {
b199796a 78 id := "3"
d4039f63
SW
79 say := "This is your nine o'clock alarm call!"
80 at := time.Now()
81 var zero_time time.Time
82 store := start_store()
83 const num_clients = 13
84 var messages_from_store [num_clients]chan []Message
85 for i := 0; i < num_clients; i++ {
86 messages_from_store[i] = make(chan []Message, 1)
87 store.Get <- &StoreRequest{zero_time, messages_from_store[i]}
88 }
b199796a 89 store.Add <- &Message{at, id, say}
d4039f63
SW
90 for i := 0; i < num_clients; i++ {
91 messages := <-messages_from_store[i]
92 if len(messages) != 1 {
d69a32e6 93 t.FailNow()
d4039f63 94 }
1c425518 95 expectMessage(t,& messages[0], at, id, say)
d4039f63
SW
96 }
97 close(store.Get)
98 close(store.Add)
99}
d69a32e6
SW
100
101func parseDuration(s string) time.Duration {
102 d, err := time.ParseDuration(s)
103 if err != nil {
104 panic(err)
105 }
106 return d
107}
108
109func atoi(s string) int {
110 i, err := strconv.Atoi(s)
111 if err != nil {
112 panic(err)
113 }
114 return i
115}
116
117func TestPartialRetreive(t *testing.T) {
118 start_speak_count := atoi(speak_count.String())
b199796a
SW
119 id1 := "4"
120 id2 := "5"
121 id3 := "6"
d69a32e6
SW
122 say1 := "No, no.....No, 'e's stunned!"
123 say2 := "You stunned him, just as he was wakin' up!"
124 say3 := "Norwegian Blues stun easily, major."
125 base := time.Now()
126 at1 := base.Add(parseDuration("-4m"))
127 since := base.Add(parseDuration("-3m"))
128 at2 := base.Add(parseDuration("-2m"))
129 at3 := base.Add(parseDuration("-1m"))
130 store := start_store()
b199796a
SW
131 store.Add <- &Message{at1, id1, say1}
132 store.Add <- &Message{at2, id2, say2}
133 store.Add <- &Message{at3, id3, say3}
d69a32e6
SW
134 for atoi(speak_count.String()) != start_speak_count+3 {
135 runtime.Gosched()
136 }
137 messages_from_store := make(chan []Message, 1)
138 store.Get <- &StoreRequest{since, messages_from_store}
139 messages := <-messages_from_store
140 if len(messages) != 2 {
141 t.FailNow()
142 }
1c425518
SW
143 expectMessage(t, &messages[0], at2, id2, say2)
144 expectMessage(t, &messages[1], at3, id3, say3)
d69a32e6
SW
145 close(store.Get)
146 close(store.Add)
147}
6e7f760f
SW
148
149func TestPrecisePartialRetreive(t *testing.T) {
150 start_speak_count := atoi(speak_count.String())
b199796a
SW
151 id1 := "7"
152 id2 := "8"
153 id3 := "9"
6e7f760f
SW
154 say1 := "Well, he's...he's, ah...probably pining for the fjords."
155 say2 := "PININ' for the FJORDS?!?!?!?"
156 say3 := "look, why did he fall flat on his back the moment I got 'im home?"
157 base := time.Now()
158 at1 := base.Add(parseDuration("-3m"))
159 at2 := base.Add(parseDuration("-2m"))
160 at3 := base.Add(parseDuration("-1m"))
161 since := at2
162 store := start_store()
b199796a
SW
163 store.Add <- &Message{at1, id1, say1}
164 store.Add <- &Message{at2, id2, say2}
165 store.Add <- &Message{at3, id3, say3}
6e7f760f
SW
166 for atoi(speak_count.String()) != start_speak_count+3 {
167 runtime.Gosched()
168 }
169 messages_from_store := make(chan []Message, 1)
170 store.Get <- &StoreRequest{since, messages_from_store}
171 messages := <-messages_from_store
172 if len(messages) != 1 {
173 t.FailNow()
174 }
1c425518 175 expectMessage(t, &messages[0], at3, id3, say3)
6e7f760f
SW
176 close(store.Get)
177 close(store.Add)
178}
179
180func TestTypicalFlow(t *testing.T) {
b199796a
SW
181 id1 := "10"
182 id2 := "11"
6e7f760f
SW
183 say1 := "The Norwegian Blue prefers kippin' on it's back!"
184 say2 := "Remarkable bird, innit, squire? Lovely plumage!"
185 store := start_store()
186
187 // A waiting zero-time fetch.
188 var zero_time time.Time
189 prev_fetch_wait_count := fetch_wait_count.String()
190 fetch1 := make(chan []Message, 1)
191 store.Get <- &StoreRequest{zero_time, fetch1}
192 for prev_fetch_wait_count == fetch_wait_count.String() {
193 runtime.Gosched()
194 }
195
196 // Someone speaks. This triggers delivery.
197 at1 := time.Now()
b199796a 198 store.Add <- &Message{at1, id1, say1}
6e7f760f
SW
199 messages1 := <-fetch1
200 if len(messages1) != 1 {
201 t.FailNow()
202 }
1c425518 203 expectMessage(t, &messages1[0], at1, id1, say1)
6e7f760f
SW
204
205 // Upon recipt, client blocks on fetch with since=at1
206 prev_fetch_wait_count = fetch_wait_count.String()
207 fetch2 := make(chan []Message, 1)
208 store.Get <- &StoreRequest{at1, fetch2}
209 for prev_fetch_wait_count == fetch_wait_count.String() {
210 runtime.Gosched()
211 }
212
213 // Someone speaks again. This triggers another delivery.
214 at2 := time.Now()
215 if !at2.After(at1) {
216 t.Fail()
217 }
b199796a 218 store.Add <- &Message{at2, id2, say2}
6e7f760f
SW
219 messages2 := <-fetch2
220 if len(messages2) != 1 {
221 t.FailNow()
222 }
1c425518 223 expectMessage(t, &messages2[0], at2, id2, say2)
6e7f760f
SW
224
225 close(store.Get)
226 close(store.Add)
227}