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 an additional task here so that when the previous task hits the |
156 request.response.write('Goodbye, test!'); | 69 // server, it will be considered too early. Otherwise we'd hit the heuristic |
157 request.response.close(); | 70 // of allowing the server to be hit in the immediately prior task. |
158 }); | 71 schedule(() => null); |
159 }); | |
160 | 72 |
161 test('test 2', () { | 73 server.handle('GET', '/hello', |
162 expect(errors.length, 2); | 74 (request) => new shelf.Response.ok('Hello, test!')); |
163 expect(errors[0].error.toString(), equals( | 75 }, "'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 | 76 |
169 expectTestsPass("a handler fails if the method is wrong", () { | 77 expectTestPasses("a handler waits for the immediately prior task to complete " |
170 var errors; | 78 "before checking if it's too early", () { |
171 test('test 1', () { | 79 var server = new ScheduledServer(); |
172 currentSchedule.onException.schedule(() { | 80 expect(server.url.then((url) => http.read(url.resolve('/hello'))), |
173 errors = currentSchedule.errors; | 81 completion(equals('Hello, test!'))); |
174 }); | |
175 | 82 |
176 var server = new ScheduledServer(); | 83 // Sleeping here is unfortunate, but we want to be sure that the HTTP |
177 expect(server.url.then((url) => http.head(url.resolve('/hello'))), | 84 // request hits the server during this test without actually blocking the |
178 completes); | 85 // task on the request completing. |
| 86 // |
| 87 // This is also a potential race condition, but hopefully a local HTTP |
| 88 // request won't take 500ms. |
| 89 schedule(() => new Future.delayed(new Duration(milliseconds: 500))); |
179 | 90 |
180 server.handle('GET', '/hello', (request) { | 91 server.handle('GET', '/hello', |
181 request.response.write('Hello, test!'); | 92 (request) => new shelf.Response.ok('Hello, test!')); |
182 request.response.close(); | 93 }); |
183 }); | |
184 }); | |
185 | 94 |
186 test('test 2', () { | 95 expectServerError("a handler fails if the url is wrong", () { |
187 expect(errors.length, 2); | 96 var server = new ScheduledServer(); |
188 expect(errors[0].error.toString(), equals( | 97 expect(server.url.then((url) => http.read(url.resolve('/hello'))), |
189 "'scheduled server 0' expected GET /hello, but got HEAD /hello.")); | 98 completion(equals('Hello, test!'))); |
190 expect(errors[1].error, new isInstanceOf<HttpException>()); | 99 |
191 }); | 100 server.handle('GET', '/goodbye', |
192 }, passing: ['test 2']); | 101 (request) => new shelf.Response.ok('Goodbye, test!')); |
| 102 }, "'scheduled server 0' expected GET /goodbye, but got GET /hello."); |
| 103 |
| 104 expectServerError("a handler fails if the method is wrong", () { |
| 105 var server = new ScheduledServer(); |
| 106 expect(server.url.then((url) => http.head(url.resolve('/hello'))), |
| 107 completes); |
| 108 |
| 109 server.handle('GET', '/hello', |
| 110 (request) => new shelf.Response.ok('Hello, test!')); |
| 111 }, "'scheduled server 0' expected GET /hello, but got HEAD /hello."); |
193 | 112 |
194 expectTestsPass("a handler times out waiting to be hit", () { | 113 expectTestsPass("a handler times out waiting to be hit", () { |
195 var clock = mock_clock.mock()..run(); | 114 var clock = mock_clock.mock()..run(); |
196 var timeOfException; | 115 var timeOfException; |
197 var errors; | 116 var errors; |
198 test('test 1', () { | 117 test('test 1', () { |
199 currentSchedule.timeout = new Duration(milliseconds: 2); | 118 currentSchedule.timeout = new Duration(milliseconds: 2); |
200 currentSchedule.onException.schedule(() { | 119 currentSchedule.onException.schedule(() { |
201 timeOfException = clock.time; | 120 timeOfException = clock.time; |
202 errors = currentSchedule.errors; | 121 errors = currentSchedule.errors; |
203 }); | 122 }); |
204 | 123 |
205 var server = new ScheduledServer(); | 124 var server = new ScheduledServer(); |
206 | 125 |
207 server.handle('GET', '/hello', (request) { | 126 server.handle('GET', '/hello', |
208 request.response.write('Hello, test!'); | 127 (request) => new shelf.Response.ok('Hello, test!')); |
209 request.response.close(); | |
210 }); | |
211 }); | 128 }); |
212 | 129 |
213 test('test 2', () { | 130 test('test 2', () { |
214 expect(clock.time, equals(2)); | 131 expect(clock.time, equals(2)); |
215 | 132 |
216 expect(errors.single, new isInstanceOf<ScheduleError>()); | 133 expect(errors.single, new isInstanceOf<ScheduleError>()); |
217 expect(errors.single.error.toString(), equals( | 134 expect(errors.single.error.toString(), equals( |
218 "The schedule timed out after 0:00:00.002000 of inactivity.")); | 135 "The schedule timed out after 0:00:00.002000 of inactivity.")); |
219 }); | 136 }); |
220 }, passing: ['test 2']); | 137 }, passing: ['test 2']); |
221 | 138 |
222 expectTestsPass("multiple handlers in series respond to requests in series", | 139 expectTestPasses("multiple handlers in series respond to requests in series", |
223 () { | 140 () { |
224 test('test', () { | 141 var server = new ScheduledServer(); |
225 var server = new ScheduledServer(); | 142 expect(server.url.then((url) { |
226 expect(server.url.then((url) { | 143 return http.read(url.resolve('/hello/1')).then((response) { |
227 return http.read(url.resolve('/hello/1')).then((response) { | 144 expect(response, equals('Hello, request 1!')); |
228 expect(response, equals('Hello, request 1!')); | 145 return http.read(url.resolve('/hello/2')); |
229 return http.read(url.resolve('/hello/2')); | 146 }).then((response) { |
230 }).then((response) { | 147 expect(response, equals('Hello, request 2!')); |
231 expect(response, equals('Hello, request 2!')); | 148 return http.read(url.resolve('/hello/3')); |
232 return http.read(url.resolve('/hello/3')); | 149 }).then((response) => expect(response, equals('Hello, request 3!'))); |
233 }).then((response) => expect(response, equals('Hello, request 3!'))); | 150 }), completes); |
234 }), completes); | |
235 | 151 |
236 server.handle('GET', '/hello/1', (request) { | 152 server.handle('GET', '/hello/1', |
237 request.response.write('Hello, request 1!'); | 153 (request) => new shelf.Response.ok('Hello, request 1!')); |
238 request.response.close(); | |
239 }); | |
240 | 154 |
241 server.handle('GET', '/hello/2', (request) { | 155 server.handle('GET', '/hello/2', |
242 request.response.write('Hello, request 2!'); | 156 (request) => new shelf.Response.ok('Hello, request 2!')); |
243 request.response.close(); | |
244 }); | |
245 | 157 |
246 server.handle('GET', '/hello/3', (request) { | 158 server.handle('GET', '/hello/3', |
247 request.response.write('Hello, request 3!'); | 159 (request) => new shelf.Response.ok('Hello, request 3!')); |
248 request.response.close(); | |
249 }); | |
250 }); | |
251 }); | 160 }); |
252 | 161 |
253 expectTestsPass("a server that receives a request after all its handlers " | 162 expectServerError("a server that receives a request after all its handlers " |
254 "have run throws an error", () { | 163 "have run throws an error", () { |
255 var errors; | 164 var server = new ScheduledServer(); |
256 test('test 1', () { | 165 expect(server.url.then((url) { |
257 currentSchedule.onException.schedule(() { | 166 return http.read(url.resolve('/hello/1')).then((response) { |
258 errors = currentSchedule.errors; | 167 expect(response, equals('Hello, request 1!')); |
259 }); | 168 return http.read(url.resolve('/hello/2')); |
| 169 }).then((response) { |
| 170 expect(response, equals('Hello, request 2!')); |
| 171 return http.read(url.resolve('/hello/3')); |
| 172 }).then((response) => expect(response, equals('Hello, request 3!'))); |
| 173 }), completes); |
260 | 174 |
261 var server = new ScheduledServer(); | 175 server.handle('GET', '/hello/1', |
262 expect(server.url.then((url) { | 176 (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 | 177 |
272 server.handle('GET', '/hello/1', (request) { | 178 server.handle('GET', '/hello/2', |
273 request.response.write('Hello, request 1!'); | 179 (request) => new shelf.Response.ok('Hello, request 2!')); |
274 request.response.close(); | 180 }, "'scheduled server 0' received GET /hello/3 when no more requests were " |
275 }); | 181 "expected."); |
276 | 182 |
277 server.handle('GET', '/hello/2', (request) { | 183 expectServerError("an error in a handler doesn't cause a timeout", () { |
278 request.response.write('Hello, request 2!'); | 184 var server = new ScheduledServer(); |
279 request.response.close(); | 185 expect(server.url.then((url) => http.read(url.resolve('/hello'))), |
280 }); | 186 completion(equals('Hello, test!'))); |
281 }); | |
282 | 187 |
283 test('test 2', () { | 188 server.handle('GET', '/hello', (request) => fail('oh no')); |
284 expect(errors.length, 2); | 189 }, 'oh no'); |
285 expect(errors[0].error.toString(), equals("'scheduled server 0' received " | 190 } |
286 "GET /hello/3 when no more requests were expected.")); | |
287 expect(errors[1].error, new isInstanceOf<HttpException>()); | |
288 }); | |
289 }, passing: ['test 2']); | |
290 | 191 |
291 expectTestsPass("an error in a handler doesn't cause a timeout", () { | 192 /// Creates a metatest that runs [testBody], captures its schedule errors, and |
292 var errors; | 193 /// asserts that it throws an error with the given [errorMessage]. |
293 test('test 1', () { | 194 void expectServerError(String description, void testBody(), |
294 currentSchedule.onException.schedule(() { | 195 String errorMessage) { |
295 errors = currentSchedule.errors; | 196 expectTestFails(description, testBody, (errors) { |
296 }); | 197 // There can be between one and three errors here. The first is the |
| 198 // expected server error. The second is an HttpException that may occur if |
| 199 // the server is closed fast enough after the error. The third is due to |
| 200 // issue 9151: the HttpException is reported without a stack trace, and so |
| 201 // when it's wrapped twice it registers as a different exception each time |
| 202 // (because it's given an ad-hoc stack trace). |
| 203 expect(errors.length, inInclusiveRange(1, 3)); |
| 204 expect(errors[0].error.toString(), equals(errorMessage)); |
297 | 205 |
298 var server = new ScheduledServer(); | 206 for (var i = 1; i < errors.length; i++) { |
299 expect(server.url.then((url) => http.read(url.resolve('/hello'))), | 207 expect(errors[i].error, new isInstanceOf<HttpException>()); |
300 completion(equals('Hello, test!'))); | 208 } |
301 | 209 }); |
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 } | 210 } |
OLD | NEW |