Skip to content

Commit 3354ea5

Browse files
authored
Expand expression evaluation tests to also test DDC module format + canary (#2465)
DDC hot reload requires a new module format. This is represented by the intersection of the DDC module format and canary. In order to make sure the new format is tested, this changes replicates any existing expression evaluation tests to use the DDC module format and canary.
1 parent e7c156c commit 3354ea5

5 files changed

+473
-347
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) 2024, 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+
@Tags(['daily'])
6+
@TestOn('vm')
7+
@Timeout(Duration(minutes: 2))
8+
library;
9+
10+
import 'package:dwds/expression_compiler.dart';
11+
import 'package:test/test.dart';
12+
import 'package:test_common/test_sdk_configuration.dart';
13+
14+
import 'evaluate_common.dart';
15+
import 'fixtures/context.dart';
16+
17+
void main() async {
18+
// Enable verbose logging for debugging.
19+
final debug = false;
20+
21+
final provider = TestSdkConfigurationProvider(
22+
verbose: debug,
23+
ddcModuleFormat: ModuleFormat.ddc,
24+
canaryFeatures: true,
25+
);
26+
tearDownAll(provider.dispose);
27+
28+
testAll(
29+
provider: provider,
30+
compilationMode: CompilationMode.buildDaemon,
31+
debug: debug,
32+
);
33+
}
Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
// Copyright (c) 2024, 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+
@TestOn('vm')
6+
@Timeout(Duration(minutes: 2))
7+
library;
8+
9+
import 'dart:async';
10+
import 'dart:convert';
11+
import 'dart:io';
12+
13+
import 'package:dwds/sdk_configuration.dart';
14+
import 'package:dwds/src/services/expression_compiler.dart';
15+
import 'package:dwds/src/services/expression_compiler_service.dart';
16+
import 'package:dwds/src/utilities/server.dart';
17+
import 'package:logging/logging.dart';
18+
import 'package:shelf/shelf.dart';
19+
import 'package:test/test.dart';
20+
import 'package:test_common/logging.dart';
21+
22+
ExpressionCompilerService get service => _service!;
23+
late ExpressionCompilerService? _service;
24+
25+
HttpServer get server => _server!;
26+
late HttpServer? _server;
27+
28+
StreamController<String> get output => _output!;
29+
late StreamController<String>? _output;
30+
31+
void testAll({required CompilerOptions compilerOptions}) {
32+
group('expression compiler service with fake asset server', () {
33+
final logger = Logger('ExpressionCompilerServiceTest');
34+
late Directory outputDir;
35+
36+
Future<void> stop() async {
37+
await _service?.stop();
38+
await _server?.close();
39+
await _output?.close();
40+
_service = null;
41+
_server = null;
42+
_output = null;
43+
}
44+
45+
setUp(() async {
46+
final systemTempDir = Directory.systemTemp;
47+
outputDir = systemTempDir.createTempSync('foo bar');
48+
final source = outputDir.uri.resolve('try.dart');
49+
final packages = outputDir.uri.resolve('package_config.json');
50+
final kernel = outputDir.uri.resolve('try.full.dill');
51+
// Expression compiler service does not need any extra assets
52+
// generated in the SDK, so we use the current SDK layout and
53+
// configuration.
54+
final executable = Platform.resolvedExecutable;
55+
final dartdevc =
56+
SdkConfiguration.defaultConfiguration.compilerWorkerPath!;
57+
// redirect logs for testing
58+
_output = StreamController<String>.broadcast();
59+
output.stream.listen(printOnFailure);
60+
61+
configureLogWriter(
62+
customLogWriter: (level, message, {error, loggerName, stackTrace}) {
63+
final e = error == null ? '' : ': $error';
64+
final s = stackTrace == null ? '' : ':\n$stackTrace';
65+
output.add('[$level] $loggerName: $message$e$s');
66+
},
67+
);
68+
69+
// start asset server
70+
_server = await startHttpServer('localhost');
71+
final port = server.port;
72+
73+
// start expression compilation service
74+
Response assetHandler(request) =>
75+
Response(200, body: File.fromUri(kernel).readAsBytesSync());
76+
_service = ExpressionCompilerService(
77+
'localhost',
78+
port,
79+
verbose: false,
80+
sdkConfigurationProvider: DefaultSdkConfigurationProvider(),
81+
);
82+
83+
await service.initialize(compilerOptions);
84+
85+
// setup asset server
86+
serveHttpRequests(server, assetHandler, (e, s) {
87+
logger.warning('Error serving requests', e, s);
88+
});
89+
90+
// generate full dill
91+
File.fromUri(source)
92+
..createSync()
93+
..writeAsStringSync('''void main() {
94+
// breakpoint line
95+
}''');
96+
97+
File.fromUri(packages)
98+
..createSync()
99+
..writeAsStringSync('''
100+
{
101+
"configVersion": 2,
102+
"packages": [
103+
{
104+
"name": "try",
105+
"rootUri": "./",
106+
"packageUri": "./"
107+
}
108+
]
109+
}
110+
''');
111+
112+
final args = [
113+
dartdevc,
114+
'try.dart',
115+
'-o',
116+
'try.js',
117+
'--experimental-output-compiled-kernel',
118+
'--multi-root',
119+
'${outputDir.uri}',
120+
'--multi-root-scheme',
121+
'org-dartlang-app',
122+
'--packages',
123+
packages.path,
124+
];
125+
final process = await Process.start(
126+
executable,
127+
args,
128+
workingDirectory: outputDir.path,
129+
).then((p) {
130+
transformToLines(p.stdout).listen(output.add);
131+
transformToLines(p.stderr).listen(output.add);
132+
return p;
133+
});
134+
expect(
135+
await process.exitCode,
136+
0,
137+
reason: 'failed running $executable with args $args',
138+
);
139+
expect(
140+
File.fromUri(kernel).existsSync(),
141+
true,
142+
reason: 'failed to create full dill',
143+
);
144+
});
145+
146+
tearDown(() async {
147+
await stop();
148+
outputDir.deleteSync(recursive: true);
149+
});
150+
151+
test('works with no errors', () async {
152+
expect(output.stream, neverEmits(contains('[SEVERE]')));
153+
expect(
154+
output.stream,
155+
emitsThrough(
156+
contains(
157+
'[INFO] ExpressionCompilerService: Updating dependencies...',
158+
),
159+
),
160+
);
161+
expect(
162+
output.stream,
163+
emitsThrough(
164+
contains(
165+
'[INFO] ExpressionCompilerService: Updated dependencies.',
166+
),
167+
),
168+
);
169+
expect(
170+
output.stream,
171+
emitsThrough(
172+
contains(
173+
'[FINEST] ExpressionCompilerService: Compiling "true" at',
174+
),
175+
),
176+
);
177+
expect(
178+
output.stream,
179+
emitsThrough(
180+
contains(
181+
'[FINEST] ExpressionCompilerService: Compiled "true" to:',
182+
),
183+
),
184+
);
185+
expect(
186+
output.stream,
187+
emitsThrough(contains('[INFO] ExpressionCompilerService: Stopped.')),
188+
);
189+
final result = await service
190+
.updateDependencies({'try': ModuleInfo('try.full.dill', 'try.dill')});
191+
expect(result, true, reason: 'failed to update dependencies');
192+
193+
final compilationResult = await service.compileExpressionToJs(
194+
'0',
195+
'org-dartlang-app:/try.dart',
196+
2,
197+
1,
198+
{},
199+
{},
200+
'try',
201+
'true',
202+
);
203+
204+
expect(
205+
compilationResult,
206+
isA<ExpressionCompilationResult>()
207+
.having((r) => r.result, 'result', contains('return true;'))
208+
.having((r) => r.isError, 'isError', false),
209+
);
210+
211+
await stop();
212+
});
213+
214+
test('can evaluate multiple expressions', () async {
215+
expect(output.stream, neverEmits(contains('[SEVERE]')));
216+
expect(
217+
output.stream,
218+
emitsThrough(
219+
contains(
220+
'[INFO] ExpressionCompilerService: Updating dependencies...',
221+
),
222+
),
223+
);
224+
expect(
225+
output.stream,
226+
emitsThrough(
227+
contains(
228+
'[INFO] ExpressionCompilerService: Updated dependencies.',
229+
),
230+
),
231+
);
232+
233+
expect(
234+
output.stream,
235+
emitsThrough(contains('[INFO] ExpressionCompilerService: Stopped.')),
236+
);
237+
final result = await service
238+
.updateDependencies({'try': ModuleInfo('try.full.dill', 'try.dill')});
239+
expect(result, true, reason: 'failed to update dependencies');
240+
241+
final compilationResult1 = await service.compileExpressionToJs(
242+
'0',
243+
'org-dartlang-app:/try.dart',
244+
2,
245+
1,
246+
{},
247+
{},
248+
'try',
249+
'true',
250+
);
251+
final compilationResult2 = await service.compileExpressionToJs(
252+
'0',
253+
'org-dartlang-app:/try.dart',
254+
2,
255+
1,
256+
{},
257+
{},
258+
'try',
259+
'false',
260+
);
261+
262+
expect(
263+
compilationResult1,
264+
isA<ExpressionCompilationResult>()
265+
.having((r) => r.result, 'result', contains('return true;'))
266+
.having((r) => r.isError, 'isError', false),
267+
);
268+
269+
expect(
270+
compilationResult2,
271+
isA<ExpressionCompilationResult>()
272+
.having((r) => r.result, 'result', contains('return false;'))
273+
.having((r) => r.isError, 'isError', false),
274+
);
275+
276+
await stop();
277+
});
278+
279+
test('can compile multiple expressions in parallel', () async {
280+
expect(output.stream, neverEmits(contains('[SEVERE]')));
281+
expect(
282+
output.stream,
283+
emitsThrough(
284+
contains(
285+
'[INFO] ExpressionCompilerService: Updating dependencies...',
286+
),
287+
),
288+
);
289+
expect(
290+
output.stream,
291+
emitsThrough(
292+
contains(
293+
'[INFO] ExpressionCompilerService: Updated dependencies.',
294+
),
295+
),
296+
);
297+
298+
expect(
299+
output.stream,
300+
emitsThrough(contains('[INFO] ExpressionCompilerService: Stopped.')),
301+
);
302+
final result = await service
303+
.updateDependencies({'try': ModuleInfo('try.full.dill', 'try.dill')});
304+
expect(result, true, reason: 'failed to update dependencies');
305+
306+
final compilationResult1 = service.compileExpressionToJs(
307+
'0',
308+
'org-dartlang-app:/try.dart',
309+
2,
310+
1,
311+
{},
312+
{},
313+
'try',
314+
'true',
315+
);
316+
final compilationResult2 = service.compileExpressionToJs(
317+
'0',
318+
'org-dartlang-app:/try.dart',
319+
2,
320+
1,
321+
{},
322+
{},
323+
'try',
324+
'false',
325+
);
326+
327+
final results =
328+
await Future.wait([compilationResult1, compilationResult2]);
329+
330+
expect(
331+
results[0],
332+
isA<ExpressionCompilationResult>()
333+
.having((r) => r.result, 'result', contains('return true;'))
334+
.having((r) => r.isError, 'isError', false),
335+
);
336+
337+
expect(
338+
results[1],
339+
isA<ExpressionCompilationResult>()
340+
.having((r) => r.result, 'result', contains('return false;'))
341+
.having((r) => r.isError, 'isError', false),
342+
);
343+
344+
await stop();
345+
});
346+
});
347+
}
348+
349+
Stream<String> transformToLines(Stream<List<int>> byteStream) {
350+
return byteStream
351+
.transform<String>(utf8.decoder)
352+
.transform<String>(const LineSplitter());
353+
}

0 commit comments

Comments
 (0)