Chromium Code Reviews| 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 |