blob: c78239a8a2e859797152fb91904015646e4a3b18 [file] [log] [blame]
// Copyright 2019 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:convert';
import 'dart:io';
import 'package:args/args.dart';
import 'package:test/test.dart';
import 'package:archive/archive.dart';
const String ipv4Env = 'FUCHSIA_IPV4_ADDR';
const String outputEnv = 'FUCHSIA_TEST_OUTDIR';
const int deviceReadyTimeoutSec = 30;
// TODO(chok): Use in-tree ACTS.zip which will likely be the CWD instead
const String actsZipAbsPath = '/etc/connectivity/acts.zip';
const String actsConfigAbsPath = '/etc/connectivity/acts_config.json';
const String actsBinRelPath = 'tools/test/connectivity/acts/framework/acts/bin/act.py';
const String actsFrameworkRelPath = 'tools/test/connectivity/acts/framework';
const String actsOutputPath = '/tmp/logs/tb/latest';
const String actsSummaryFileName = 'test_run_summary.json';
Future<void> waitDeviceReady(final String ip) async {
for (var i = 0; i < deviceReadyTimeoutSec; i++) {
final result = Process.runSync('ping', [ip, '-c', '1', '-W', '1']);
if (result.exitCode == 0) {
print('Fuchsia device is online @ [$ip].');
return;
}
await Future.delayed(const Duration(seconds: 1));
}
throw Exception('Device [$ip] is not ping-able.');
}
void extractActsZip(final String tmpDirPath) {
final List<int> bytes = File(actsZipAbsPath).readAsBytesSync();
final Archive archive = ZipDecoder().decodeBytes(bytes);
// Extract the contents of the Zip archive to disk.
for (ArchiveFile file in archive) {
String filename = file.name;
var filepath = '$tmpDirPath/$filename';
if (file.isFile) {
List<int> data = file.content;
File(filepath)
..createSync(recursive: true)
..writeAsBytesSync(data);
} else {
Directory(filepath).create(recursive: true);
}
}
}
Future<Process> runActs(final String tmpDirPath, final String tests) {
final actsBinAbsPath = '$tmpDirPath/$actsBinRelPath';
final actsArgs = ['-c', actsConfigAbsPath, '-tc']
..addAll(tests.split(' '));
// Set ACTS binary as executable
Process.runSync('chmod', ['+x', actsBinAbsPath]);
return Process.start(actsBinAbsPath, actsArgs, environment: {
'PYTHONPATH': '$tmpDirPath/$actsFrameworkRelPath'
});
}
void main(final List<String> args) {
final argResults = (ArgParser()
..addOption('tests',
help: 'Space delimited string of ACTS tests to run.'))
.parse(args);
// Fetch env var
final Map<String, String> envVars = Platform.environment;
final String ipStr = envVars[ipv4Env];
final String outputDir = envVars[outputEnv];
tearDown(() {
// Copy ACTS output to designated dir for GCS upload
Process.runSync('/bin/cp', ['-r', actsOutputPath, outputDir]);
});
test('ActsSuite', () async {
// Extract ACTS zip into tmp dir
final tmpDir = Directory.systemTemp.createTempSync('acts_');
extractActsZip(tmpDir.path);
// Wait for device to be online before running tests
for(var ip in ipStr.split(',')) {
await waitDeviceReady(ip);
}
// Run ACTS tests
final proc = await runActs(tmpDir.path, argResults['tests']);
await Future.wait([stdout.addStream(proc.stdout), stderr.addStream(proc.stderr)]);
expect(await proc.exitCode, equals(0));
// Assert that ACTS actually ran tests
final json = File('$actsOutputPath/$actsSummaryFileName').readAsStringSync();
final data = jsonDecode(json);
expect(data, contains('Results'));
expect(data['Summary']['Executed'], isNonZero);
}, timeout: Timeout(Duration(minutes: 15)));
}