blob: 55f878b8cca90ddba3f2da2dc3598dc1658aedb9 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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:io';
import 'package:fidl_fuchsia_modular/fidl.dart';
import 'package:fidl_fuchsia_sys/fidl.dart';
import 'package:fidl_fuchsia_testing_runner/fidl.dart';
import 'package:flutter/material.dart';
import 'package:lib.app.dart/app.dart';
import 'package:lib.app.dart/logging.dart';
import 'package:lib.app_driver.dart/module_driver.dart';
import 'package:lib.widgets.dart/model.dart';
import 'package:lib.widgets/widgets.dart';
import 'build_status_model.dart';
import 'dashboard_app.dart';
import 'dashboard_model.dart';
import 'service/build_service.dart';
const List<List<List<String>>> _kTargetsMap = const <List<List<String>>>[
const <List<String>>[
const <String>[
'topaz-arm64-debug-qemu_kvm',
'arm64-debug',
'topaz',
],
const <String>[
'topaz-arm64-release-qemu_kvm',
'arm64-release',
'topaz',
],
const <String>[
'topaz-x64-debug-qemu_kvm',
'x64-debug',
'topaz',
],
const <String>[
'topaz-x64-release-qemu_kvm',
'x64-release',
'topaz',
],
],
const <List<String>>[
const <String>[
'peridot-arm64-debug-qemu_kvm',
'arm64-debug',
'peridot',
],
const <String>[
'peridot-arm64-release-qemu_kvm',
'arm64-release',
'peridot',
],
const <String>[
'peridot-x64-debug-qemu_kvm',
'x64-debug',
'peridot',
],
const <String>[
'peridot-x64-release-qemu_kvm',
'x64-release',
'peridot',
],
],
const <List<String>>[
const <String>[
'garnet-arm64-debug-qemu_kvm',
'arm64-debug',
'garnet',
],
const <String>[
'garnet-arm64-release-qemu_kvm',
'arm64-release',
'garnet',
],
const <String>[
'garnet-x64-debug-qemu_kvm',
'x64-debug',
'garnet',
],
const <String>[
'garnet-x64-release-qemu_kvm',
'x64-release',
'garnet',
],
],
const <List<String>>[
const <String>[
'zircon-arm64-clang-qemu_kvm',
'arm64-clang',
'zircon',
],
const <String>[
'zircon-arm64-gcc-qemu_kvm',
'arm64-gcc',
'zircon',
],
const <String>[
'zircon-x64-clang-qemu_kvm',
'x64-clang',
'zircon',
],
const <String>[
'zircon-x64-gcc-qemu_kvm',
'x64-gcc',
'zircon',
],
],
const <List<String>>[
const <String>[
'web_view-x64-linux',
'x64-linux',
'web_view',
],
const <String>[
'web_view-arm64-linux',
'arm64-linux',
'web_view',
],
const <String>[
'jiri',
'jiri',
'jiri',
],
],
const <List<String>>[
const <String>[
'zircon-roller',
'zircon',
'roller',
],
const <String>[
'garnet-roller',
'garnet',
'roller',
],
const <String>[
'peridot-roller',
'peridot',
'roller',
],
]
];
const String _kLastUpdate = '/config/build-info/last-update';
const String _testName = 'dashboard_boot_test';
TestRunnerProxy runnerProxy;
LauncherProxy launcherProxy;
final List<List<BuildStatusModel>> _buildStatusModels =
<List<BuildStatusModel>>[];
// TODO: Refactor this class to use the new SDK instead of deprecated API
// ignore: deprecated_member_use
ModuleDriver _driver;
void main() {
setupLogger();
DateTime buildTimestamp;
File lastUpdateFile = new File(_kLastUpdate);
if (lastUpdateFile.existsSync()) {
String lastUpdate = lastUpdateFile.readAsStringSync();
log.info('Build timestamp: ${lastUpdate.trim()}');
try {
buildTimestamp = DateTime.parse(lastUpdate.trim());
} on FormatException {
log.warning('Could not parse build timestamp! ${lastUpdate.trim()}');
}
}
final BuildService buildService = new BuildService();
for (List<List<String>> buildConfigs in _kTargetsMap) {
List<BuildStatusModel> categoryModels = <BuildStatusModel>[];
for (List<String> config in buildConfigs) {
BuildStatusModel buildStatusModel = new BuildStatusModel(
type: config[2],
name: config[1],
url: config[0],
buildService: buildService,
modelRowsCount: _buildStatusModels.length,
)..start();
categoryModels.add(buildStatusModel);
}
_buildStatusModels.add(categoryModels);
}
StartupContext startupContext = new StartupContext.fromStartupInfo();
final dashboardModel = new DashboardModel(
buildStatusModels: _buildStatusModels,
launchWebview: _launchWebview,
);
// TODO: Refactor this class to use the new SDK instead of deprecated API
// ignore: deprecated_member_use
_driver = new ModuleDriver(onTerminate: dashboardModel.onStop);
runApp(
MaterialApp(
title: 'Fuchsia Build Status',
theme: new ThemeData(primaryColor: kFuchsiaColor),
home: new WindowMediaQuery(
onWindowMetricsChanged: () {
_buildStatusModels
.expand((List<BuildStatusModel> models) => models)
// ignore: avoid_function_literals_in_foreach_calls
.forEach((BuildStatusModel model) =>
model.onWindowMetricsChanged(_buildStatusModels.length));
},
child: new ScopedModel<DashboardModel>(
model: dashboardModel,
child: new DashboardApp(
buildService: buildService,
buildStatusModels: _buildStatusModels,
buildTimestamp: buildTimestamp,
onRefresh: onRefresh,
onLaunchUrl: dashboardModel.launchWebView,
),
),
),
),
);
_driver.start().then((_) {
dashboardModel.loadDeviceMap(startupContext);
}).catchError(log.severe);
_reportTestResultsIfInTestHarness(startupContext.environmentServices);
}
void onRefresh() {
_buildStatusModels
.expand((List<BuildStatusModel> models) => models)
// ignore: avoid_function_literals_in_foreach_calls
.forEach((BuildStatusModel model) => model.refresh());
}
Future<ModuleControllerClient> _launchWebview(Intent intent) async {
return _driver.startModule(
intent: intent,
name: 'module:web_view',
surfaceRelation:
const SurfaceRelation(arrangement: SurfaceArrangement.copresent),
);
}
void _reportTestResultsIfInTestHarness(
ServiceProviderProxy environmentServices) {
runnerProxy = new TestRunnerProxy();
try {
connectToService(environmentServices, runnerProxy.ctrl);
runnerProxy.identify(_testName, () {});
try {
launcherProxy = new LauncherProxy();
connectToService(environmentServices, launcherProxy.ctrl);
runTestIterations();
} on Exception catch (e) {
log.warning('Not able to launch. Not enabling test mode: $e');
runnerProxy.teardown(() {
runnerProxy.ctrl.close();
});
}
} on Exception catch (e) {
log.warning('Not in automated test. Using normal mode: $e');
}
}
const int kMaxAttempts = 3;
const int kDelayBeforeCaptureSeconds = 7;
int _iterationAttempt = 0;
void runTestIterations() {
Stopwatch stopWatch = new Stopwatch()..start();
new Timer(const Duration(seconds: kDelayBeforeCaptureSeconds), () {
LaunchInfo launchInfo =
new LaunchInfo(url: 'screencap', arguments: ['-histogram']);
final ComponentControllerProxy controller = new ComponentControllerProxy();
launcherProxy.createComponent(launchInfo, controller.ctrl.request());
controller.onTerminated = (int r, _) {
if (r == 0) {
log.info('elapsed: ${stopWatch.elapsedMilliseconds}');
TestResult testResult = new TestResult(
name: _testName,
elapsed: stopWatch.elapsedMilliseconds,
failed: false,
message: 'success',
);
launcherProxy.ctrl.close();
runnerProxy
..reportResult(testResult)
..teardown(() {
runnerProxy.ctrl.close();
});
return;
} else {
_iterationAttempt++;
if (_iterationAttempt >= kMaxAttempts) {
log.info('elapsed: ${stopWatch.elapsedMilliseconds}');
TestResult testResult = new TestResult(
name: _testName,
elapsed: stopWatch.elapsedMilliseconds,
failed: true,
message: 'failed: See log for more info');
launcherProxy.ctrl.close();
runnerProxy
..reportResult(testResult)
..teardown(() {
runnerProxy.ctrl.close();
});
return;
}
// Try refreshing the screen captures and comparing again
onRefresh();
runTestIterations();
}
};
});
}