OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library scheduled_process_test; |
| 6 |
| 7 import 'dart:async'; |
| 8 import 'dart:io'; |
| 9 |
| 10 import 'package:pathos/path.dart' as path; |
| 11 import 'package:scheduled_test/scheduled_process.dart'; |
| 12 import 'package:scheduled_test/scheduled_test.dart'; |
| 13 import 'package:scheduled_test/src/mock_clock.dart' as mock_clock; |
| 14 |
| 15 import 'metatest.dart'; |
| 16 import 'utils.dart'; |
| 17 |
| 18 ServerSocket backChannel; |
| 19 |
| 20 void main() { |
| 21 expectTestsPass("a process must have kill() or shouldExit() called", () { |
| 22 var errors; |
| 23 test('test 1', () { |
| 24 currentSchedule.onException.schedule(() { |
| 25 errors = currentSchedule.errors; |
| 26 }); |
| 27 |
| 28 startDartProcess('print("hello!");'); |
| 29 }); |
| 30 |
| 31 test('test 2', () { |
| 32 expect(errors, everyElement(new isInstanceOf<ScheduleError>())); |
| 33 expect(errors.length, equals(1)); |
| 34 expect(errors.first.error, isStateError); |
| 35 expect(errors.first.error.message, matches(r"^Scheduled process " |
| 36 r"'[^']+[\\/]dart' must have shouldExit\(\) or kill\(\) called " |
| 37 r"before the test is run\.$")); |
| 38 }); |
| 39 }, passing: ['test 2']); |
| 40 |
| 41 expectTestsPass("a process exits with the expected exit code", () { |
| 42 test('exit code 0', () { |
| 43 var process = startDartProcess('exitCode = 0;'); |
| 44 process.shouldExit(0); |
| 45 }); |
| 46 |
| 47 test('exit code 42', () { |
| 48 var process = startDartProcess('exitCode = 42;'); |
| 49 process.shouldExit(42); |
| 50 }); |
| 51 }); |
| 52 |
| 53 expectTestsPass("a process exiting with an unexpected exit code should cause " |
| 54 "an error", () { |
| 55 var errors; |
| 56 test('test 1', () { |
| 57 currentSchedule.onException.schedule(() { |
| 58 errors = currentSchedule.errors; |
| 59 }); |
| 60 |
| 61 var process = startDartProcess('exitCode = 1;'); |
| 62 process.shouldExit(0); |
| 63 }); |
| 64 |
| 65 test('test 2', () { |
| 66 expect(errors, everyElement(new isInstanceOf<ScheduleError>())); |
| 67 expect(errors.length, equals(1)); |
| 68 expect(errors.first.error, new isInstanceOf<TestFailure>()); |
| 69 }); |
| 70 }, passing: ['test 2']); |
| 71 |
| 72 expectTestsPass("a killed process doesn't care about its exit code", () { |
| 73 test('exit code 0', () { |
| 74 var process = startDartProcess('exitCode = 0;'); |
| 75 process.kill(); |
| 76 }); |
| 77 |
| 78 test('exit code 1', () { |
| 79 var process = startDartProcess('exitCode = 1;'); |
| 80 process.kill(); |
| 81 }); |
| 82 }); |
| 83 |
| 84 expectTestsPass("a killed process stops running", () { |
| 85 test('test', () { |
| 86 var process = startDartProcess('while (true);'); |
| 87 process.kill(); |
| 88 }); |
| 89 }); |
| 90 |
| 91 expectTestsPass("kill can't be called twice", () { |
| 92 test('test', () { |
| 93 var process = startDartProcess(''); |
| 94 process.kill(); |
| 95 expect(process.kill, throwsA(isStateError)); |
| 96 }); |
| 97 }); |
| 98 |
| 99 expectTestsPass("kill can't be called after shouldExit", () { |
| 100 test('test', () { |
| 101 var process = startDartProcess(''); |
| 102 process.shouldExit(0); |
| 103 expect(process.kill, throwsA(isStateError)); |
| 104 }); |
| 105 }); |
| 106 |
| 107 expectTestsPass("shouldExit can't be called twice", () { |
| 108 test('test', () { |
| 109 var process = startDartProcess(''); |
| 110 process.shouldExit(0); |
| 111 expect(() => process.shouldExit(0), throwsA(isStateError)); |
| 112 }); |
| 113 }); |
| 114 |
| 115 expectTestsPass("shouldExit can't be called after kill", () { |
| 116 test('test', () { |
| 117 var process = startDartProcess(''); |
| 118 process.kill(); |
| 119 expect(() => process.shouldExit(0), throwsA(isStateError)); |
| 120 }); |
| 121 }); |
| 122 |
| 123 expectTestsPass("a process that ends while waiting for stdout shouldn't " |
| 124 "block the test", () { |
| 125 var errors; |
| 126 test('test 1', () { |
| 127 currentSchedule.onException.schedule(() { |
| 128 errors = currentSchedule.errors; |
| 129 }); |
| 130 |
| 131 var process = startDartProcess(''); |
| 132 expect(process.nextLine(), completion(equals('hello'))); |
| 133 expect(process.nextLine(), completion(equals('world'))); |
| 134 process.shouldExit(0); |
| 135 }); |
| 136 |
| 137 test('test 2', () { |
| 138 expect(errors, everyElement(new isInstanceOf<ScheduleError>())); |
| 139 expect(errors.length, equals(2)); |
| 140 expect(errors[0].error, isStateError); |
| 141 expect(errors[0].error.message, equals("No elements")); |
| 142 expect(errors[1].error, matches(r"^Process '[^']+[\\/]dart [^']+' ended " |
| 143 r"earlier than scheduled with exit code 0\.")); |
| 144 }); |
| 145 }, passing: ['test 2']); |
| 146 |
| 147 expectTestsPass("a process that ends during the task immediately before it's " |
| 148 "scheduled to end shouldn't cause an error", () { |
| 149 test('test', () { |
| 150 var process = startDartProcess('stdin.toList();'); |
| 151 process.closeStdin(); |
| 152 // Unfortunately, sleeping for a second seems like the best way of |
| 153 // guaranteeing that the process ends during this task. |
| 154 schedule(() => new Future.delayed(new Duration(seconds: 1))); |
| 155 process.shouldExit(0); |
| 156 }); |
| 157 }); |
| 158 |
| 159 expectTestsPass("nextLine returns the next line of stdout from the process", |
| 160 () { |
| 161 test('test', () { |
| 162 var process = startDartProcess(r'print("hello\n\nworld"); print("hi");'); |
| 163 expect(process.nextLine(), completion(equals('hello'))); |
| 164 expect(process.nextLine(), completion(equals(''))); |
| 165 expect(process.nextLine(), completion(equals('world'))); |
| 166 expect(process.nextLine(), completion(equals('hi'))); |
| 167 process.shouldExit(0); |
| 168 }); |
| 169 }); |
| 170 |
| 171 expectTestsPass("nextLine throws an error if there's no more stdout", () { |
| 172 var errors; |
| 173 test('test 1', () { |
| 174 currentSchedule.onException.schedule(() { |
| 175 errors = currentSchedule.errors; |
| 176 }); |
| 177 |
| 178 var process = startDartProcess('print("hello");'); |
| 179 expect(process.nextLine(), completion(equals('hello'))); |
| 180 expect(process.nextLine(), completion(equals('world'))); |
| 181 process.shouldExit(0); |
| 182 }); |
| 183 |
| 184 test('test 2', () { |
| 185 expect(errors, everyElement(new isInstanceOf<ScheduleError>())); |
| 186 expect(errors.length, equals(2)); |
| 187 expect(errors[0].error, isStateError); |
| 188 expect(errors[0].error.message, equals("No elements")); |
| 189 expect(errors[1].error, matches(r"^Process '[^']+[\\/]dart [^']+' ended " |
| 190 r"earlier than scheduled with exit code 0\.")); |
| 191 }); |
| 192 }, passing: ['test 2']); |
| 193 |
| 194 expectTestsPass("nextErrLine returns the next line of stderr from the " |
| 195 "process", () { |
| 196 test('test', () { |
| 197 var process = startDartProcess(r''' |
| 198 stderr.addString("hello\n\nworld\n"); |
| 199 stderr.addString("hi"); |
| 200 '''); |
| 201 expect(process.nextErrLine(), completion(equals('hello'))); |
| 202 expect(process.nextErrLine(), completion(equals(''))); |
| 203 expect(process.nextErrLine(), completion(equals('world'))); |
| 204 expect(process.nextErrLine(), completion(equals('hi'))); |
| 205 process.shouldExit(0); |
| 206 }); |
| 207 }); |
| 208 |
| 209 expectTestsPass("nextErrLine throws an error if there's no more stderr", () { |
| 210 var errors; |
| 211 test('test 1', () { |
| 212 currentSchedule.onException.schedule(() { |
| 213 errors = currentSchedule.errors; |
| 214 }); |
| 215 |
| 216 var process = startDartProcess(r'stderr.addString("hello\n");'); |
| 217 expect(process.nextErrLine(), completion(equals('hello'))); |
| 218 expect(process.nextErrLine(), completion(equals('world'))); |
| 219 process.shouldExit(0); |
| 220 }); |
| 221 |
| 222 test('test 2', () { |
| 223 expect(errors, everyElement(new isInstanceOf<ScheduleError>())); |
| 224 expect(errors.length, equals(2)); |
| 225 expect(errors[0].error, isStateError); |
| 226 expect(errors[0].error.message, equals("No elements")); |
| 227 expect(errors[1].error, matches(r"^Process '[^']+[\\/]dart [^']+' ended " |
| 228 r"earlier than scheduled with exit code 0\.")); |
| 229 }); |
| 230 }, passing: ['test 2']); |
| 231 |
| 232 expectTestsPass("remainingStdout returns all the stdout if it's not consumed " |
| 233 "any other way", () { |
| 234 test('test', () { |
| 235 var process = startDartProcess(r'print("hello\n\nworld"); print("hi");'); |
| 236 process.shouldExit(0); |
| 237 expect(process.remainingStdout(), |
| 238 completion(equals("hello\n\nworld\nhi"))); |
| 239 }); |
| 240 }); |
| 241 |
| 242 expectTestsPass("remainingStdout returns the empty string if there's no " |
| 243 "stdout", () { |
| 244 test('test', () { |
| 245 var process = startDartProcess(r''); |
| 246 process.shouldExit(0); |
| 247 expect(process.remainingStdout(), completion(isEmpty)); |
| 248 }); |
| 249 }); |
| 250 |
| 251 expectTestsPass("remainingStdout returns the remaining stdout after the " |
| 252 "lines consumed by nextLine", () { |
| 253 test('test', () { |
| 254 var process = startDartProcess(r'print("hello\n\nworld"); print("hi");'); |
| 255 expect(process.nextLine(), completion(equals("hello"))); |
| 256 expect(process.nextLine(), completion(equals(""))); |
| 257 process.shouldExit(0); |
| 258 expect(process.remainingStdout(), completion(equals("world\nhi"))); |
| 259 }); |
| 260 }); |
| 261 |
| 262 expectTestsPass("remainingStdout can't be called before the process is " |
| 263 "scheduled to end", () { |
| 264 test('test', () { |
| 265 var process = startDartProcess(r''); |
| 266 expect(process.remainingStdout, throwsA(isStateError)); |
| 267 process.shouldExit(0); |
| 268 }); |
| 269 }); |
| 270 |
| 271 expectTestsPass("remainingStderr returns all the stderr if it's not consumed " |
| 272 "any other way", () { |
| 273 test('test', () { |
| 274 var process = startDartProcess(r''' |
| 275 stderr.addString("hello\n\nworld\n"); |
| 276 stderr.addString("hi\n"); |
| 277 '''); |
| 278 process.shouldExit(0); |
| 279 expect(process.remainingStderr(), |
| 280 completion(equals("hello\n\nworld\nhi"))); |
| 281 }); |
| 282 }); |
| 283 |
| 284 expectTestsPass("remainingStderr returns the empty string if there's no " |
| 285 "stderr", () { |
| 286 test('test', () { |
| 287 var process = startDartProcess(r''); |
| 288 process.shouldExit(0); |
| 289 expect(process.remainingStderr(), completion(isEmpty)); |
| 290 }); |
| 291 }); |
| 292 |
| 293 expectTestsPass("remainingStderr returns the remaining stderr after the " |
| 294 "lines consumed by nextLine", () { |
| 295 test('test', () { |
| 296 var process = startDartProcess(r''' |
| 297 stderr.addString("hello\n\nworld\n"); |
| 298 stderr.addString("hi\n"); |
| 299 '''); |
| 300 expect(process.nextErrLine(), completion(equals("hello"))); |
| 301 expect(process.nextErrLine(), completion(equals(""))); |
| 302 process.shouldExit(0); |
| 303 expect(process.remainingStderr(), completion(equals("world\nhi"))); |
| 304 }); |
| 305 }); |
| 306 |
| 307 expectTestsPass("remainingStderr can't be called before the process is " |
| 308 "scheduled to end", () { |
| 309 test('test', () { |
| 310 var process = startDartProcess(r''); |
| 311 expect(process.remainingStderr, throwsA(isStateError)); |
| 312 process.shouldExit(0); |
| 313 }); |
| 314 }); |
| 315 |
| 316 expectTestsPass("writeLine schedules a line to be written to the process", |
| 317 () { |
| 318 test('test', () { |
| 319 var process = startDartProcess(r''' |
| 320 stdinLines.listen((line) => print("> $line")); |
| 321 '''); |
| 322 process.writeLine("hello"); |
| 323 expect(process.nextLine(), completion(equals("> hello"))); |
| 324 process.writeLine("world"); |
| 325 expect(process.nextLine(), completion(equals("> world"))); |
| 326 process.kill(); |
| 327 }); |
| 328 }); |
| 329 |
| 330 expectTestsPass("closeStdin closes the process's stdin stream", () { |
| 331 test('test', () { |
| 332 currentSchedule.timeout = new Duration(seconds: 1); |
| 333 var process = startDartProcess(r''' |
| 334 stdin.listen((line) => print("> $line"), |
| 335 onDone: () => print("stdin closed")); |
| 336 '''); |
| 337 process.closeStdin(); |
| 338 process.shouldExit(0); |
| 339 expect(process.nextLine(), completion(equals('stdin closed'))); |
| 340 }); |
| 341 }); |
| 342 } |
| 343 |
| 344 ScheduledProcess startDartProcess(String script) { |
| 345 var tempDir = schedule(() { |
| 346 return new Directory('').createTemp().then((dir) => dir.path); |
| 347 }, 'create temp dir'); |
| 348 |
| 349 var dartPath = schedule(() { |
| 350 return tempDir.then((dir) { |
| 351 var utilsPath = path.absolute(path.join( |
| 352 new Options().script, 'utils.dart')); |
| 353 return new File(path.join(dir, 'test.dart')).writeAsString(''' |
| 354 import 'dart:async'; |
| 355 import 'dart:io'; |
| 356 |
| 357 var stdinLines = stdin |
| 358 .transform(new StringDecoder()) |
| 359 .transform(new LineTransformer()); |
| 360 |
| 361 void main() { |
| 362 $script |
| 363 } |
| 364 ''').then((file) => file.path); |
| 365 }); |
| 366 }, 'write script file'); |
| 367 |
| 368 currentSchedule.onComplete.schedule(() { |
| 369 return tempDir.catchError((_) => null).then((dir) { |
| 370 if (dir == null) return; |
| 371 return new Directory(dir).delete(recursive: true); |
| 372 }); |
| 373 }, 'clean up temp dir'); |
| 374 |
| 375 return new ScheduledProcess.start(dartExecutable, ['--checked', dartPath]); |
| 376 } |
OLD | NEW |