Commit 3419068c authored by Ian Hickson's avatar Ian Hickson

Port test logic to Dart.

parent 1cadf125
...@@ -87,25 +87,27 @@ Testing the `flutter` package is currently a bit harder because we don't yet ...@@ -87,25 +87,27 @@ Testing the `flutter` package is currently a bit harder because we don't yet
support testing the `flutter` package with pre-built binaries. To test the support testing the `flutter` package with pre-built binaries. To test the
package, you'll need to follow the [instructions below](#working-on-the-engine-and-the-framework-at-the-same-time) package, you'll need to follow the [instructions below](#working-on-the-engine-and-the-framework-at-the-same-time)
for working with this repository and the Flutter engine repository for working with this repository and the Flutter engine repository
simultaneously and then run the following command: simultaneously and then run the following command (assuming the `flutter/bin`
directory is in your path):
* `./dev/run_tests --debug` * `flutter test --debug`
Creating a workflow for running the test with a prebuilt binary is Creating a workflow for running the test with a prebuilt binary is
[Issue #56](https://github.com/flutter/flutter/issues/56). If you want to run [Issue #56](https://github.com/flutter/flutter/issues/56). If you want
a single test individually: to run a single test individually:
* `./dev/run_tests --debug test/harness/trivial_test.dart` * `flutter test --debug trivial_test.dart`
Note: The tests are headless, you won't see any UI. You can use `print` to Note: The tests are headless, you won't see any UI. You can use
generate console output or you can interact with the DartVM via observatory at [http://localhost:8181/](http://localhost:8181/). `print` to generate console output or you can interact with the DartVM
via observatory at [http://localhost:8181/](http://localhost:8181/).
Adding a test Adding a test
------------- -------------
To add a test, simply create a file whose name ends with `_test.dart` in the To add a test, simply create a file whose name ends with `_test.dart`
`packags/unit/test` directory. The test should have a `main` function and use in the `packages/unit/test` directory. The test should have a `main`
the `test` package. function and use the `test` package.
Contributing code Contributing code
----------------- -----------------
...@@ -120,7 +122,7 @@ To start working on a patch: ...@@ -120,7 +122,7 @@ To start working on a patch:
and [design principles](https://github.com/flutter/engine/blob/master/sky/specs/design.md) and [design principles](https://github.com/flutter/engine/blob/master/sky/specs/design.md)
before working on anything non-trivial. These guidelines are intended to keep before working on anything non-trivial. These guidelines are intended to keep
the code consistent and avoid common pitfalls. the code consistent and avoid common pitfalls.
* `git commit -a -m "<your brief but informative commit message>"` * `git commit -a -m "<your informative commit message>"`
* `git push origin name_of_your_branch` * `git push origin name_of_your_branch`
To send us a pull request: To send us a pull request:
...@@ -163,15 +165,15 @@ the following steps. ...@@ -163,15 +165,15 @@ the following steps.
(e.g., `out/Debug`). To run examples on Android, build one of the Android (e.g., `out/Debug`). To run examples on Android, build one of the Android
configurations (e.g., `out/android_Debug`). configurations (e.g., `out/android_Debug`).
You should now be able to run the tests against your locally built engine using You should now be able to run the tests against your locally built
the `./dev/run_tests` script. To run one of the examples on your device using engine using the `flutter test --debug` command. To run one of the
your locally built engine, use the `--engine-src-path` option to the `flutter` examples on your device using your locally built engine, use the
tool: `--debug` option to the `flutter` tool:
* `flutter start --engine-src-path /foo/bar/engine/src` * `flutter start --debug`
Eventually, the `--local-build` flag for the `flutter` command will If you want to test the release version instead of the debug version,
automatically set the correct engine src path (see [Issue #57](https://github.com/flutter/flutter/issues/57)). use `--release` instead of `--debug`.
Making a breaking change to the engine Making a breaking change to the engine
-------------------------------------- --------------------------------------
......
#!/usr/bin/env python
# Copyright 2015 The Chromium 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 os
import sys
import subprocess
import argparse
FLUTTER_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
FLUTTER = os.path.join(FLUTTER_ROOT, 'bin', 'flutter')
UNIT_DIR = os.path.join(FLUTTER_ROOT, 'packages', 'unit')
TESTS_DIR = os.path.join(UNIT_DIR, 'test')
DEFAULT_ENGINE_DIR = os.path.abspath(os.path.join(FLUTTER_ROOT, '..', 'engine', 'src'))
def main():
parser = argparse.ArgumentParser(description='Runs Flutter unit tests')
parser.add_argument('--engine-src-path', default=DEFAULT_ENGINE_DIR)
parser.add_argument('--config', default='Debug')
parser.add_argument('--debug', dest='config', action='store_const', const='Debug')
parser.add_argument('--release', dest='config', action='store_const', const='Release')
args, remaining = parser.parse_known_args()
build_dir = os.path.join(os.path.abspath(args.engine_src_path), 'out', args.config)
if not remaining:
for root, dirs, files in os.walk(TESTS_DIR):
remaining.extend(os.path.join(root, f)
for f in files if f.endswith("_test.dart"))
if os.environ['TERM'] == 'dumb':
remaining = [ '--no-color' ] + remaining
return subprocess.call([
FLUTTER,
'test',
'--build-dir=%s' % build_dir
] + remaining, cwd=UNIT_DIR)
if __name__ == '__main__':
sys.exit(main())
// Copyright 2015 The Chromium 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 'package:sky_tools/src/test/loader.dart' as loader;
import 'package:test/src/executable.dart' as executable;
main(List<String> args) {
loader.installHook();
return executable.main(args);
}
...@@ -74,6 +74,7 @@ class ApplicationPackageStore { ...@@ -74,6 +74,7 @@ class ApplicationPackageStore {
return iOS; return iOS;
case TargetPlatform.iOSSimulator: case TargetPlatform.iOSSimulator:
return iOSSimulator; return iOSSimulator;
case TargetPlatform.mac:
case TargetPlatform.linux: case TargetPlatform.linux:
return null; return null;
} }
...@@ -110,6 +111,7 @@ class ApplicationPackageStore { ...@@ -110,6 +111,7 @@ class ApplicationPackageStore {
iOSSimulator = new IOSApp(localPath: path.join(config.buildDir, IOSApp._defaultName)); iOSSimulator = new IOSApp(localPath: path.join(config.buildDir, IOSApp._defaultName));
break; break;
case TargetPlatform.mac:
case TargetPlatform.linux: case TargetPlatform.linux:
break; break;
} }
......
...@@ -34,6 +34,8 @@ String _getNameForTargetPlatform(TargetPlatform platform) { ...@@ -34,6 +34,8 @@ String _getNameForTargetPlatform(TargetPlatform platform) {
return 'ios-arm'; return 'ios-arm';
case TargetPlatform.iOSSimulator: case TargetPlatform.iOSSimulator:
return 'ios-x64'; return 'ios-x64';
case TargetPlatform.mac:
return 'darwin-x64';
case TargetPlatform.linux: case TargetPlatform.linux:
return 'linux-x64'; return 'linux-x64';
} }
...@@ -158,12 +160,31 @@ class ArtifactStore { ...@@ -158,12 +160,31 @@ class ArtifactStore {
// These values are initialized by FlutterCommandRunner on startup. // These values are initialized by FlutterCommandRunner on startup.
static String flutterRoot; static String flutterRoot;
static String packageRoot; static String packageRoot = 'packages';
static bool get isPackageRootValid {
return FileSystemEntity.isDirectorySync(packageRoot);
}
static void ensurePackageRootIsValid() {
if (!isPackageRootValid) {
String message = '$packageRoot is not a valid directory.';
if (packageRoot == 'packages') {
if (FileSystemEntity.isFileSync('pubspec.yaml'))
message += '\nDid you run `pub get` in this directory?';
else
message += '\nDid you run this command from the same directory as your pubspec.yaml file?';
}
stderr.writeln(message);
throw new ProcessExit(2);
}
}
static String _engineRevision; static String _engineRevision;
static String get engineRevision { static String get engineRevision {
if (_engineRevision == null) { if (_engineRevision == null) {
ensurePackageRootIsValid();
File revisionFile = new File(path.join(packageRoot, 'sky_engine', 'REVISION')); File revisionFile = new File(path.join(packageRoot, 'sky_engine', 'REVISION'));
if (revisionFile.existsSync()) if (revisionFile.existsSync())
_engineRevision = revisionFile.readAsStringSync(); _engineRevision = revisionFile.readAsStringSync();
......
...@@ -24,6 +24,7 @@ enum TargetPlatform { ...@@ -24,6 +24,7 @@ enum TargetPlatform {
android, android,
iOS, iOS,
iOSSimulator, iOSSimulator,
mac,
linux, linux,
} }
...@@ -36,12 +37,21 @@ HostPlatform getCurrentHostPlatform() { ...@@ -36,12 +37,21 @@ HostPlatform getCurrentHostPlatform() {
return HostPlatform.linux; return HostPlatform.linux;
} }
TargetPlatform getCurrentHostPlatformAsTarget() {
if (Platform.isMacOS)
return TargetPlatform.mac;
if (Platform.isLinux)
return TargetPlatform.linux;
_logging.warning('Unsupported host platform, defaulting to Linux');
return TargetPlatform.linux;
}
class BuildConfiguration { class BuildConfiguration {
BuildConfiguration.prebuilt({ BuildConfiguration.prebuilt({
this.hostPlatform, this.hostPlatform,
this.targetPlatform, this.targetPlatform,
this.deviceId this.deviceId
}) : type = BuildType.prebuilt, buildDir = null; }) : type = BuildType.prebuilt, buildDir = null, testable = false;
BuildConfiguration.local({ BuildConfiguration.local({
this.type, this.type,
...@@ -49,7 +59,8 @@ class BuildConfiguration { ...@@ -49,7 +59,8 @@ class BuildConfiguration {
this.targetPlatform, this.targetPlatform,
String enginePath, String enginePath,
String buildPath, String buildPath,
this.deviceId this.deviceId,
this.testable: false
}) : buildDir = path.normalize(path.join(enginePath, buildPath)) { }) : buildDir = path.normalize(path.join(enginePath, buildPath)) {
assert(type == BuildType.debug || type == BuildType.release); assert(type == BuildType.debug || type == BuildType.release);
} }
...@@ -59,4 +70,5 @@ class BuildConfiguration { ...@@ -59,4 +70,5 @@ class BuildConfiguration {
final TargetPlatform targetPlatform; final TargetPlatform targetPlatform;
final String buildDir; final String buildDir;
final String deviceId; final String deviceId;
final bool testable;
} }
...@@ -8,6 +8,7 @@ import 'dart:io'; ...@@ -8,6 +8,7 @@ import 'dart:io';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import '../application_package.dart'; import '../application_package.dart';
import '../build_configuration.dart';
import '../device.dart'; import '../device.dart';
import '../toolchain.dart'; import '../toolchain.dart';
import 'flutter_command_runner.dart'; import 'flutter_command_runner.dart';
...@@ -18,19 +19,21 @@ abstract class FlutterCommand extends Command { ...@@ -18,19 +19,21 @@ abstract class FlutterCommand extends Command {
/// Whether this command needs to be run from the root of a project. /// Whether this command needs to be run from the root of a project.
bool get requiresProjectRoot => true; bool get requiresProjectRoot => true;
List<BuildConfiguration> get buildConfigurations => runner.buildConfigurations;
Future downloadApplicationPackages() async { Future downloadApplicationPackages() async {
if (applicationPackages == null) if (applicationPackages == null)
applicationPackages = await ApplicationPackageStore.forConfigs(runner.buildConfigurations); applicationPackages = await ApplicationPackageStore.forConfigs(buildConfigurations);
} }
Future downloadToolchain() async { Future downloadToolchain() async {
if (toolchain == null) if (toolchain == null)
toolchain = await Toolchain.forConfigs(runner.buildConfigurations); toolchain = await Toolchain.forConfigs(buildConfigurations);
} }
void connectToDevices() { void connectToDevices() {
if (devices == null) if (devices == null)
devices = new DeviceStore.forConfigs(runner.buildConfigurations); devices = new DeviceStore.forConfigs(buildConfigurations);
} }
Future downloadApplicationPackagesAndConnectToDevices() async { Future downloadApplicationPackagesAndConnectToDevices() async {
......
...@@ -9,36 +9,66 @@ import 'package:logging/logging.dart'; ...@@ -9,36 +9,66 @@ import 'package:logging/logging.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:test/src/executable.dart' as executable; import 'package:test/src/executable.dart' as executable;
import 'flutter_command.dart'; import '../artifacts.dart';
import '../build_configuration.dart';
import '../test/loader.dart' as loader; import '../test/loader.dart' as loader;
import 'flutter_command.dart';
final Logger _logging = new Logger('sky_tools.test'); final Logger _logging = new Logger('sky_tools.test');
class TestCommand extends FlutterCommand { class TestCommand extends FlutterCommand {
final String name = 'test'; String get name => 'test';
final String description = 'Runs Flutter unit tests for the current project (requires a local build of the engine).'; String get description => 'Runs Flutter unit tests for the current project. At least one of --debug and --release must be set.';
TestCommand() { bool get requiresProjectRoot => false;
argParser.addOption('build-dir', help: 'The directory in which to find a prebuilt engine');
}
String get _shellPath { String getShellPath(TargetPlatform platform, String buildPath) {
if (Platform.isLinux) switch (platform) {
return path.join(argResults['build-dir'], 'sky_shell'); case TargetPlatform.linux:
if (Platform.isMacOS) return path.join(buildPath, 'sky_shell');
return path.join(argResults['build-dir'], 'SkyShell.app', 'Contents', 'MacOS', 'SkyShell'); case TargetPlatform.mac:
throw new Exception('Unsupported platform.'); return path.join(buildPath, 'SkyShell.app', 'Contents', 'MacOS', 'SkyShell');
default:
throw new Exception('Unsupported platform.');
}
} }
@override @override
Future<int> runInProject() async { Future<int> runInProject() async {
loader.shellPath = _shellPath; List<String> testArgs = argResults.rest.toList();
if (!FileSystemEntity.isFileSync(loader.shellPath)) { Directory testDir = new Directory(path.join(ArtifactStore.flutterRoot, 'packages/unit/test'));
_logging.severe('Cannot find Flutter Shell at ${loader.shellPath}'); if (testArgs.isEmpty) {
return 1; testArgs.addAll(testDir.listSync(recursive: true, followLinks: false)
.where((FileSystemEntity entity) => entity.path.endsWith('_test.dart') && FileSystemEntity.isFileSync(entity.path))
.map((FileSystemEntity entity) => path.absolute(entity.path)));
} }
testArgs.insert(0, '--');
if (Platform.environment['TERM'] == 'dumb')
testArgs.insert(0, '--no-color');
List<BuildConfiguration> configs = buildConfigurations;
bool foundOne = false;
String currentDirectory = Directory.current.path;
Directory.current = testDir.path;
// TODO(ianh): Verify that this directory has had 'pub get' run in it at least once.
loader.installHook(); loader.installHook();
await executable.main(argResults.rest); for (BuildConfiguration config in configs) {
return exitCode; if (!config.testable)
continue;
foundOne = true;
loader.shellPath = path.join(currentDirectory, getShellPath(config.targetPlatform, config.buildDir));
if (!FileSystemEntity.isFileSync(loader.shellPath)) {
_logging.severe('Cannot find Flutter shell at ${loader.shellPath}');
return 1;
}
await executable.main(testArgs);
if (exitCode != 0)
return exitCode;
}
if (!foundOne) {
stderr.writeln('At least one of --debug or --release must be set, to specify the local build products to test.');
return 1;
}
return 0;
} }
} }
\ No newline at end of file
...@@ -920,6 +920,7 @@ class DeviceStore { ...@@ -920,6 +920,7 @@ class DeviceStore {
assert(iOSSimulator == null); assert(iOSSimulator == null);
iOSSimulator = new IOSSimulator(); iOSSimulator = new IOSSimulator();
break; break;
case TargetPlatform.mac:
case TargetPlatform.linux: case TargetPlatform.linux:
break; break;
} }
......
...@@ -6,4 +6,4 @@ set -ex ...@@ -6,4 +6,4 @@ set -ex
(cd packages/flx; pub global run tuneup check; pub run test -j1) (cd packages/flx; pub global run tuneup check; pub run test -j1)
(cd packages/newton; pub global run tuneup check; pub run test -j1) (cd packages/newton; pub global run tuneup check; pub run test -j1)
./dev/run_tests --engine-src-path bin/cache/travis ./bin/flutter test --engine-src-path bin/cache/travis
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