blob: 736ad3e89cecef26d0dbd465eb06daa9669e30af [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;
const String defaultActsZipAbsPath = '/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.');
}
String resolveActsPath() {
final List entities = Directory.current.listSync(recursive: true);
for (var entity in entities) {
if(entity.path.endsWith('acts.zip')) {
return entity.path;
}
}
// Use pre-provisioned 'acts.zip' if it's not found under cur directory
return defaultActsZipAbsPath;
}
void extractActsZip(final String tmpDirPath) {
final actsPath = resolveActsPath();
print('Found "acts.zip" @ [$actsPath].');
final List<int> bytes = File(actsPath).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',
// Required for some Wifi testcases
'LANG': 'C.UTF-8',
'LC_ALL': 'C.UTF-8'
});
}
void main(final List<String> args) {
final argResults = (ArgParser()
..addOption('tests',
help: 'Space delimited string of ACTS tests to run.')
..addOption('timeout',
help: 'Timeout in minutes for ACTS test execution.'))
.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: int.parse(argResults['timeout']))));
}