Skip to content

Commit

Permalink
Implement generic module with helper functions, resolves #23
Browse files Browse the repository at this point in the history
  • Loading branch information
NeoTheThird committed Nov 5, 2020
1 parent e4c90b2 commit bbf9ad7
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 1 deletion.
65 changes: 64 additions & 1 deletion src/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,67 @@ const Fastboot = require("./fastboot.js");
const Heimdall = require("./heimdall.js");
const Tool = require("./tool.js");

module.exports = { Adb, Fastboot, Heimdall, Tool };
const EventEmitter = require("events");
const { CancelablePromise } = require("cancelable-promise");

/**
* A wrapper for Adb, Fastboot, and Heimall that returns convenient promises.
*/
class DeviceTools extends EventEmitter {
constructor() {
super();
this.adb = new Adb();
this.fastboot = new Fastboot();
this.heimdall = new Heimdall();

["adb", "fastboot", "heimdall"].forEach(tool => {
this[tool].on("exec", r => this.emit("exec", r));
this[tool].on("spawn:start", r => this.emit("spawn:start", r));
this[tool].on("spawn:exit", r => this.emit("spawn:exit", r));
this[tool].on("spawn:error", r => this.emit("spawn:error", r));
});
}

/**
* Wait for a device
* @returns {CancelablePromise<String>}
*/
wait() {
const _this = this;
return new CancelablePromise(function(resolve, reject, onCancel) {
const waitPromises = [
_this.adb.wait(),
_this.fastboot.wait(),
_this.heimdall.wait()
];
CancelablePromise.race(waitPromises)
.then(state => {
waitPromises.forEach(p => p.cancel());
resolve(state);
})
.catch(() => {
reject(new Error("no device"));
});

onCancel(() => waitPromises.forEach(p => p.cancel()));
});
}

/**
* Wait for a device
* @returns {Promise<String>}
*/
getDeviceName() {
return Promise.any([
this.adb.getDeviceName(),
this.fastboot.getDeviceName(),
this.heimdall.hasAccess().then(() => {
throw new Error(`Can't get name from heimdall`);
})
]).catch(() => {
throw new Error("no device");
});
}
}

module.exports = { Adb, Fastboot, Heimdall, Tool, DeviceTools };
115 changes: 115 additions & 0 deletions tests/unit-tests/test_module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"use strict";

/*
* Copyright (C) 2017-2019 UBports Foundation <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

const chai = require("chai");
const sinon = require("sinon");
const chaiAsPromised = require("chai-as-promised");
const sinonChai = require("sinon-chai");
const expect = chai.expect;
chai.use(sinonChai);
chai.use(chaiAsPromised);

const DeviceTools = require("../../src/module.js").DeviceTools;
const { CancelablePromise } = require("cancelable-promise");

function expectReject(error, message) {
expect(error).to.be.instanceOf(Error);
expect(error).to.haveOwnProperty("message", message);
}

describe("DeviceTools module", function() {
describe("constructor()", function() {
it("should construct deviceTools", function() {
const deviceTools = new DeviceTools();
expect(deviceTools).to.exist;
});
});
describe("wait()", function() {
it("should resolve mode", function() {
const deviceTools = new DeviceTools();
sinon
.stub(deviceTools.adb, "wait")
.returns(CancelablePromise.resolve("device"));
sinon
.stub(deviceTools.fastboot, "wait")
.returns(CancelablePromise.reject());
sinon
.stub(deviceTools.heimdall, "wait")
.returns(CancelablePromise.reject());
return deviceTools.wait().then(r => {
expect(r).to.eql("device");
});
});
it("should reject if all wait functions rejected", function(done) {
const deviceTools = new DeviceTools();
sinon.stub(deviceTools.adb, "wait").returns(CancelablePromise.reject());
sinon
.stub(deviceTools.fastboot, "wait")
.returns(CancelablePromise.reject());
sinon
.stub(deviceTools.heimdall, "wait")
.returns(CancelablePromise.reject());
deviceTools.wait().catch(e => {
expectReject(e, "no device");
done();
});
});
it("should be cancellable", function() {
const deviceTools = new DeviceTools();
sinon.stub(deviceTools.adb, "wait").returns(new CancelablePromise());
sinon.stub(deviceTools.fastboot, "wait").returns(new CancelablePromise());
sinon.stub(deviceTools.heimdall, "wait").returns(new CancelablePromise());
const cp = deviceTools.wait();
cp.cancel();
});
});
describe("getDeviceName()", function() {
it("should resolve device name", function() {
const deviceTools = new DeviceTools();
sinon
.stub(deviceTools.adb, "getDeviceName")
.returns(CancelablePromise.resolve("asdf"));
sinon
.stub(deviceTools.fastboot, "getDeviceName")
.returns(CancelablePromise.reject());
sinon
.stub(deviceTools.heimdall, "hasAccess")
.returns(CancelablePromise.resolve(false));
return deviceTools.getDeviceName().then(r => {
expect(r).to.eql("asdf");
});
});
it("should reject on error", function(done) {
const deviceTools = new DeviceTools();
sinon
.stub(deviceTools.adb, "getDeviceName")
.returns(CancelablePromise.reject());
sinon
.stub(deviceTools.fastboot, "getDeviceName")
.returns(CancelablePromise.reject());
sinon
.stub(deviceTools.heimdall, "hasAccess")
.returns(CancelablePromise.resolve(false));
deviceTools.getDeviceName().catch(e => {
expectReject(e, "no device");
done();
});
});
});
});

0 comments on commit bbf9ad7

Please sign in to comment.