OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library scheduled_server_test; | 5 library scheduled_server_test; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:io'; | 8 import 'dart:io'; |
9 | 9 |
10 import 'package:http/http.dart' as http; | 10 import 'package:http/http.dart' as http; |
11 import 'package:scheduled_test/scheduled_server.dart'; | 11 import 'package:scheduled_test/scheduled_server.dart'; |
12 import 'package:scheduled_test/scheduled_test.dart'; | 12 import 'package:scheduled_test/scheduled_test.dart'; |
13 import 'package:scheduled_test/src/mock_clock.dart' as mock_clock; | 13 import 'package:scheduled_test/src/mock_clock.dart' as mock_clock; |
14 import 'package:shelf/shelf.dart' as shelf; | |
14 | 15 |
15 import 'metatest.dart'; | 16 import 'metatest.dart'; |
16 import 'utils.dart'; | 17 import 'utils.dart'; |
17 | 18 |
18 void main(_, message) { | 19 void main(_, message) { |
19 initMetatest(message); | 20 initMetatest(message); |
20 | 21 |
21 setUpTimeout(); | 22 setUpTimeout(); |
22 | 23 |
23 expectTestsPass("a server with no handlers does nothing", () { | 24 expectTestPasses("a server with no handlers does nothing", |
24 test('test', () => new ScheduledServer()); | 25 () => new ScheduledServer()); |
26 | |
27 expectServerError("a server with no handlers that receives a request throws " | |
28 "an error", () { | |
29 var server = new ScheduledServer(); | |
30 expect(server.url.then((url) => http.read(url.resolve('/hello'))), | |
31 completion(equals('Hello, test!'))); | |
32 }, "'scheduled server 0' received GET /hello when no more requests were " | |
33 "expected."); | |
34 | |
35 expectTestPasses("a handler runs when it's hit", () { | |
36 var server = new ScheduledServer(); | |
37 expect(server.url.then((url) => http.read(url.resolve('/hello'))), | |
38 completion(equals('Hello, test!'))); | |
39 | |
40 server.handle('GET', '/hello', | |
41 (request) => new shelf.Response.ok('Hello, test!')); | |
25 }); | 42 }); |
26 | 43 |
27 expectTestsPass("a server with no handlers that receives a request throws an " | 44 expectTestPasses("a handler blocks the schedule on the returned future", () { |
28 "error", () { | 45 var blockedOnFuture = false; |
29 var errors; | 46 var server = new ScheduledServer(); |
30 test('test 1', () { | 47 expect(server.url.then((url) => http.read(url.resolve('/hello'))), |
31 currentSchedule.onException.schedule(() { | 48 completion(equals('Hello, test!'))); |
32 errors = currentSchedule.errors; | |
33 }); | |
34 | 49 |
35 var server = new ScheduledServer(); | 50 server.handle('GET', '/hello', (request) { |
36 expect(server.url.then((url) => http.read(url.resolve('/hello'))), | 51 return pumpEventQueue().then((_) { |
37 completion(equals('Hello, test!'))); | 52 blockedOnFuture = true; |
38 }); | 53 return new shelf.Response.ok('Hello, test!'); |
39 | |
40 test('test 2', () { | |
41 expect(errors, everyElement(new isInstanceOf<ScheduleError>())); | |
42 expect(errors.length, 2); | |
43 expect(errors[0].error.toString(), equals("'scheduled server 0' received " | |
44 "GET /hello when no more requests were expected.")); | |
45 expect(errors[1].error, new isInstanceOf<HttpException>()); | |
46 }); | |
47 }, passing: ['test 2']); | |
48 | |
49 expectTestsPass("a handler runs when it's hit", () { | |
50 test('test', () { | |
51 var server = new ScheduledServer(); | |
52 expect(server.url.then((url) => http.read(url.resolve('/hello'))), | |
53 completion(equals('Hello, test!'))); | |
54 | |
55 server.handle('GET', '/hello', (request) { | |
56 request.response.write('Hello, test!'); | |
57 request.response.close(); | |
58 }); | |
59 }); | |
60 }); | |
61 | |
62 expectTestsPass("a handler blocks the schedule on the returned future", () { | |
63 test('test', () { | |
64 var blockedOnFuture = false; | |
65 var server = new ScheduledServer(); | |
66 expect(server.url.then((url) => http.read(url.resolve('/hello'))), | |
67 completion(equals('Hello, test!'))); | |
68 | |
69 server.handle('GET', '/hello', (request) { | |
70 request.response.write('Hello, test!'); | |
71 request.response.close(); | |
72 return pumpEventQueue().then((_) { | |
73 blockedOnFuture = true; | |
74 }); | |
75 }); | |
76 | |
77 schedule(() => expect(blockedOnFuture, isTrue)); | |
78 }); | |
79 }); | |
80 | |
81 expectTestsPass("a handler fails if it's hit too early", () { | |
82 var errors; | |
83 test('test 1', () { | |
84 currentSchedule.onException.schedule(() { | |
85 errors = currentSchedule.errors; | |
86 }); | |
87 | |
88 var server = new ScheduledServer(); | |
89 var response = server.url.then((url) => http.read(url.resolve('/hello'))); | |
90 expect(response, completion(equals('Hello, test!'))); | |
91 | |
92 // Block the schedule until we're sure the request has hit the server. | |
93 schedule(() => response); | |
94 | |
95 // Add a task's worth of space to avoid hitting the heuristic of waiting | |
96 // for the immediately-preceding task. | |
97 schedule(() => null); | |
98 | |
99 server.handle('GET', '/hello', (request) { | |
100 request.response.write('Hello, test!'); | |
101 request.response.close(); | |
102 }); | 54 }); |
103 }); | 55 }); |
104 | 56 |
105 test('test 2', () { | 57 schedule(() => expect(blockedOnFuture, isTrue)); |
106 // TODO(nweiz): There can be three errors due to issue 9151. The | |
107 // HttpException is reported without a stack trace, and so when it's | |
108 // wrapped twice it registers as a different exception each time (because | |
109 // it's given an ad-hoc stack trace). Always expect two exceptions when | |
110 // issue 9151 is fixed. | |
111 expect(errors.length, inInclusiveRange(2, 3)); | |
112 expect(errors[0].error.toString(), equals( | |
113 "'scheduled server 0' received GET /hello earlier than expected.")); | |
114 expect(errors[1].error, new isInstanceOf<HttpException>()); | |
115 if (errors.length > 2) { | |
116 expect(errors[2].error, new isInstanceOf<HttpException>()); | |
117 } | |
118 expect(errors, everyElement(new isInstanceOf<ScheduleError>())); | |
119 }); | |
120 }, passing: ['test 2']); | |
121 | |
122 expectTestsPass("a handler waits for the immediately prior task to complete " | |
123 "before checking if it's too early", () { | |
124 test('test', () { | |
125 var server = new ScheduledServer(); | |
126 expect(server.url.then((url) => http.read(url.resolve('/hello'))), | |
127 completion(equals('Hello, test!'))); | |
128 | |
129 // Sleeping here is unfortunate, but we want to be sure that the HTTP | |
130 // request hits the server during this test without actually blocking the | |
131 // task on the request completing. | |
132 // | |
133 // This is also a potential race condition, but hopefully a local HTTP | |
134 // request won't take 1s. | |
135 schedule(() => new Future.delayed(new Duration(seconds: 1))); | |
136 | |
137 server.handle('GET', '/hello', (request) { | |
138 request.response.write('Hello, test!'); | |
139 request.response.close(); | |
140 }); | |
141 }); | |
142 }); | 58 }); |
143 | 59 |
144 expectTestsPass("a handler fails if the url is wrong", () { | 60 expectServerError("a handler fails if it's hit too early", () { |
145 var errors; | 61 var server = new ScheduledServer(); |
146 test('test 1', () { | 62 var response = server.url.then((url) => http.read(url.resolve('/hello'))); |
147 currentSchedule.onException.schedule(() { | 63 expect(response, completion(equals('Hello, test!'))); |
148 errors = currentSchedule.errors; | |
149 }); | |
150 | 64 |
151 var server = new ScheduledServer(); | 65 // Block the schedule until we're sure the request has hit the server. |
152 expect(server.url.then((url) => http.read(url.resolve('/hello'))), | 66 schedule(() => response); |
153 completion(equals('Hello, test!'))); | |
154 | 67 |
155 server.handle('GET', '/goodbye', (request) { | 68 // Add a task's worth of space to avoid hitting the heuristic of waiting |
Bob Nystrom
2014/04/02 23:55:30
What does "a task's worth of space" mean here?
nweiz
2014/04/03 00:34:09
Clarified.
| |
156 request.response.write('Goodbye, test!'); | 69 // for the immediately-preceding task. |
157 request.response.close(); | 70 schedule(() => null); |
158 }); | |
159 }); | |
160 | 71 |
161 test('test 2', () { | 72 server.handle('GET', '/hello', |
162 expect(errors.length, 2); | 73 (request) => new shelf.Response.ok('Hello, test!')); |
163 expect(errors[0].error.toString(), equals( | 74 }, "'scheduled server 0' received GET /hello earlier than expected."); |
164 "'scheduled server 0' expected GET /goodbye, but got GET /hello.")); | |
165 expect(errors[1].error, new isInstanceOf<HttpException>()); | |
166 }); | |
167 }, passing: ['test 2']); | |
168 | 75 |
169 expectTestsPass("a handler fails if the method is wrong", () { | 76 expectTestPasses("a handler waits for the immediately prior task to complete " |
170 var errors; | 77 "before checking if it's too early", () { |
171 test('test 1', () { | 78 var server = new ScheduledServer(); |
172 currentSchedule.onException.schedule(() { | 79 expect(server.url.then((url) => http.read(url.resolve('/hello'))), |
173 errors = currentSchedule.errors; | 80 completion(equals('Hello, test!'))); |
174 }); | |
175 | 81 |
176 var server = new ScheduledServer(); | 82 // Sleeping here is unfortunate, but we want to be sure that the HTTP |
177 expect(server.url.then((url) => http.head(url.resolve('/hello'))), | 83 // request hits the server during this test without actually blocking the |
178 completes); | 84 // task on the request completing. |
85 // | |
86 // This is also a potential race condition, but hopefully a local HTTP | |
87 // request won't take 1s. | |
88 schedule(() => new Future.delayed(new Duration(seconds: 1))); | |
Bob Nystrom
2014/04/02 23:55:30
1s is pretty brutal. Can this be cranked down a bi
nweiz
2014/04/03 00:34:09
Done.
| |
179 | 89 |
180 server.handle('GET', '/hello', (request) { | 90 server.handle('GET', '/hello', |
181 request.response.write('Hello, test!'); | 91 (request) => new shelf.Response.ok('Hello, test!')); |
182 request.response.close(); | 92 }); |
183 }); | |
184 }); | |
185 | 93 |
186 test('test 2', () { | 94 expectServerError("a handler fails if the url is wrong", () { |
187 expect(errors.length, 2); | 95 var server = new ScheduledServer(); |
188 expect(errors[0].error.toString(), equals( | 96 expect(server.url.then((url) => http.read(url.resolve('/hello'))), |
189 "'scheduled server 0' expected GET /hello, but got HEAD /hello.")); | 97 completion(equals('Hello, test!'))); |
190 expect(errors[1].error, new isInstanceOf<HttpException>()); | 98 |
191 }); | 99 server.handle('GET', '/goodbye', |
192 }, passing: ['test 2']); | 100 (request) => new shelf.Response.ok('Goodbye, test!')); |
101 }, "'scheduled server 0' expected GET /goodbye, but got GET /hello."); | |
102 | |
103 expectServerError("a handler fails if the method is wrong", () { | |
104 var server = new ScheduledServer(); | |
105 expect(server.url.then((url) => http.head(url.resolve('/hello'))), | |
106 completes); | |
107 | |
108 server.handle('GET', '/hello', | |
109 (request) => new shelf.Response.ok('Hello, test!')); | |
110 }, "'scheduled server 0' expected GET /hello, but got HEAD /hello."); | |
193 | 111 |
194 expectTestsPass("a handler times out waiting to be hit", () { | 112 expectTestsPass("a handler times out waiting to be hit", () { |
195 var clock = mock_clock.mock()..run(); | 113 var clock = mock_clock.mock()..run(); |
196 var timeOfException; | 114 var timeOfException; |
197 var errors; | 115 var errors; |
198 test('test 1', () { | 116 test('test 1', () { |
199 currentSchedule.timeout = new Duration(milliseconds: 2); | 117 currentSchedule.timeout = new Duration(milliseconds: 2); |
200 currentSchedule.onException.schedule(() { | 118 currentSchedule.onException.schedule(() { |
201 timeOfException = clock.time; | 119 timeOfException = clock.time; |
202 errors = currentSchedule.errors; | 120 errors = currentSchedule.errors; |
203 }); | 121 }); |
204 | 122 |
205 var server = new ScheduledServer(); | 123 var server = new ScheduledServer(); |
206 | 124 |
207 server.handle('GET', '/hello', (request) { | 125 server.handle('GET', '/hello', |
208 request.response.write('Hello, test!'); | 126 (request) => new shelf.Response.ok('Hello, test!')); |
209 request.response.close(); | |
210 }); | |
211 }); | 127 }); |
212 | 128 |
213 test('test 2', () { | 129 test('test 2', () { |
214 expect(clock.time, equals(2)); | 130 expect(clock.time, equals(2)); |
215 | 131 |
216 expect(errors.single, new isInstanceOf<ScheduleError>()); | 132 expect(errors.single, new isInstanceOf<ScheduleError>()); |
217 expect(errors.single.error.toString(), equals( | 133 expect(errors.single.error.toString(), equals( |
218 "The schedule timed out after 0:00:00.002000 of inactivity.")); | 134 "The schedule timed out after 0:00:00.002000 of inactivity.")); |
219 }); | 135 }); |
220 }, passing: ['test 2']); | 136 }, passing: ['test 2']); |
221 | 137 |
222 expectTestsPass("multiple handlers in series respond to requests in series", | 138 expectTestPasses("multiple handlers in series respond to requests in series", |
223 () { | 139 () { |
224 test('test', () { | 140 var server = new ScheduledServer(); |
225 var server = new ScheduledServer(); | 141 expect(server.url.then((url) { |
226 expect(server.url.then((url) { | 142 return http.read(url.resolve('/hello/1')).then((response) { |
227 return http.read(url.resolve('/hello/1')).then((response) { | 143 expect(response, equals('Hello, request 1!')); |
228 expect(response, equals('Hello, request 1!')); | 144 return http.read(url.resolve('/hello/2')); |
229 return http.read(url.resolve('/hello/2')); | 145 }).then((response) { |
230 }).then((response) { | 146 expect(response, equals('Hello, request 2!')); |
231 expect(response, equals('Hello, request 2!')); | 147 return http.read(url.resolve('/hello/3')); |
232 return http.read(url.resolve('/hello/3')); | 148 }).then((response) => expect(response, equals('Hello, request 3!'))); |
233 }).then((response) => expect(response, equals('Hello, request 3!'))); | 149 }), completes); |
234 }), completes); | |
235 | 150 |
236 server.handle('GET', '/hello/1', (request) { | 151 server.handle('GET', '/hello/1', |
237 request.response.write('Hello, request 1!'); | 152 (request) => new shelf.Response.ok('Hello, request 1!')); |
238 request.response.close(); | |
239 }); | |
240 | 153 |
241 server.handle('GET', '/hello/2', (request) { | 154 server.handle('GET', '/hello/2', |
242 request.response.write('Hello, request 2!'); | 155 (request) => new shelf.Response.ok('Hello, request 2!')); |
243 request.response.close(); | |
244 }); | |
245 | 156 |
246 server.handle('GET', '/hello/3', (request) { | 157 server.handle('GET', '/hello/3', |
247 request.response.write('Hello, request 3!'); | 158 (request) => new shelf.Response.ok('Hello, request 3!')); |
248 request.response.close(); | |
249 }); | |
250 }); | |
251 }); | 159 }); |
252 | 160 |
253 expectTestsPass("a server that receives a request after all its handlers " | 161 expectServerError("a server that receives a request after all its handlers " |
254 "have run throws an error", () { | 162 "have run throws an error", () { |
255 var errors; | 163 var server = new ScheduledServer(); |
256 test('test 1', () { | 164 expect(server.url.then((url) { |
257 currentSchedule.onException.schedule(() { | 165 return http.read(url.resolve('/hello/1')).then((response) { |
258 errors = currentSchedule.errors; | 166 expect(response, equals('Hello, request 1!')); |
259 }); | 167 return http.read(url.resolve('/hello/2')); |
168 }).then((response) { | |
169 expect(response, equals('Hello, request 2!')); | |
170 return http.read(url.resolve('/hello/3')); | |
171 }).then((response) => expect(response, equals('Hello, request 3!'))); | |
172 }), completes); | |
260 | 173 |
261 var server = new ScheduledServer(); | 174 server.handle('GET', '/hello/1', |
262 expect(server.url.then((url) { | 175 (request) => new shelf.Response.ok('Hello, request 1!')); |
263 return http.read(url.resolve('/hello/1')).then((response) { | |
264 expect(response, equals('Hello, request 1!')); | |
265 return http.read(url.resolve('/hello/2')); | |
266 }).then((response) { | |
267 expect(response, equals('Hello, request 2!')); | |
268 return http.read(url.resolve('/hello/3')); | |
269 }).then((response) => expect(response, equals('Hello, request 3!'))); | |
270 }), completes); | |
271 | 176 |
272 server.handle('GET', '/hello/1', (request) { | 177 server.handle('GET', '/hello/2', |
273 request.response.write('Hello, request 1!'); | 178 (request) => new shelf.Response.ok('Hello, request 2!')); |
274 request.response.close(); | 179 }, "'scheduled server 0' received GET /hello/3 when no more requests were " |
275 }); | 180 "expected."); |
276 | 181 |
277 server.handle('GET', '/hello/2', (request) { | 182 expectServerError("an error in a handler doesn't cause a timeout", () { |
278 request.response.write('Hello, request 2!'); | 183 var server = new ScheduledServer(); |
279 request.response.close(); | 184 expect(server.url.then((url) => http.read(url.resolve('/hello'))), |
280 }); | 185 completion(equals('Hello, test!'))); |
281 }); | |
282 | 186 |
283 test('test 2', () { | 187 server.handle('GET', '/hello', (request) => fail('oh no')); |
284 expect(errors.length, 2); | 188 }, 'oh no'); |
285 expect(errors[0].error.toString(), equals("'scheduled server 0' received " | 189 } |
286 "GET /hello/3 when no more requests were expected.")); | |
287 expect(errors[1].error, new isInstanceOf<HttpException>()); | |
288 }); | |
289 }, passing: ['test 2']); | |
290 | 190 |
291 expectTestsPass("an error in a handler doesn't cause a timeout", () { | 191 /// Creates a metatest that runs [testBody], captures its schedule errors, and |
292 var errors; | 192 /// asserts that it throws an error with the given [errorMessage]. |
293 test('test 1', () { | 193 void expectServerError(String description, void testBody(), |
294 currentSchedule.onException.schedule(() { | 194 String errorMessage) { |
295 errors = currentSchedule.errors; | 195 expectTestFails(description, testBody, (errors) { |
296 }); | 196 // There can be between one and three errors here. The first is the |
197 // expected server error. The second is an HttpException that may occur if | |
198 // the server is closed fast enough after the error. The third is due to | |
199 // issue 9151: the HttpException is reported without a stack trace, and so | |
200 // when it's wrapped twice it registers as a different exception each time | |
201 // (because it's given an ad-hoc stack trace). | |
202 expect(errors.length, inInclusiveRange(1, 3)); | |
203 expect(errors[0].error.toString(), equals(errorMessage)); | |
297 | 204 |
298 var server = new ScheduledServer(); | 205 for (var i = 1; i < errors.length; i++) { |
299 expect(server.url.then((url) => http.read(url.resolve('/hello'))), | 206 expect(errors[i].error, new isInstanceOf<HttpException>()); |
300 completion(equals('Hello, test!'))); | 207 } |
301 | 208 }); |
302 server.handle('GET', '/hello', (request) { | |
303 fail('oh no'); | |
304 }); | |
305 }); | |
306 | |
307 test('test 2', () { | |
308 expect(errors.length, 2); | |
309 expect(errors[0].error.toString(), equals('oh no')); | |
310 expect(errors[1].error, new isInstanceOf<HttpException>()); | |
311 }); | |
312 }, passing: ['test 2']); | |
313 } | 209 } |
OLD | NEW |