diff --git a/agent/lib/src/adb.dart b/agent/lib/src/adb.dart index 7fa3794314..045020751d 100644 --- a/agent/lib/src/adb.dart +++ b/agent/lib/src/adb.dart @@ -22,6 +22,10 @@ Future pickNextDevice() async { List allDevices = (await Adb.deviceIds) .map((String id) => new Adb(deviceId: id)) .toList(); + + if (allDevices.length == 0) + throw 'No Android devices detected'; + // TODO(yjbanov): filter out and warn about those with low battery level _currentDevice = allDevices[new math.Random().nextInt(allDevices.length)]; } diff --git a/agent/lib/src/agent.dart b/agent/lib/src/agent.dart index 5c5ffbfa7c..8e154d1db8 100644 --- a/agent/lib/src/agent.dart +++ b/agent/lib/src/agent.dart @@ -37,9 +37,14 @@ class Agent { final Client httpClient; /// Makes a REST API request to Cocoon. - Future _cocoon(String apiPath, dynamic json) async { + Future _cocoon(String apiPath, [dynamic json]) async { String url = '$baseCocoonUrl/api/$apiPath'; - Response resp = await httpClient.post(url, body: JSON.encode(json)); + Response resp; + if (json != null) { + resp = await httpClient.post(url, body: JSON.encode(json)); + } else { + resp = await httpClient.get(url); + } return JSON.decode(resp.body); } @@ -121,6 +126,10 @@ class Agent { 'NewStatus': newStatus, }); } + + Future> getAuthenticationStatus() async { + return await _cocoon('get-authentication-status'); + } } class AuthenticatedClient extends BaseClient { diff --git a/agent/lib/src/commands/ci.dart b/agent/lib/src/commands/ci.dart index 387212bc30..0d63484a7c 100644 --- a/agent/lib/src/commands/ci.dart +++ b/agent/lib/src/commands/ci.dart @@ -8,7 +8,9 @@ import 'dart:io'; import 'package:args/args.dart'; +import '../adb.dart'; import '../agent.dart'; +import '../firebase.dart'; import '../utils.dart'; /// Agents periodically poll the server for more tasks. This sleep period is @@ -33,6 +35,7 @@ class ContinuousIntegrationCommand extends Command { @override Future run(ArgResults args) async { + await _performPreflightChecks(); _listenToShutdownSignals(); while(!_exiting) { try { @@ -72,6 +75,19 @@ class ContinuousIntegrationCommand extends Command { } } + Future _performPreflightChecks() async { + print('Pre-flight checks:'); + await pickNextDevice(); + print(' - device connected'); + await checkFirebaseConnection(); + print(' - firebase connected'); + if (!(await agent.getAuthenticationStatus())['Status'] == 'OK') { + throw 'Failed to authenticate to Cocoon. Check config.yaml.'; + } + print(' - Cocoon auth OK'); + print('Pre-flight OK'); + } + /// Listens to standard output and upload logs to Cocoon in semi-realtime. Future _logStandardStreams(CocoonTask task, Process proc) async { StringBuffer buffer = new StringBuffer(); diff --git a/agent/lib/src/firebase.dart b/agent/lib/src/firebase.dart index 4633a656e3..c9297295dc 100644 --- a/agent/lib/src/firebase.dart +++ b/agent/lib/src/firebase.dart @@ -16,6 +16,12 @@ Firebase _measurements() { auth: firebaseToken); } +Future checkFirebaseConnection() async { + if (await _measurements().child('dashboard_bot_status').child('current').get() == null) { + throw 'Connection to Firebase is unhealthy. Failed to read the current dashboard_bot_status entity.'; + } +} + Future uploadToFirebase(String measurementKey, dynamic jsonData) async { Firebase ref = _measurements().child(measurementKey); await ref.child('current').set(jsonData);