From bb4a5fa7ab825c3ab6541cf70353aaa7eb301aef Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Mon, 14 Mar 2022 13:35:18 -0700 Subject: [PATCH] [flutter_tools] exec rather than spawn subprocess from bin/internal/shared.sh (#99871) --- bin/internal/shared.sh | 4 +- .../bash_entrypoint_test.dart | 71 +++++++++++++++++++ .../test_data/listen_for_sigterm.dart | 25 +++++++ 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 packages/flutter_tools/test/integration.shard/bash_entrypoint_test.dart create mode 100644 packages/flutter_tools/test/integration.shard/test_data/listen_for_sigterm.dart diff --git a/bin/internal/shared.sh b/bin/internal/shared.sh index 50ffcd4c287..f38522959e6 100644 --- a/bin/internal/shared.sh +++ b/bin/internal/shared.sh @@ -222,10 +222,10 @@ function shared::execute() { flutter*) # FLUTTER_TOOL_ARGS aren't quoted below, because it is meant to be # considered as separate space-separated args. - "$DART" --disable-dart-dev --packages="$FLUTTER_TOOLS_DIR/.packages" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@" + exec "$DART" --disable-dart-dev --packages="$FLUTTER_TOOLS_DIR/.packages" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@" ;; dart*) - "$DART" "$@" + exec "$DART" "$@" ;; *) >&2 echo "Error! Executable name $BIN_NAME not recognized!" diff --git a/packages/flutter_tools/test/integration.shard/bash_entrypoint_test.dart b/packages/flutter_tools/test/integration.shard/bash_entrypoint_test.dart new file mode 100644 index 00000000000..7377889c24e --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/bash_entrypoint_test.dart @@ -0,0 +1,71 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:convert'; + +import 'package:file/file.dart'; +import 'package:flutter_tools/src/base/io.dart'; + +import '../src/common.dart'; +import 'test_utils.dart'; + +final String flutterRootPath = getFlutterRoot(); +final Directory flutterRoot = fileSystem.directory(flutterRootPath); + +Future main() async { + test('verify terminating flutter/bin/dart terminates the underlying dart process', () async { + final Completer childReadyCompleter = Completer(); + String stdout = ''; + final Process process = await processManager.start( + [ + dartBash.path, + listenForSigtermScript.path, + ], + ); + final Future stdoutFuture = process.stdout + .transform(utf8.decoder) + .forEach((String str) { + stdout += str; + if (stdout.contains('Ready to receive signals') && !childReadyCompleter.isCompleted) { + childReadyCompleter.complete(); + } + }); + // Ensure that the child app has registered its signal handler + await childReadyCompleter.future; + final bool killSuccess = process.kill(); + expect(killSuccess, true); + // Wait for stdout to complete + await stdoutFuture; + // Ensure child exited successfully + expect( + await process.exitCode, + 0, + reason: 'child process exited with code ${await process.exitCode}, and ' + 'stdout:\n$stdout', + ); + expect(stdout, contains('Successfully received SIGTERM!')); + }, + skip: platform.isWindows); // [intended] Windows does not use the bash entrypoint +} + +// A test Dart app that will run until it receives SIGTERM +File get listenForSigtermScript { + return flutterRoot + .childDirectory('packages') + .childDirectory('flutter_tools') + .childDirectory('test') + .childDirectory('integration.shard') + .childDirectory('test_data') + .childFile('listen_for_sigterm.dart') + .absolute; +} + +// The executable bash entrypoint for the Dart binary. +File get dartBash { + return flutterRoot + .childDirectory('bin') + .childFile('dart') + .absolute; +} diff --git a/packages/flutter_tools/test/integration.shard/test_data/listen_for_sigterm.dart b/packages/flutter_tools/test/integration.shard/test_data/listen_for_sigterm.dart new file mode 100644 index 00000000000..69859675237 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/test_data/listen_for_sigterm.dart @@ -0,0 +1,25 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'package:flutter_tools/src/base/io.dart'; + +// This application will log to STDOUT and exit with 0 when it receives the +// SIGTERM signal. +Future main() async { + final Stdout stdout = Stdio().stdout; + final Stream interruptStream = ProcessSignal.sigterm.watch(); + interruptStream.listen((_) { + // The test should assert that this was logged + stdout.writeln('Successfully received SIGTERM!'); + exit(0); + }); + // The test should wait for this message before sending SIGTERM, or else the + // listener may not have been registered. + stdout.writeln('Ready to receive signals'); + + await Future.delayed(const Duration(seconds: 10)); + stdout.writeln('Did not receive SIGTERM!'); + exit(1); +}