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 // VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked | |
5 | |
6 library test_helper; | |
7 | |
8 import 'dart:async'; | |
9 import 'dart:convert'; | |
10 import 'dart:io'; | |
11 import 'package:observatory/service_io.dart'; | |
12 | |
13 // This invocation should set up the state being tested. | |
14 const String _TESTEE_MODE_FLAG = "--testee-mode"; | |
15 | |
16 class _TestLauncher { | |
17 Process process; | |
18 final List<String> args; | |
19 | |
20 _TestLauncher() : args = ['--enable-vm-service:0', | |
21 Platform.script.toFilePath(), | |
22 _TESTEE_MODE_FLAG] {} | |
23 | |
24 Future<int> launch(bool pause_on_exit) { | |
25 String dartExecutable = Platform.executable; | |
26 var fullArgs = []; | |
27 if (pause_on_exit == true) { | |
28 fullArgs.add('--pause-isolates-on-exit'); | |
29 } | |
30 fullArgs.addAll(Platform.executableArguments); | |
31 fullArgs.addAll(args); | |
32 print('** Launching $dartExecutable ${fullArgs.join(' ')}'); | |
33 return Process.start(dartExecutable, fullArgs).then((p) { | |
34 | |
35 Completer completer = new Completer(); | |
36 process = p; | |
37 var portNumber; | |
38 var blank; | |
39 var first = true; | |
40 process.stdout.transform(UTF8.decoder) | |
41 .transform(new LineSplitter()).listen((line) { | |
42 if (line.startsWith('Observatory listening on http://')) { | |
43 RegExp portExp = new RegExp(r"\d+.\d+.\d+.\d+:(\d+)"); | |
44 var port = portExp.firstMatch(line).group(1); | |
45 portNumber = int.parse(port); | |
46 } | |
47 if (line == '') { | |
48 // Received blank line. | |
49 blank = true; | |
50 } | |
51 if (portNumber != null && blank == true && first == true) { | |
52 completer.complete(portNumber); | |
53 // Stop repeat completions. | |
54 first = false; | |
55 print('** Signaled to run test queries on $portNumber'); | |
56 } | |
57 print(line); | |
58 }); | |
59 process.stderr.transform(UTF8.decoder) | |
60 .transform(new LineSplitter()).listen((line) { | |
61 print(line); | |
62 }); | |
63 process.exitCode.then((exitCode) { | |
64 print("** Process exited"); | |
65 }); | |
66 return completer.future; | |
67 }); | |
68 } | |
69 | |
70 void requestExit() { | |
71 print('** Killing script'); | |
72 process.kill(); | |
73 } | |
74 } | |
75 | |
76 typedef Future IsolateTest(Isolate isolate); | |
77 typedef Future VMTest(VM vm); | |
78 | |
79 /// Runs [tests] in sequence, each of which should take an [Isolate] and | |
80 /// return a [Future]. Code for setting up state can run before and/or | |
81 /// concurrently with the tests. Uses [mainArgs] to determine whether | |
82 /// to run tests or testee in this invokation of the script. | |
83 void runIsolateTests(List<String> mainArgs, | |
84 List<IsolateTest> tests, | |
85 {void testeeBefore(), | |
86 void testeeConcurrent(), | |
87 bool pause_on_exit}) { | |
88 if (mainArgs.contains(_TESTEE_MODE_FLAG)) { | |
89 if (testeeBefore != null) { | |
90 testeeBefore(); | |
91 } | |
92 print(''); // Print blank line to signal that we are ready. | |
93 if (testeeConcurrent != null) { | |
94 testeeConcurrent(); | |
95 } | |
96 // Wait around for the process to be killed. | |
97 stdin.first.then((_) => exit(0)); | |
98 } else { | |
99 var process = new _TestLauncher(); | |
100 process.launch(pause_on_exit).then((port) { | |
101 String addr = 'ws://localhost:$port/ws'; | |
102 var testIndex = 0; | |
103 var totalTests = tests.length - 1; | |
104 var name = Platform.script.pathSegments.last; | |
105 new WebSocketVM(new WebSocketVMTarget(addr)).load() | |
106 .then((VM vm) => vm.isolates.first.load()) | |
107 .then((Isolate isolate) => Future.forEach(tests, (test) { | |
108 print('Running $name [$testIndex/$totalTests]'); | |
109 testIndex++; | |
110 return test(isolate); | |
111 })).then((_) => process.requestExit()); | |
112 }); | |
113 } | |
114 } | |
115 | |
116 | |
117 // Cancel the subscription and complete the completer when finished processing | |
118 // events. | |
119 typedef void ServiceEventHandler(ServiceEvent event, | |
120 StreamSubscription subscription, | |
121 Completer completer); | |
122 | |
123 Future processServiceEvents(VM vm, ServiceEventHandler handler) { | |
124 Completer completer = new Completer(); | |
125 var subscription; | |
126 subscription = vm.events.stream.listen((ServiceEvent event) { | |
127 handler(event, subscription, completer); | |
128 }); | |
129 return completer.future; | |
130 } | |
131 | |
132 | |
133 /// Runs [tests] in sequence, each of which should take an [Isolate] and | |
134 /// return a [Future]. Code for setting up state can run before and/or | |
135 /// concurrently with the tests. Uses [mainArgs] to determine whether | |
136 /// to run tests or testee in this invokation of the script. | |
137 Future runVMTests(List<String> mainArgs, | |
138 List<VMTest> tests, | |
139 {Future testeeBefore(), | |
140 Future testeeConcurrent(), | |
141 bool pause_on_exit}) async { | |
142 if (mainArgs.contains(_TESTEE_MODE_FLAG)) { | |
143 if (testeeBefore != null) { | |
144 await testeeBefore(); | |
145 } | |
146 print(''); // Print blank line to signal that we are ready. | |
147 if (testeeConcurrent != null) { | |
148 await testeeConcurrent(); | |
149 } | |
150 // Wait around for the process to be killed. | |
151 stdin.first.then((_) => exit(0)); | |
152 } else { | |
153 var process = new _TestLauncher(); | |
154 process.launch(pause_on_exit).then((port) async { | |
155 String addr = 'ws://localhost:$port/ws'; | |
156 var testIndex = 0; | |
157 var totalTests = tests.length - 1; | |
158 var name = Platform.script.pathSegments.last; | |
159 new WebSocketVM(new WebSocketVMTarget(addr)).load() | |
160 .then((VM vm) => Future.forEach(tests, (test) { | |
161 print('Running $name [$testIndex/$totalTests]'); | |
162 testIndex++; | |
163 return test(vm); | |
164 })).then((_) => process.requestExit()); | |
165 }); | |
166 } | |
167 } | |
OLD | NEW |