]> git.scottworley.com Git - reliable-chat/blob - server/server_test.go
Link to the IRC,Better diagram in the README
[reliable-chat] / server / server_test.go
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
18 package main
19
20 import "testing"
21 import "runtime"
22 import "strconv"
23 import "time"
24
25 func 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
37 func TestMessageInsertAndRetreive(t *testing.T) {
38 id := "1"
39 say := "'Ello, Mister Polly Parrot!"
40 at := time.Now()
41 var zero_time time.Time
42 store := start_store()
43 store.Add <- &Message{at, id, say}
44 messages_from_store := make(chan []Message, 1)
45 store.Get <- &StoreRequest{zero_time, messages_from_store}
46 messages := <-messages_from_store
47 if len(messages) != 1 {
48 t.FailNow()
49 }
50 expectMessage(t, &messages[0], at, id, say)
51 close(store.Get)
52 close(store.Add)
53 }
54
55 func TestFetchBlocksUntilSpeak(t *testing.T) {
56 start_fetch_wait_count := fetch_wait_count.String()
57 id := "2"
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 }
67 store.Add <- &Message{at, id, say}
68 messages := <-messages_from_store
69 if len(messages) != 1 {
70 t.FailNow()
71 }
72 expectMessage(t, &messages[0], at, id, say)
73 close(store.Get)
74 close(store.Add)
75 }
76
77 func TestMultipleListeners(t *testing.T) {
78 id := "3"
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 }
89 store.Add <- &Message{at, id, say}
90 for i := 0; i < num_clients; i++ {
91 messages := <-messages_from_store[i]
92 if len(messages) != 1 {
93 t.FailNow()
94 }
95 expectMessage(t,& messages[0], at, id, say)
96 }
97 close(store.Get)
98 close(store.Add)
99 }
100
101 func parseDuration(s string) time.Duration {
102 d, err := time.ParseDuration(s)
103 if err != nil {
104 panic(err)
105 }
106 return d
107 }
108
109 func atoi(s string) int {
110 i, err := strconv.Atoi(s)
111 if err != nil {
112 panic(err)
113 }
114 return i
115 }
116
117 func TestPartialRetreive(t *testing.T) {
118 start_speak_count := atoi(speak_count.String())
119 id1 := "4"
120 id2 := "5"
121 id3 := "6"
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()
131 store.Add <- &Message{at1, id1, say1}
132 store.Add <- &Message{at2, id2, say2}
133 store.Add <- &Message{at3, id3, say3}
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 }
143 expectMessage(t, &messages[0], at2, id2, say2)
144 expectMessage(t, &messages[1], at3, id3, say3)
145 close(store.Get)
146 close(store.Add)
147 }
148
149 func TestPrecisePartialRetreive(t *testing.T) {
150 start_speak_count := atoi(speak_count.String())
151 id1 := "7"
152 id2 := "8"
153 id3 := "9"
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()
163 store.Add <- &Message{at1, id1, say1}
164 store.Add <- &Message{at2, id2, say2}
165 store.Add <- &Message{at3, id3, say3}
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 }
175 expectMessage(t, &messages[0], at3, id3, say3)
176 close(store.Get)
177 close(store.Add)
178 }
179
180 func TestTypicalFlow(t *testing.T) {
181 id1 := "10"
182 id2 := "11"
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()
198 store.Add <- &Message{at1, id1, say1}
199 messages1 := <-fetch1
200 if len(messages1) != 1 {
201 t.FailNow()
202 }
203 expectMessage(t, &messages1[0], at1, id1, say1)
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 }
218 store.Add <- &Message{at2, id2, say2}
219 messages2 := <-fetch2
220 if len(messages2) != 1 {
221 t.FailNow()
222 }
223 expectMessage(t, &messages2[0], at2, id2, say2)
224
225 close(store.Get)
226 close(store.Add)
227 }