Commit b2323889 authored by Dan Field's avatar Dan Field Committed by Flutter GitHub Bot

Pipe through test-randomize-ordering-seed (#47243)

parent b39ebcb5
...@@ -22,6 +22,7 @@ import 'package:flutter_tools/src/project.dart'; ...@@ -22,6 +22,7 @@ import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/test/coverage_collector.dart'; import 'package:flutter_tools/src/test/coverage_collector.dart';
import 'package:flutter_tools/src/test/runner.dart'; import 'package:flutter_tools/src/test/runner.dart';
import 'package:flutter_tools/src/test/test_wrapper.dart';
// This was largely inspired by lib/src/commands/test.dart. // This was largely inspired by lib/src/commands/test.dart.
...@@ -142,6 +143,7 @@ Future<void> run(List<String> args) async { ...@@ -142,6 +143,7 @@ Future<void> run(List<String> args) async {
} }
exitCode = await runTests( exitCode = await runTests(
const TestWrapper(),
tests.keys.toList(), tests.keys.toList(),
workDir: testDirectory, workDir: testDirectory,
watcher: collector, watcher: collector,
......
...@@ -21,10 +21,14 @@ import '../runner/flutter_command.dart'; ...@@ -21,10 +21,14 @@ import '../runner/flutter_command.dart';
import '../test/coverage_collector.dart'; import '../test/coverage_collector.dart';
import '../test/event_printer.dart'; import '../test/event_printer.dart';
import '../test/runner.dart'; import '../test/runner.dart';
import '../test/test_wrapper.dart';
import '../test/watcher.dart'; import '../test/watcher.dart';
class TestCommand extends FastFlutterCommand { class TestCommand extends FastFlutterCommand {
TestCommand({ bool verboseHelp = false }) { TestCommand({
bool verboseHelp = false,
this.testWrapper = const TestWrapper(),
}) : assert(testWrapper != null) {
requiresPubspecYaml(); requiresPubspecYaml();
usesPubOption(); usesPubOption();
argParser argParser
...@@ -100,10 +104,20 @@ class TestCommand extends FastFlutterCommand { ...@@ -100,10 +104,20 @@ class TestCommand extends FastFlutterCommand {
allowed: const <String>['tester', 'chrome'], allowed: const <String>['tester', 'chrome'],
defaultsTo: 'tester', defaultsTo: 'tester',
help: 'The platform to run the unit tests on. Defaults to "tester".', help: 'The platform to run the unit tests on. Defaults to "tester".',
)
..addOption('test-randomize-ordering-seed',
defaultsTo: '0',
help: 'If positive, use this as a seed to randomize the execution of '
'test cases (must be a 32bit unsigned integer).\n'
'If "random", pick a random seed to use.\n'
'If 0 or not set, do not randomize test case execution order.',
); );
usesTrackWidgetCreation(verboseHelp: verboseHelp); usesTrackWidgetCreation(verboseHelp: verboseHelp);
} }
/// The interface for starting and configuring the tester.
final TestWrapper testWrapper;
@override @override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async { Future<Set<DevelopmentArtifact>> get requiredArtifacts async {
final Set<DevelopmentArtifact> results = <DevelopmentArtifact>{}; final Set<DevelopmentArtifact> results = <DevelopmentArtifact>{};
...@@ -223,6 +237,7 @@ class TestCommand extends FastFlutterCommand { ...@@ -223,6 +237,7 @@ class TestCommand extends FastFlutterCommand {
boolArg('disable-service-auth-codes'); boolArg('disable-service-auth-codes');
final int result = await runTests( final int result = await runTests(
testWrapper,
files, files,
workDir: workDir, workDir: workDir,
names: names, names: names,
...@@ -240,6 +255,7 @@ class TestCommand extends FastFlutterCommand { ...@@ -240,6 +255,7 @@ class TestCommand extends FastFlutterCommand {
buildTestAssets: buildTestAssets, buildTestAssets: buildTestAssets,
flutterProject: flutterProject, flutterProject: flutterProject,
web: stringArg('platform') == 'chrome', web: stringArg('platform') == 'chrome',
randomSeed: stringArg('test-randomize-ordering-seed'),
); );
if (collector != null) { if (collector != null) {
......
...@@ -7,10 +7,7 @@ import 'dart:async'; ...@@ -7,10 +7,7 @@ import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:stream_channel/stream_channel.dart'; import 'package:stream_channel/stream_channel.dart';
import 'package:test_api/src/backend/runtime.dart'; // ignore: implementation_imports
import 'package:test_api/src/backend/suite_platform.dart'; // ignore: implementation_imports import 'package:test_api/src/backend/suite_platform.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/platform.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/hack_register_platform.dart' as hack; // ignore: implementation_imports
import 'package:test_core/src/runner/runner_suite.dart'; // ignore: implementation_imports import 'package:test_core/src/runner/runner_suite.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/plugin/platform_helpers.dart'; // ignore: implementation_imports import 'package:test_core/src/runner/plugin/platform_helpers.dart'; // ignore: implementation_imports
...@@ -27,6 +24,7 @@ import '../convert.dart'; ...@@ -27,6 +24,7 @@ import '../convert.dart';
import '../dart/package_map.dart'; import '../dart/package_map.dart';
import '../globals.dart'; import '../globals.dart';
import '../project.dart'; import '../project.dart';
import '../test/test_wrapper.dart';
import '../vmservice.dart'; import '../vmservice.dart';
import 'test_compiler.dart'; import 'test_compiler.dart';
import 'test_config.dart'; import 'test_config.dart';
...@@ -71,6 +69,7 @@ typedef PlatformPluginRegistration = void Function(FlutterPlatform platform); ...@@ -71,6 +69,7 @@ typedef PlatformPluginRegistration = void Function(FlutterPlatform platform);
/// (that is, one Dart file with a `*_test.dart` file name and a single `void /// (that is, one Dart file with a `*_test.dart` file name and a single `void
/// main()`), you can set an observatory port explicitly. /// main()`), you can set an observatory port explicitly.
FlutterPlatform installHook({ FlutterPlatform installHook({
TestWrapper testWrapper = const TestWrapper(),
@required String shellPath, @required String shellPath,
TestWatcher watcher, TestWatcher watcher,
bool enableObservatory = false, bool enableObservatory = false,
...@@ -91,11 +90,12 @@ FlutterPlatform installHook({ ...@@ -91,11 +90,12 @@ FlutterPlatform installHook({
String icudtlPath, String icudtlPath,
PlatformPluginRegistration platformPluginRegistration, PlatformPluginRegistration platformPluginRegistration,
}) { }) {
assert(testWrapper != null);
assert(enableObservatory || (!startPaused && observatoryPort == null)); assert(enableObservatory || (!startPaused && observatoryPort == null));
// registerPlatformPlugin can be injected for testing since it's not very mock-friendly. // registerPlatformPlugin can be injected for testing since it's not very mock-friendly.
platformPluginRegistration ??= (FlutterPlatform platform) { platformPluginRegistration ??= (FlutterPlatform platform) {
hack.registerPlatformPlugin( testWrapper.registerPlatformPlugin(
<Runtime>[Runtime.vm], <Runtime>[Runtime.vm],
() { () {
return platform; return platform;
......
...@@ -17,7 +17,6 @@ import 'package:shelf_packages_handler/shelf_packages_handler.dart'; ...@@ -17,7 +17,6 @@ import 'package:shelf_packages_handler/shelf_packages_handler.dart';
import 'package:shelf_static/shelf_static.dart'; import 'package:shelf_static/shelf_static.dart';
import 'package:shelf_web_socket/shelf_web_socket.dart'; import 'package:shelf_web_socket/shelf_web_socket.dart';
import 'package:stream_channel/stream_channel.dart'; import 'package:stream_channel/stream_channel.dart';
import 'package:test_api/backend.dart'; // ignore: deprecated_member_use
import 'package:test_api/src/backend/runtime.dart'; import 'package:test_api/src/backend/runtime.dart';
import 'package:test_api/src/backend/suite_platform.dart'; import 'package:test_api/src/backend/suite_platform.dart';
import 'package:test_api/src/util/stack_trace_mapper.dart'; import 'package:test_api/src/util/stack_trace_mapper.dart';
......
...@@ -5,9 +5,6 @@ ...@@ -5,9 +5,6 @@
import 'dart:async'; import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:test_api/backend.dart'; // ignore: deprecated_member_use
import 'package:test_core/src/executable.dart' as test; // ignore: implementation_imports
import 'package:test_core/src/runner/hack_register_platform.dart' as hack; // ignore: implementation_imports
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/common.dart'; import '../base/common.dart';
...@@ -22,10 +19,12 @@ import '../project.dart'; ...@@ -22,10 +19,12 @@ import '../project.dart';
import '../web/compile.dart'; import '../web/compile.dart';
import 'flutter_platform.dart' as loader; import 'flutter_platform.dart' as loader;
import 'flutter_web_platform.dart'; import 'flutter_web_platform.dart';
import 'test_wrapper.dart';
import 'watcher.dart'; import 'watcher.dart';
/// Runs tests using package:test and the Flutter engine. /// Runs tests using package:test and the Flutter engine.
Future<int> runTests( Future<int> runTests(
TestWrapper testWrapper,
List<String> testFiles, { List<String> testFiles, {
Directory workDir, Directory workDir,
List<String> names = const <String>[], List<String> names = const <String>[],
...@@ -47,6 +46,7 @@ Future<int> runTests( ...@@ -47,6 +46,7 @@ Future<int> runTests(
String icudtlPath, String icudtlPath,
Directory coverageDirectory, Directory coverageDirectory,
bool web = false, bool web = false,
String randomSeed = '0',
}) async { }) async {
// Configure package:test to use the Flutter engine for child processes. // Configure package:test to use the Flutter engine for child processes.
final String shellPath = artifacts.getArtifactPath(Artifact.flutterTester); final String shellPath = artifacts.getArtifactPath(Artifact.flutterTester);
...@@ -67,6 +67,7 @@ Future<int> runTests( ...@@ -67,6 +67,7 @@ Future<int> runTests(
...<String>['--name', name], ...<String>['--name', name],
for (String plainName in plainNames) for (String plainName in plainNames)
...<String>['--plain-name', plainName], ...<String>['--plain-name', plainName],
'--test-randomize-ordering-seed=$randomSeed',
]; ];
if (web) { if (web) {
final String tempBuildDir = fs.systemTempDirectory final String tempBuildDir = fs.systemTempDirectory
...@@ -89,7 +90,7 @@ Future<int> runTests( ...@@ -89,7 +90,7 @@ Future<int> runTests(
..add('--precompiled=$tempBuildDir') ..add('--precompiled=$tempBuildDir')
..add('--') ..add('--')
..addAll(testFiles); ..addAll(testFiles);
hack.registerPlatformPlugin( testWrapper.registerPlatformPlugin(
<Runtime>[Runtime.chrome], <Runtime>[Runtime.chrome],
() { () {
return FlutterWebPlatform.start( return FlutterWebPlatform.start(
...@@ -100,7 +101,7 @@ Future<int> runTests( ...@@ -100,7 +101,7 @@ Future<int> runTests(
); );
}, },
); );
await test.main(testArgs); await testWrapper.main(testArgs);
return exitCode; return exitCode;
} }
...@@ -112,6 +113,7 @@ Future<int> runTests( ...@@ -112,6 +113,7 @@ Future<int> runTests(
ipv6 ? InternetAddressType.IPv6 : InternetAddressType.IPv4; ipv6 ? InternetAddressType.IPv6 : InternetAddressType.IPv4;
final loader.FlutterPlatform platform = loader.installHook( final loader.FlutterPlatform platform = loader.installHook(
testWrapper: testWrapper,
shellPath: shellPath, shellPath: shellPath,
watcher: watcher, watcher: watcher,
enableObservatory: enableObservatory, enableObservatory: enableObservatory,
...@@ -144,7 +146,7 @@ Future<int> runTests( ...@@ -144,7 +146,7 @@ Future<int> runTests(
} }
printTrace('running test package with arguments: $testArgs'); printTrace('running test package with arguments: $testArgs');
await test.main(testArgs); await testWrapper.main(testArgs);
// test.main() sets dart:io's exitCode global. // test.main() sets dart:io's exitCode global.
printTrace('test package returned with exit code $exitCode'); printTrace('test package returned with exit code $exitCode');
......
// 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:test_api/backend.dart'; // ignore: deprecated_member_use
import 'package:test_core/src/runner/platform.dart'; // ignore: implementation_imports
import 'package:test_core/src/executable.dart' as test; // ignore: implementation_imports
import 'package:test_core/src/runner/hack_register_platform.dart' as hack; // ignore: implementation_imports
export 'package:test_api/backend.dart' show Runtime; // ignore: deprecated_member_use
export 'package:test_core/src/runner/platform.dart' show PlatformPlugin; // ignore: implementation_imports
abstract class TestWrapper {
const factory TestWrapper() = _DefaultTestWrapper;
Future<void> main(List<String> args);
void registerPlatformPlugin(Iterable<Runtime> runtimes, FutureOr<PlatformPlugin> Function() platforms);
}
class _DefaultTestWrapper implements TestWrapper {
const _DefaultTestWrapper();
@override
Future<void> main(List<String> args) async {
await test.main(args);
}
@override
void registerPlatformPlugin(Iterable<Runtime> runtimes, FutureOr<PlatformPlugin> Function() platforms) {
hack.registerPlatformPlugin(runtimes, platforms);
}
}
// 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:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/test.dart';
import 'package:flutter_tools/src/test/test_wrapper.dart';
import 'package:process/process.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/testbed.dart';
void main() {
Cache.disableLocking();
MemoryFileSystem fs;
setUp(() {
fs = MemoryFileSystem();
fs.file('pubspec.yaml').createSync();
fs.directory('test').childFile('some_test.dart').createSync(recursive: true);
});
testUsingContext('Pipes test-randomize-ordering-seed to package:test',
() async {
final FakePackageTest fakePackageTest = FakePackageTest();
final TestCommand testCommand = TestCommand(testWrapper: fakePackageTest);
final CommandRunner<void> commandRunner =
createTestCommandRunner(testCommand);
await commandRunner.run(const <String>[
'test',
'--test-randomize-ordering-seed=random',
'--no-pub',
]);
expect(
fakePackageTest.lastArgs,
contains('--test-randomize-ordering-seed=random'),
);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
Cache: () => FakeCache(),
});
}
class FakePackageTest implements TestWrapper {
List<String> lastArgs;
@override
Future<void> main(List<String> args) async {
lastArgs = args;
}
@override
void registerPlatformPlugin(
Iterable<Runtime> runtimes,
FutureOr<PlatformPlugin> Function() platforms,
) {}
}
...@@ -66,7 +66,7 @@ void main() { ...@@ -66,7 +66,7 @@ void main() {
fs.path.join(flutterTools, 'lib', 'src', 'build_runner', 'build_script.dart'), fs.path.join(flutterTools, 'lib', 'src', 'build_runner', 'build_script.dart'),
fs.path.join(flutterTools, 'lib', 'src', 'test', 'flutter_platform.dart'), fs.path.join(flutterTools, 'lib', 'src', 'test', 'flutter_platform.dart'),
fs.path.join(flutterTools, 'lib', 'src', 'test', 'flutter_web_platform.dart'), fs.path.join(flutterTools, 'lib', 'src', 'test', 'flutter_web_platform.dart'),
fs.path.join(flutterTools, 'lib', 'src', 'test', 'runner.dart'), fs.path.join(flutterTools, 'lib', 'src', 'test', 'test_wrapper.dart'),
]; ];
bool _isNotWhitelisted(FileSystemEntity entity) => whitelistedPaths.every((String path) => path != entity.path); bool _isNotWhitelisted(FileSystemEntity entity) => whitelistedPaths.every((String path) => path != entity.path);
......
...@@ -11,15 +11,12 @@ import 'package:async/async.dart'; ...@@ -11,15 +11,12 @@ import 'package:async/async.dart';
import 'package:coverage/coverage.dart'; import 'package:coverage/coverage.dart';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/context_runner.dart'; import 'package:flutter_tools/src/context_runner.dart';
import 'package:flutter_tools/src/test/test_wrapper.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:stream_channel/isolate_channel.dart'; import 'package:stream_channel/isolate_channel.dart';
import 'package:stream_channel/stream_channel.dart'; import 'package:stream_channel/stream_channel.dart';
import 'package:test_core/src/runner/hack_register_platform.dart' as hack; // ignore: implementation_imports
import 'package:test_core/src/executable.dart' as test; // ignore: implementation_imports
import 'package:vm_service_client/vm_service_client.dart'; // ignore: deprecated_member_use import 'package:vm_service_client/vm_service_client.dart'; // ignore: deprecated_member_use
import 'package:test_api/src/backend/runtime.dart'; // ignore: implementation_imports
import 'package:test_api/src/backend/suite_platform.dart'; // ignore: implementation_imports import 'package:test_api/src/backend/suite_platform.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/platform.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/runner_suite.dart'; // ignore: implementation_imports import 'package:test_core/src/runner/runner_suite.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/plugin/platform_helpers.dart'; // ignore: implementation_imports import 'package:test_core/src/runner/plugin/platform_helpers.dart'; // ignore: implementation_imports
...@@ -35,7 +32,8 @@ import 'package:flutter_tools/src/test/coverage_collector.dart'; ...@@ -35,7 +32,8 @@ import 'package:flutter_tools/src/test/coverage_collector.dart';
Future<void> main(List<String> arguments) async { Future<void> main(List<String> arguments) async {
return runInContext(() async { return runInContext(() async {
final VMPlatform vmPlatform = VMPlatform(); final VMPlatform vmPlatform = VMPlatform();
hack.registerPlatformPlugin( const TestWrapper test = TestWrapper();
test.registerPlatformPlugin(
<Runtime>[Runtime.vm], <Runtime>[Runtime.vm],
() => vmPlatform, () => vmPlatform,
); );
......
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