| // 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:io'; |
| |
| import 'package:flutter_devicelab/framework/utils.dart' show rm; |
| import 'package:path/path.dart' as path; |
| import 'package:process/process.dart'; |
| |
| import 'common.dart'; |
| |
| void main() { |
| const ProcessManager processManager = LocalProcessManager(); |
| |
| group('run.dart script', () { |
| Future<ProcessResult> runScript(List<String> testNames, |
| [List<String> otherArgs = const <String>[]]) async { |
| final String dart = path.absolute( |
| path.join('..', '..', 'bin', 'cache', 'dart-sdk', 'bin', 'dart')); |
| final ProcessResult scriptProcess = processManager.runSync(<String>[ |
| dart, |
| 'bin/run.dart', |
| '--no-terminate-stray-dart-processes', |
| ...otherArgs, |
| for (final String testName in testNames) ...<String>['-t', testName], |
| ]); |
| return scriptProcess; |
| } |
| |
| Future<void> expectScriptResult( |
| List<String> testNames, |
| int expectedExitCode, |
| {String? deviceId} |
| ) async { |
| final ProcessResult result = await runScript(testNames, <String>[ |
| if (deviceId != null) ...<String>['-d', deviceId], |
| ]); |
| expect(result.exitCode, expectedExitCode, |
| reason: |
| '[ stderr from test process ]\n\n${result.stderr}\n\n[ end of stderr ]' |
| '\n\n[ stdout from test process ]\n\n${result.stdout}\n\n[ end of stdout ]'); |
| } |
| |
| test('exits with code 0 when succeeds', () async { |
| await expectScriptResult(<String>['smoke_test_success'], 0); |
| }); |
| |
| test('accepts file paths', () async { |
| await expectScriptResult( |
| <String>['bin/tasks/smoke_test_success.dart'], 0); |
| }); |
| |
| test('rejects invalid file paths', () async { |
| await expectScriptResult(<String>['lib/framework/adb.dart'], 1); |
| }); |
| |
| test('exits with code 1 when task throws', () async { |
| await expectScriptResult(<String>['smoke_test_throws'], 1); |
| }); |
| |
| test('exits with code 1 when fails', () async { |
| await expectScriptResult(<String>['smoke_test_failure'], 1); |
| }); |
| |
| test('exits with code 1 when fails to connect', () async { |
| await expectScriptResult(<String>['smoke_test_setup_failure'], 1); |
| }, skip: true); // https://github.com/flutter/flutter/issues/53707 |
| |
| test('exits with code 1 when results are mixed', () async { |
| await expectScriptResult( |
| <String>[ |
| 'smoke_test_failure', |
| 'smoke_test_success', |
| ], |
| 1, |
| ); |
| }); |
| |
| test('exits with code 0 when provided a valid device ID', () async { |
| await expectScriptResult(<String>['smoke_test_device'], 0, |
| deviceId: 'FAKE'); |
| }); |
| |
| test('exits with code 1 when provided a bad device ID', () async { |
| await expectScriptResult(<String>['smoke_test_device'], 1, |
| deviceId: 'THIS_IS_NOT_VALID'); |
| }); |
| |
| |
| test('runs A/B test', () async { |
| final Directory tempDirectory = Directory.systemTemp.createTempSync('flutter_devicelab_ab_test.'); |
| final File abResultsFile = File(path.join(tempDirectory.path, 'test_results.json')); |
| |
| expect(abResultsFile.existsSync(), isFalse); |
| |
| final ProcessResult result = await runScript( |
| <String>['smoke_test_success'], |
| <String>['--ab=2', '--local-engine=host_debug_unopt', '--ab-result-file', abResultsFile.path], |
| ); |
| expect(result.exitCode, 0); |
| |
| String sectionHeader = !Platform.isWindows |
| ? '═════════════════════════╡ ••• A/B results so far ••• ╞═════════════════════════' |
| : 'A/B results so far'; |
| expect( |
| result.stdout, |
| contains( |
| '$sectionHeader\n' |
| '\n' |
| 'Score\tAverage A (noise)\tAverage B (noise)\tSpeed-up\n' |
| 'metric1\t42.00 (0.00%)\t42.00 (0.00%)\t1.00x\t\n' |
| 'metric2\t123.00 (0.00%)\t123.00 (0.00%)\t1.00x\t\n', |
| ), |
| ); |
| |
| sectionHeader = !Platform.isWindows |
| ? '════════════════════════════╡ ••• Raw results ••• ╞═════════════════════════════' |
| : 'Raw results'; |
| expect( |
| result.stdout, |
| contains( |
| '$sectionHeader\n' |
| '\n' |
| 'metric1:\n' |
| ' A:\t42.00\t42.00\t\n' |
| ' B:\t42.00\t42.00\t\n' |
| 'metric2:\n' |
| ' A:\t123.00\t123.00\t\n' |
| ' B:\t123.00\t123.00\t\n', |
| ), |
| ); |
| |
| sectionHeader = !Platform.isWindows |
| ? '═════════════════════════╡ ••• Final A/B results ••• ╞══════════════════════════' |
| : 'Final A/B results'; |
| expect( |
| result.stdout, |
| contains( |
| '$sectionHeader\n' |
| '\n' |
| 'Score\tAverage A (noise)\tAverage B (noise)\tSpeed-up\n' |
| 'metric1\t42.00 (0.00%)\t42.00 (0.00%)\t1.00x\t\n' |
| 'metric2\t123.00 (0.00%)\t123.00 (0.00%)\t1.00x\t\n', |
| ), |
| ); |
| |
| expect(abResultsFile.existsSync(), isTrue); |
| rm(tempDirectory, recursive: true); |
| }); |
| |
| test('fails to upload results to Cocoon if flags given', () async { |
| // CocoonClient will fail to find test-file, and will not send any http requests. |
| final ProcessResult result = await runScript( |
| <String>['smoke_test_success'], |
| <String>['--service-account-file=test-file', '--task-key=task123'], |
| ); |
| expect(result.exitCode, 1); |
| }); |
| }); |
| } |