5
5
import 'dart:async' ;
6
6
import 'dart:convert' ;
7
7
import 'dart:io' ;
8
- import 'dart:math' ;
9
8
10
9
import 'package:dust/src/path.dart' ;
11
10
import 'package:dust/src/path_canonicalizer.dart' ;
12
11
import 'package:dust/src/vm_result.dart' ;
13
12
import 'package:path/path.dart' as path;
14
13
import 'package:pedantic/pedantic.dart' ;
15
- import 'package:vm_service_lib/vm_service_lib .dart' ;
16
- import 'package:vm_service_lib/vm_service_lib_io .dart' ;
14
+ import 'package:vm_service/vm_service .dart' ;
15
+ import 'package:vm_service/vm_service_io .dart' ;
17
16
18
17
/// A class to start a VM, connect to its service, and control its fuzz cases.
19
18
///
@@ -47,17 +46,6 @@ class VmController {
47
46
/// Check if this VM is connected.
48
47
bool get isConnected => _serviceClient != null ;
49
48
50
- /// Count all paths that could be exercised for the target script.
51
- Future <int > countPaths () async {
52
- final fuzzIsolate = await _preRunCase ('' );
53
-
54
- final pathCount = await _countPath (fuzzIsolate);
55
-
56
- await _finalizeOutput (fuzzIsolate);
57
-
58
- return pathCount;
59
- }
60
-
61
49
/// Kill the process & close the service connection.
62
50
Future <void > dispose () async {
63
51
try {
@@ -85,8 +73,10 @@ class VmController {
85
73
final fuzzIsolate = await _preRunCase (input);
86
74
87
75
final paths = readCoverage ? await _getPath (fuzzIsolate) : null ;
76
+ await _serviceClient.resume (fuzzIsolate.id);
77
+ await _fuzzIsolateDead ();
88
78
89
- final jsonOut = await _finalizeOutput (fuzzIsolate );
79
+ final jsonOut = await _finalizeOutput ();
90
80
91
81
final bool succeeded = jsonOut['success' ];
92
82
if (succeeded) {
@@ -122,19 +112,6 @@ class VmController {
122
112
return _serviceClient;
123
113
}
124
114
125
- Future <int > _countPath (Isolate isolate) async {
126
- final report = await _serviceClient
127
- .getSourceReport (isolate.id, [SourceReportKind .kCoverage]);
128
- var sum = 0 ;
129
- for (final range in report.ranges) {
130
- if (range.coverage == null ) {
131
- continue ;
132
- }
133
- sum += range.coverage.hits.length + range.coverage.misses.length;
134
- }
135
- return sum;
136
- }
137
-
138
115
Future <T > _exponentialBackoff <T >(
139
116
Future <T > Function () action, bool Function (T ) accept,
140
117
{Duration limit = const Duration (seconds: 5 )}) async {
@@ -166,14 +143,9 @@ class VmController {
166
143
throw Exception ('$limit tries exceeded: $reason ' );
167
144
}
168
145
169
- /// Continue [fuzzIsolate] to unblock the main isolate and get json output.
170
- Future <Map <String , dynamic >> _finalizeOutput (Isolate fuzzIsolate) async {
171
- await _serviceClient.resume (fuzzIsolate.id);
172
- await _fuzzIsolateDead ();
173
-
174
- return _exponentialBackoff (
175
- () async => jsonDecode (_outputBuffer.toString ().trim ()), (_) => true );
176
- }
146
+ /// Read the json output from the main isolate.
147
+ Future <Map <String , dynamic >> _finalizeOutput () async => _exponentialBackoff (
148
+ () async => jsonDecode (_outputBuffer.toString ().trim ()), (_) => true );
177
149
178
150
Future <Isolate > _fuzzIsolateComplete () async {
179
151
final isolateRef = await _exponentialBackoff (
@@ -184,7 +156,7 @@ class VmController {
184
156
185
157
final isolate = await _exponentialBackoff (
186
158
() async => _serviceClient.getIsolate (isolateRef.id),
187
- (isolate) => isolate.pauseEvent.kind == 'PauseExit' ,
159
+ (isolate) => isolate == null || isolate .pauseEvent.kind == 'PauseExit' ,
188
160
limit: Duration (seconds: _timeout + 2 ));
189
161
190
162
_timeElapsed ?? = DateTime .now ().difference (_startTime);
@@ -234,7 +206,7 @@ class VmController {
234
206
path.join (Platform .environment['HOME' ],
235
207
'.pub-cache/global_packages/dust/bin/controller.dart.snapshot.dart2' ),
236
208
_script,
237
- " $_timeout " ,
209
+ ' $_timeout ' ,
238
210
]);
239
211
240
212
final vmCompleter = Completer ();
@@ -246,12 +218,39 @@ class VmController {
246
218
}));
247
219
_processExit = vmCompleter.future;
248
220
221
+ _outputBuffer = StringBuffer ();
249
222
_process.stdout
250
223
.transform (utf8.decoder)
251
224
.listen ((output) => _outputBuffer? .write (output));
252
225
253
226
_stdErrBuffer = StringBuffer ();
254
227
_process.stderr.transform (utf8.decoder).listen (_stdErrBuffer.write);
228
+
229
+ // Ensure observatory starts up properly.
230
+ // TODO: Try a different port on failure.
231
+ try {
232
+ await _exponentialBackoff (
233
+ () async => _outputBuffer.toString (),
234
+ (output) =>
235
+ output.contains ('listening on' ) && output.contains (':$_port /' ));
236
+ } catch (_) {
237
+ throw 'Observatory did not start on $_port \n output:\n $_outputBuffer ' ;
238
+ }
239
+ }
240
+
241
+ /// Generate a snapshot for the script, for faster fuzzing.
242
+ static Future <void > snapshot (String script, String snapshotPath) async {
243
+ final sdk = path.dirname (path.dirname (Platform .resolvedExecutable));
244
+
245
+ final result = await Process .run ('$sdk /bin/dart' , [
246
+ '--snapshot=$snapshotPath ' ,
247
+ '--snapshot-kind=kernel' ,
248
+ script,
249
+ ]);
250
+
251
+ if (result.exitCode != 0 ) {
252
+ throw '${result .stdout }${result .stderr }' ;
253
+ }
255
254
}
256
255
}
257
256
0 commit comments