From bec546eca2e95944e8dcdf10b3df573e7223e473 Mon Sep 17 00:00:00 2001 From: Danny Tuppeny Date: Sat, 15 Oct 2022 13:58:46 +0100 Subject: [PATCH] Add support for expression compilation when debugging integration tests Fixes #79439. --- .../lib/src/test/flutter_platform.dart | 20 ++++++----- .../lib/src/test/integration_test_device.dart | 8 ++++- .../integration_test_device_test.dart | 3 ++ .../expression_evaluation_test.dart | 33 +++++++++++++++++++ .../test_data/integration_tests_project.dart | 4 +-- .../test/integration.shard/test_driver.dart | 3 ++ 6 files changed, 59 insertions(+), 12 deletions(-) diff --git a/packages/flutter_tools/lib/src/test/flutter_platform.dart b/packages/flutter_tools/lib/src/test/flutter_platform.dart index eea5f7a1252ed..9a3d89d988303 100644 --- a/packages/flutter_tools/lib/src/test/flutter_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_platform.dart @@ -418,6 +418,7 @@ class FlutterPlatform extends PlatformPlugin { debuggingOptions: debuggingOptions, device: integrationTestDevice!, userIdentifier: integrationTestUserIdentifier, + compileExpression: _compileExpressionService ); } return FlutterTesterTestDevice( @@ -457,21 +458,22 @@ class FlutterPlatform extends PlatformPlugin { 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 mapping is provided, look kernel file from mapping. // If all fails, create a "listener" dart that invokes actual test. String? mainDart; if (precompiledDillPath != null) { 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) { mainDart = precompiledDillFiles![testPath]; } else { diff --git a/packages/flutter_tools/lib/src/test/integration_test_device.dart b/packages/flutter_tools/lib/src/test/integration_test_device.dart index c95db3774899b..cdf1dbd70befe 100644 --- a/packages/flutter_tools/lib/src/test/integration_test_device.dart +++ b/packages/flutter_tools/lib/src/test/integration_test_device.dart @@ -24,12 +24,14 @@ class IntegrationTestTestDevice implements TestDevice { required this.device, required this.debuggingOptions, required this.userIdentifier, + required this.compileExpression, }); final int id; final Device device; final DebuggingOptions debuggingOptions; final String? userIdentifier; + final CompileExpression? compileExpression; ApplicationPackage? _applicationPackage; final Completer _finished = Completer(); @@ -70,7 +72,11 @@ class IntegrationTestTestDevice implements TestDevice { _gotProcessObservatoryUri.complete(observatoryUri); 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), onTimeout: () => throw TimeoutException('Connecting to the VM Service timed out.'), ); diff --git a/packages/flutter_tools/test/general.shard/integration_test_device_test.dart b/packages/flutter_tools/test/general.shard/integration_test_device_test.dart index ef0fb741aaa86..6d2a90c1a36e5 100644 --- a/packages/flutter_tools/test/general.shard/integration_test_device_test.dart +++ b/packages/flutter_tools/test/general.shard/integration_test_device_test.dart @@ -77,6 +77,7 @@ void main() { BuildInfo.debug, ), userIdentifier: '', + compileExpression: null, ); fakeVmServiceHost = FakeVmServiceHost(requests: [ @@ -173,6 +174,7 @@ void main() { BuildInfo.debug, ), userIdentifier: '', + compileExpression: null, ); expect(() => testDevice.start('entrypointPath'), throwsA(isA())); @@ -201,6 +203,7 @@ void main() { BuildInfo.debug, ), userIdentifier: '', + compileExpression: null, ); expect(() => testDevice.start('entrypointPath'), throwsA(isA())); diff --git a/packages/flutter_tools/test/integration.shard/expression_evaluation_test.dart b/packages/flutter_tools/test/integration.shard/expression_evaluation_test.dart index 90ab661ad3037..6da4b413e5d6c 100644 --- a/packages/flutter_tools/test/integration.shard/expression_evaluation_test.dart +++ b/packages/flutter_tools/test/integration.shard/expression_evaluation_test.dart @@ -8,6 +8,7 @@ import 'package:vm_service/vm_service.dart'; import '../src/common.dart'; import 'test_data/basic_project.dart'; +import 'test_data/integration_tests_project.dart'; import 'test_data/tests_project.dart'; import 'test_driver.dart'; import 'test_utils.dart'; @@ -141,6 +142,37 @@ void batch2() { }); } +void batch3() { + final IntegrationTestsProject project = IntegrationTestsProject(); + late Directory tempDir; + late FlutterTestTestDriver flutter; + + Future initProject() async { + tempDir = createResolvedTempDirectorySync('integration_test_expression_eval_test.'); + await project.setUpIn(tempDir); + flutter = FlutterTestTestDriver(tempDir); + } + + Future 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 evaluateTrivialExpressions(FlutterTestDriver flutter) async { ObjRef res; @@ -189,4 +221,5 @@ void expectValue(ObjRef result, String message) { void main() { batch1(); batch2(); + batch3(); } diff --git a/packages/flutter_tools/test/integration.shard/test_data/integration_tests_project.dart b/packages/flutter_tools/test/integration.shard/test_data/integration_tests_project.dart index c1cb36516d403..8d24a8523c10b 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/integration_tests_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/integration_tests_project.dart @@ -58,11 +58,11 @@ class IntegrationTestsProject extends Project implements TestsProject { String get testFilePath => fileSystem.path.join(dir.path, 'integration_test', 'app_test.dart'); @override - Uri get breakpointUri => throw UnimplementedError(); + Uri get breakpointUri => Uri.file(testFilePath); @override Uri get breakpointAppUri => throw UnimplementedError(); @override - int get breakpointLine => throw UnimplementedError(); + int get breakpointLine => lineContaining(testContent, '// BREAKPOINT'); } diff --git a/packages/flutter_tools/test/integration.shard/test_driver.dart b/packages/flutter_tools/test/integration.shard/test_driver.dart index 654efbd1593bc..19063d0cad2b9 100644 --- a/packages/flutter_tools/test/integration.shard/test_driver.dart +++ b/packages/flutter_tools/test/integration.shard/test_driver.dart @@ -763,6 +763,7 @@ class FlutterTestTestDriver extends FlutterTestDriver { Future test({ String testFile = 'test/test.dart', + String? deviceId, bool withDebugger = false, bool pauseOnExceptions = false, bool coverage = false, @@ -775,6 +776,8 @@ class FlutterTestTestDriver extends FlutterTestDriver { '--machine', if (coverage) '--coverage', + if (deviceId != null) + ...['-d', deviceId], ], script: testFile, withDebugger: withDebugger, pauseOnExceptions: pauseOnExceptions, beforeStart: beforeStart); }