blob: 9309a3058a5ad2e2b816cd41ea5e918e40d7dcb0 [file] [log] [blame]
// Copyright 2022 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 * as vscode from 'vscode';
import * as assert from 'assert';
import { beforeEach, describe, it } from 'mocha';
import { createSandbox } from 'sinon';
import { Ffx, FfxEventType, FuchsiaDevice } from '../../ffx';
import { ToolFinder } from '../../tool_finder';
import { StubbedSpawn } from './utils';
describe('FuchsiaDevice', function () {
describe('#constructor()', function () {
it('creates an instance of FuchsiaDevice from the json returned from ffx target list',
function () {
const data = {
'nodename': 'test-device',
// eslint-disable-next-line @typescript-eslint/naming-convention
'rcs_state': 'Y',
'serial': '<unknown>',
// eslint-disable-next-line @typescript-eslint/naming-convention
'target_type': 'workstation.qemu-x64',
// eslint-disable-next-line @typescript-eslint/naming-convention
'target_state': 'Product',
'addresses': ['fe80::3bee:1d4:e205:777e%brqemu', '172.1.1.1']
};
let device = new FuchsiaDevice(data);
assert.strictEqual(device.nodeName, data['nodename']);
assert.strictEqual(device.rcsState, data['rcs_state']);
assert.strictEqual(device.serial, data['serial']);
assert.strictEqual(device.targetType, data['target_type']);
assert.strictEqual(device.targetState, data['target_state']);
let testAddresses = data['addresses'];
let actualAddresses = device.addresses;
for (let i in testAddresses) {
assert.strictEqual(testAddresses[i], actualAddresses[i]);
}
});
});
});
describe('Ffx', function () {
const sandbox = createSandbox();
const TEST_FFX = '/path/to/ffx';
const TEST_CWD = '/path/to/workspace';
var log: vscode.OutputChannel;
var toolFinder: ToolFinder;
var stubbedSpawn: StubbedSpawn;
this.beforeEach(function () {
let logger = sandbox.spy(vscode.window.createOutputChannel);
log = logger('test_ffx');
toolFinder = new ToolFinder(log);
sandbox.stub(toolFinder, 'getFfxPath').returns(TEST_FFX);
stubbedSpawn = new StubbedSpawn(sandbox);
});
this.afterEach(function () {
sandbox.restore();
});
describe('#constructor', function () {
it('creates an instance of ffx', function () {
new Ffx(log, TEST_CWD, TEST_FFX);
});
});
describe('#rebootTarget', function () {
it('calls ffx target reboot for the default device successfully', async () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
try {
let promise = ffx.rebootTarget();
stubbedSpawn.spawnEvent.emit('exit', 0);
let output = await promise;
assert.strictEqual(output, '');
assert.deepStrictEqual(stubbedSpawn.spawnStubInfo.getCall(0).args,
[TEST_FFX, ['target', 'reboot'], { cwd: TEST_CWD }]);
} catch (err) {
assert.fail(`unexpected exception: ${err}`);
}
});
it('calls ffx target reboot for the default device and fails', async () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
const errorMessage = 'Cannot reboot device';
try {
let promise = ffx.rebootTarget();
stubbedSpawn.spawnEvent.stderr?.emit('data', errorMessage);
stubbedSpawn.spawnEvent.emit('exit', 1);
await promise;
} catch (err) {
assert.strictEqual(`Error 1: ${errorMessage}`, err);
}
});
it('calls ffx target reboot the specified device', async () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
let device = new FuchsiaDevice({ 'nodename': 'test-device' });
try {
let promise = ffx.rebootTarget(device);
stubbedSpawn.spawnEvent.emit('exit', 0);
let output = await promise;
assert.strictEqual(output, '');
assert.deepStrictEqual(stubbedSpawn.spawnStubInfo.getCall(0).args,
[TEST_FFX, ['--target', 'test-device', 'target', 'reboot'], { cwd: TEST_CWD }]);
} catch (err) {
assert.fail(`unexpected error: ${err}`);
}
});
});
describe('#showTarget', function () {
it('calls ffx target show for the default device successfully', async () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
try {
let promise = ffx.rebootTarget();
// normal exit, no output.
stubbedSpawn.spawnEvent.emit('exit', 0);
let output = await promise;
assert.strictEqual(output, '');
assert.deepStrictEqual(stubbedSpawn.spawnStubInfo.getCall(0).args,
[TEST_FFX, ['target', 'reboot'], { cwd: TEST_CWD }]);
} catch (err) {
assert.fail(`unexpected error: ${err}`);
}
});
it('calls ffx target reboot for the default device and fails', async () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
const errorMessage = 'Cannot reboot device';
try {
let promise = ffx.rebootTarget();
stubbedSpawn.spawnEvent.stderr?.emit('data', errorMessage);
stubbedSpawn.spawnEvent.emit('exit', 1);
await promise;
} catch (err) {
assert.strictEqual(`Error 1: ${errorMessage}`, err);
}
});
it('calls ffx target reboot the specified device', async () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
try {
let device = new FuchsiaDevice({ 'nodename': 'test-device' });
let promise = ffx.rebootTarget(device);
stubbedSpawn.spawnEvent.emit('exit', 0);
let output = await promise;
assert.strictEqual(output, '');
assert.deepStrictEqual(stubbedSpawn.spawnStubInfo.getCall(0).args,
[TEST_FFX, ['--target', 'test-device', 'target', 'reboot'], { cwd: TEST_CWD }]);
} catch (err) {
assert.fail(`unexpected error: ${err}`);
}
});
});
describe('#defaultTarget', function () {
it('sets the specified device to be the default target', async () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
let device = new FuchsiaDevice({ 'nodename': 'test-device' });
try {
let promise = ffx.defaultTarget(device);
stubbedSpawn.spawnEvent.emit('exit', 0);
let output = await promise;
assert.strictEqual(output, '');
assert.deepStrictEqual(stubbedSpawn.spawnStubInfo.getCall(0).args,
[TEST_FFX, ['target', 'default', 'set', 'test-device'], { cwd: TEST_CWD }]);
} catch (err) {
assert.fail(`unexpected error: ${err}`);
}
});
});
describe('#events', function () {
it('Verify set path events', () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
let lastEvent: FfxEventType | undefined;
ffx.onDidChangeConfiguration(event => {
lastEvent = event;
});
ffx.setFfxPath(TEST_FFX);
assert.strictEqual(lastEvent, FfxEventType.ffxPathSet);
ffx.setFfxPath(undefined);
assert.strictEqual(lastEvent, FfxEventType.ffxPathReset);
ffx.setFfxPath(TEST_FFX);
assert.strictEqual(lastEvent, FfxEventType.ffxPathSet);
});
});
describe('#getTargetList', function () {
const targetListData = [
{
'nodename': 'test-device',
// eslint-disable-next-line @typescript-eslint/naming-convention
'rcs_state': 'Y',
'serial': 'serial-11111',
// eslint-disable-next-line @typescript-eslint/naming-convention
'target_type': 'test-product',
// eslint-disable-next-line @typescript-eslint/naming-convention
'target_state': 'Product',
'addresses': ['fe80::41e7:ace8:59b7:3cb7%en11'],
// eslint-disable-next-line @typescript-eslint/naming-convention
'is_default': false
},
{
'nodename': 'another-device',
// eslint-disable-next-line @typescript-eslint/naming-convention
'rcs_state': 'Y',
'serial': 'serial-222222',
// eslint-disable-next-line @typescript-eslint/naming-convention
'target_type': 'test-product',
// eslint-disable-next-line @typescript-eslint/naming-convention
'target_state': 'Product',
'addresses': ['fe80::1010:1010:1010:1010%en11'],
// eslint-disable-next-line @typescript-eslint/naming-convention
'is_default': true
}
];
const TARGET_LIST_ARGS = ['target', 'list', '--format', 'json'];
it('gets a map of device name to FuchsiaDevice.', async () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
stubbedSpawn.spawnStubInfo.callsFake(function () {
setTimeout(() => {
stubbedSpawn.spawnEvent.stdout?.emit('data', JSON.stringify(targetListData));
stubbedSpawn.spawnEvent.emit('exit', 0);
}, 1);
return stubbedSpawn.spawnEvent;
});
try {
let deviceList = await ffx.getTargetList();
assert.deepStrictEqual(stubbedSpawn.spawnStubInfo.getCall(0).args,
[TEST_FFX, TARGET_LIST_ARGS, { cwd: TEST_CWD }]);
// check number of devices
assert.strictEqual(Object.keys(deviceList).length, targetListData.length);
} catch (err) {
assert.fail(`unexpected error: ${err}`);
}
});
it('gets a map of device name to FuchsiaDevice and gets the default.', async () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
stubbedSpawn.spawnStubInfo.callsFake(function () {
setTimeout(() => {
stubbedSpawn.spawnEvent.stdout?.emit('data', JSON.stringify(targetListData));
stubbedSpawn.spawnEvent.emit('exit', 0);
}, 1);
return stubbedSpawn.spawnEvent;
});
try {
let deviceList = await ffx.getTargetList();
assert.deepStrictEqual(stubbedSpawn.spawnStubInfo.getCall(0).args,
[TEST_FFX, TARGET_LIST_ARGS, { cwd: TEST_CWD }]);
// check number of devices
assert.strictEqual(Object.keys(deviceList).length, targetListData.length);
// check there is no default.
for (let name in deviceList) {
assert.strictEqual(deviceList[name].isDefault(),
deviceList[name].nodeName === 'another-device');
}
} catch (err) {
assert.fail(`unexpected error: ${err}`);
}
});
it('Verify set target event', async () => {
const ffx = new Ffx(log, TEST_CWD, TEST_FFX);
stubbedSpawn.spawnStubInfo.callsFake(function () {
setTimeout(() => {
stubbedSpawn.spawnEvent.stdout?.emit('data', JSON.stringify(targetListData));
stubbedSpawn.spawnEvent.emit('exit', 0);
}, 1);
return stubbedSpawn.spawnEvent;
});
let count = 0;
ffx.onSetTarget(target => {
count += 1;
});
assert.strictEqual(count, 0);
ffx.setFfxPath(TEST_FFX);
await new Promise(resolve => setTimeout(resolve, 50));
assert.strictEqual(count, 1);
});
});
describe('#runLog', () => {
let ffx: Ffx;
let log: vscode.OutputChannel;
const LOG_ARGS = ['--target', 'foo', '--machine', 'json', 'log'];
beforeEach(() => {
let logger = sandbox.spy(vscode.window.createOutputChannel);
log = logger('test_ffx');
ffx = new Ffx(log, TEST_CWD, TEST_FFX);
});
it('parses stdout and sends it to the callback', () => {
let received = undefined;
const TEST_DATA : Object = {'foo': 'bar'};
stubbedSpawn.spawnStubInfo.callsFake(() => stubbedSpawn.spawnEvent);
ffx.runLog('foo', (data) => {
received = data;
});
assert.deepStrictEqual(stubbedSpawn.spawnStubInfo.getCall(0).args,
[TEST_FFX, LOG_ARGS, { cwd: TEST_CWD }]);
stubbedSpawn.spawnEvent.stdout?.emit('data', JSON.stringify(TEST_DATA));
assert.deepStrictEqual(received, TEST_DATA);
});
it('sends stderr to the log', () => {
sandbox.spy(log, 'appendLine');
stubbedSpawn.spawnStubInfo.callsFake(() => stubbedSpawn.spawnEvent);
ffx.runLog('foo', (_) => {});
stubbedSpawn.spawnEvent.stderr?.emit('data', 'oh no');
// @ts-ignore: sinon
assert.ok(log.appendLine.calledTwice);
assert.deepStrictEqual(
// @ts-ignore: sinon
log.appendLine.getCall(0).args[0],
`Running: /path/to/ffx ${LOG_ARGS.join(' ')}`);
assert.deepStrictEqual(
// @ts-ignore: sinon
log.appendLine.getCall(1).args[0],
`Error [/path/to/ffx ${LOG_ARGS.join(' ')}]: oh no`
);
});
});
});