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