Unverified Commit 3599b3a8 authored by Danny Tuppeny's avatar Danny Tuppeny Committed by GitHub

Add support for expression compilation when debugging integration tests (#113481)

Fixes #79439.
parent 5304a241
...@@ -418,6 +418,7 @@ class FlutterPlatform extends PlatformPlugin { ...@@ -418,6 +418,7 @@ class FlutterPlatform extends PlatformPlugin {
debuggingOptions: debuggingOptions, debuggingOptions: debuggingOptions,
device: integrationTestDevice!, device: integrationTestDevice!,
userIdentifier: integrationTestUserIdentifier, userIdentifier: integrationTestUserIdentifier,
compileExpression: _compileExpressionService
); );
} }
return FlutterTesterTestDevice( return FlutterTesterTestDevice(
...@@ -457,21 +458,22 @@ class FlutterPlatform extends PlatformPlugin { ...@@ -457,21 +458,22 @@ class FlutterPlatform extends PlatformPlugin {
controllerSinkClosed = true; controllerSinkClosed = true;
})); }));
// When start paused is specified, it means that the user is likely
// running this with a debugger attached. Initialize the resident
// compiler in this case.
if (debuggingOptions.startPaused) {
compiler ??= TestCompiler(debuggingOptions.buildInfo, flutterProject, precompiledDillPath: precompiledDillPath, testTimeRecorder: testTimeRecorder);
final Uri testUri = globals.fs.file(testPath).uri;
// Trigger a compilation to initialize the resident compiler.
unawaited(compiler!.compile(testUri));
}
// If a kernel file is given, then use that to launch the test. // If a kernel file is given, then use that to launch the test.
// If mapping is provided, look kernel file from mapping. // If mapping is provided, look kernel file from mapping.
// If all fails, create a "listener" dart that invokes actual test. // If all fails, create a "listener" dart that invokes actual test.
String? mainDart; String? mainDart;
if (precompiledDillPath != null) { if (precompiledDillPath != null) {
mainDart = precompiledDillPath; mainDart = precompiledDillPath;
// When start paused is specified, it means that the user is likely
// running this with a debugger attached. Initialize the resident
// compiler in this case.
if (debuggingOptions.startPaused) {
compiler ??= TestCompiler(debuggingOptions.buildInfo, flutterProject, precompiledDillPath: precompiledDillPath, testTimeRecorder: testTimeRecorder);
final Uri testUri = globals.fs.file(testPath).uri;
// Trigger a compilation to initialize the resident compiler.
unawaited(compiler!.compile(testUri));
}
} else if (precompiledDillFiles != null) { } else if (precompiledDillFiles != null) {
mainDart = precompiledDillFiles![testPath]; mainDart = precompiledDillFiles![testPath];
} else { } else {
......
...@@ -24,12 +24,14 @@ class IntegrationTestTestDevice implements TestDevice { ...@@ -24,12 +24,14 @@ class IntegrationTestTestDevice implements TestDevice {
required this.device, required this.device,
required this.debuggingOptions, required this.debuggingOptions,
required this.userIdentifier, required this.userIdentifier,
required this.compileExpression,
}); });
final int id; final int id;
final Device device; final Device device;
final DebuggingOptions debuggingOptions; final DebuggingOptions debuggingOptions;
final String? userIdentifier; final String? userIdentifier;
final CompileExpression? compileExpression;
ApplicationPackage? _applicationPackage; ApplicationPackage? _applicationPackage;
final Completer<void> _finished = Completer<void>(); final Completer<void> _finished = Completer<void>();
...@@ -70,7 +72,11 @@ class IntegrationTestTestDevice implements TestDevice { ...@@ -70,7 +72,11 @@ class IntegrationTestTestDevice implements TestDevice {
_gotProcessObservatoryUri.complete(observatoryUri); _gotProcessObservatoryUri.complete(observatoryUri);
globals.printTrace('test $id: Connecting to vm service'); globals.printTrace('test $id: Connecting to vm service');
final FlutterVmService vmService = await connectToVmService(observatoryUri, logger: globals.logger).timeout( final FlutterVmService vmService = await connectToVmService(
observatoryUri,
logger: globals.logger,
compileExpression: compileExpression,
).timeout(
const Duration(seconds: 5), const Duration(seconds: 5),
onTimeout: () => throw TimeoutException('Connecting to the VM Service timed out.'), onTimeout: () => throw TimeoutException('Connecting to the VM Service timed out.'),
); );
......
...@@ -77,6 +77,7 @@ void main() { ...@@ -77,6 +77,7 @@ void main() {
BuildInfo.debug, BuildInfo.debug,
), ),
userIdentifier: '', userIdentifier: '',
compileExpression: null,
); );
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[ fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...@@ -173,6 +174,7 @@ void main() { ...@@ -173,6 +174,7 @@ void main() {
BuildInfo.debug, BuildInfo.debug,
), ),
userIdentifier: '', userIdentifier: '',
compileExpression: null,
); );
expect(() => testDevice.start('entrypointPath'), throwsA(isA<TestDeviceException>())); expect(() => testDevice.start('entrypointPath'), throwsA(isA<TestDeviceException>()));
...@@ -201,6 +203,7 @@ void main() { ...@@ -201,6 +203,7 @@ void main() {
BuildInfo.debug, BuildInfo.debug,
), ),
userIdentifier: '', userIdentifier: '',
compileExpression: null,
); );
expect(() => testDevice.start('entrypointPath'), throwsA(isA<TestDeviceException>())); expect(() => testDevice.start('entrypointPath'), throwsA(isA<TestDeviceException>()));
......
...@@ -8,6 +8,7 @@ import 'package:vm_service/vm_service.dart'; ...@@ -8,6 +8,7 @@ import 'package:vm_service/vm_service.dart';
import '../src/common.dart'; import '../src/common.dart';
import 'test_data/basic_project.dart'; import 'test_data/basic_project.dart';
import 'test_data/integration_tests_project.dart';
import 'test_data/tests_project.dart'; import 'test_data/tests_project.dart';
import 'test_driver.dart'; import 'test_driver.dart';
import 'test_utils.dart'; import 'test_utils.dart';
...@@ -141,6 +142,37 @@ void batch2() { ...@@ -141,6 +142,37 @@ void batch2() {
}); });
} }
void batch3() {
final IntegrationTestsProject project = IntegrationTestsProject();
late Directory tempDir;
late FlutterTestTestDriver flutter;
Future<void> initProject() async {
tempDir = createResolvedTempDirectorySync('integration_test_expression_eval_test.');
await project.setUpIn(tempDir);
flutter = FlutterTestTestDriver(tempDir);
}
Future<void> cleanProject() async {
await flutter.waitForCompletion();
tryToDelete(tempDir);
}
testWithoutContext('flutter integration test expression evaluation - can evaluate expressions in a test', () async {
await initProject();
await flutter.test(
deviceId: 'flutter-tester',
testFile: project.testFilePath,
withDebugger: true,
beforeStart: () => flutter.addBreakpoint(project.breakpointUri, project.breakpointLine),
);
await flutter.waitForPause();
await evaluateTrivialExpressions(flutter);
await cleanProject();
});
}
Future<void> evaluateTrivialExpressions(FlutterTestDriver flutter) async { Future<void> evaluateTrivialExpressions(FlutterTestDriver flutter) async {
ObjRef res; ObjRef res;
...@@ -189,4 +221,5 @@ void expectValue(ObjRef result, String message) { ...@@ -189,4 +221,5 @@ void expectValue(ObjRef result, String message) {
void main() { void main() {
batch1(); batch1();
batch2(); batch2();
batch3();
} }
...@@ -58,11 +58,11 @@ class IntegrationTestsProject extends Project implements TestsProject { ...@@ -58,11 +58,11 @@ class IntegrationTestsProject extends Project implements TestsProject {
String get testFilePath => fileSystem.path.join(dir.path, 'integration_test', 'app_test.dart'); String get testFilePath => fileSystem.path.join(dir.path, 'integration_test', 'app_test.dart');
@override @override
Uri get breakpointUri => throw UnimplementedError(); Uri get breakpointUri => Uri.file(testFilePath);
@override @override
Uri get breakpointAppUri => throw UnimplementedError(); Uri get breakpointAppUri => throw UnimplementedError();
@override @override
int get breakpointLine => throw UnimplementedError(); int get breakpointLine => lineContaining(testContent, '// BREAKPOINT');
} }
...@@ -763,6 +763,7 @@ class FlutterTestTestDriver extends FlutterTestDriver { ...@@ -763,6 +763,7 @@ class FlutterTestTestDriver extends FlutterTestDriver {
Future<void> test({ Future<void> test({
String testFile = 'test/test.dart', String testFile = 'test/test.dart',
String? deviceId,
bool withDebugger = false, bool withDebugger = false,
bool pauseOnExceptions = false, bool pauseOnExceptions = false,
bool coverage = false, bool coverage = false,
...@@ -775,6 +776,8 @@ class FlutterTestTestDriver extends FlutterTestDriver { ...@@ -775,6 +776,8 @@ class FlutterTestTestDriver extends FlutterTestDriver {
'--machine', '--machine',
if (coverage) if (coverage)
'--coverage', '--coverage',
if (deviceId != null)
...<String>['-d', deviceId],
], script: testFile, withDebugger: withDebugger, pauseOnExceptions: pauseOnExceptions, beforeStart: beforeStart); ], script: testFile, withDebugger: withDebugger, pauseOnExceptions: pauseOnExceptions, beforeStart: beforeStart);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment