| // 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<void> main() async { |
| test('verify terminating flutter/bin/dart terminates the underlying dart process', () async { |
| final Completer<void> childReadyCompleter = Completer<void>(); |
| String stdout = ''; |
| final Process process = await processManager.start( |
| <String>[ |
| dartBash.path, |
| listenForSigtermScript.path, |
| ], |
| ); |
| final Future<Object?> stdoutFuture = process.stdout |
| .transform<String>(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 |
| |
| test('shared.sh does not compile flutter tool if PROG_NAME=dart', () async { |
| final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('bash_entrypoint_test'); |
| try { |
| // bash script checks it is in a git repo |
| ProcessResult result = await processManager.run(<String>['git', 'init'], workingDirectory: tempDir.path); |
| expect(result, const ProcessResultMatcher()); |
| result = await processManager.run(<String>['git', 'commit', '--allow-empty', '-m', 'init commit'], workingDirectory: tempDir.path); |
| expect(result, const ProcessResultMatcher()); |
| |
| // copy dart and shared.sh to temp dir |
| final File trueSharedSh = flutterRoot.childDirectory('bin').childDirectory('internal').childFile('shared.sh'); |
| final File fakeSharedSh = (tempDir.childDirectory('bin').childDirectory('internal') |
| ..createSync(recursive: true)) |
| .childFile('shared.sh'); |
| trueSharedSh.copySync(fakeSharedSh.path); |
| final File fakeDartBash = tempDir.childDirectory('bin').childFile('dart'); |
| dartBash.copySync(fakeDartBash.path); |
| // mark dart executable |
| makeExecutable(fakeDartBash); |
| |
| // create no-op fake update_dart_sdk.sh script |
| final File updateDartSdk = tempDir.childDirectory('bin').childDirectory('internal').childFile('update_dart_sdk.sh')..writeAsStringSync(''' |
| #!/usr/bin/env bash |
| |
| echo downloaded dart sdk |
| '''); |
| makeExecutable(updateDartSdk); |
| |
| // create a fake dart runtime |
| final File dartBin = (tempDir.childDirectory('bin') |
| .childDirectory('cache') |
| .childDirectory('dart-sdk') |
| .childDirectory('bin') |
| ..createSync(recursive: true)) |
| .childFile('dart'); |
| dartBin.writeAsStringSync(''' |
| #!/usr/bin/env bash |
| |
| echo executed dart binary |
| '''); |
| makeExecutable(dartBin); |
| |
| result = await processManager.run(<String>[fakeDartBash.path]); |
| expect(result, const ProcessResultMatcher()); |
| expect( |
| (result.stdout as String).split('\n'), |
| // verify we ran updateDartSdk and dartBin |
| containsAll(<String>['downloaded dart sdk', 'executed dart binary']), |
| ); |
| |
| // Verify we did not try to compile the flutter_tool |
| expect(result.stderr, isNot(contains('Building flutter tool...'))); |
| } finally { |
| tryToDelete(tempDir); |
| } |
| }, |
| 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; |
| } |
| |
| void makeExecutable(File file) { |
| final ProcessResult result = processManager.runSync(<String>['chmod', '+x', file.path]); |
| expect(result, const ProcessResultMatcher()); |
| } |