Bug 1493104 - Add unit test for AddonAwareADBScanner;r=ladybenko,daisuke

--HG--
extra : rebase_source : b508f59719bea9fc9b827155f8b872052fa69469
This commit is contained in:
Julian Descottes 2018-10-05 15:16:39 +02:00
Родитель f1a644359d
Коммит b05e78acd6
5 изменённых файлов: 252 добавлений и 7 удалений

Просмотреть файл

@ -22,14 +22,25 @@ loader.lazyRequireGetter(this, "ADBScanner", "devtools/shared/adb/adb-scanner",
* - event "runtime-list-updated" * - event "runtime-list-updated"
*/ */
class AddonAwareADBScanner extends EventEmitter { class AddonAwareADBScanner extends EventEmitter {
constructor() { /**
* Parameters are provided only to allow tests to replace actual implementations with
* mocks.
*
* @param {ADBScanner} scanner
* Only provided in tests for mocks
* @param {ADBAddon} addon
* Only provided in tests for mocks
*/
constructor(scanner = new ADBScanner(), addon = adbAddon) {
super(); super();
this._onScannerListUpdated = this._onScannerListUpdated.bind(this); this._onScannerListUpdated = this._onScannerListUpdated.bind(this);
this._onAddonUpdate = this._onAddonUpdate.bind(this); this._onAddonUpdate = this._onAddonUpdate.bind(this);
this._scanner = new ADBScanner(); this._scanner = scanner;
this._scanner.on("runtime-list-updated", this._onScannerListUpdated); this._scanner.on("runtime-list-updated", this._onScannerListUpdated);
this._addon = addon;
} }
/** /**
@ -37,21 +48,21 @@ class AddonAwareADBScanner extends EventEmitter {
* only works if the addon is installed. * only works if the addon is installed.
*/ */
enable() { enable() {
if (adbAddon.status === "installed") { if (this._addon.status === "installed") {
this._scanner.enable(); this._scanner.enable();
} }
// Remove any previous listener, to make sure we only add one listener if enable() is // Remove any previous listener, to make sure we only add one listener if enable() is
// called several times. // called several times.
adbAddon.off("update", this._onAddonUpdate); this._addon.off("update", this._onAddonUpdate);
adbAddon.on("update", this._onAddonUpdate); this._addon.on("update", this._onAddonUpdate);
} }
disable() { disable() {
this._scanner.disable(); this._scanner.disable();
adbAddon.off("update", this._onAddonUpdate); this._addon.off("update", this._onAddonUpdate);
} }
/** /**
@ -73,7 +84,7 @@ class AddonAwareADBScanner extends EventEmitter {
} }
_onAddonUpdate() { _onAddonUpdate() {
if (adbAddon.status === "installed") { if (this._addon.status === "installed") {
this._scanner.enable(); this._scanner.enable();
} else { } else {
this._scanner.disable(); this._scanner.disable();

Просмотреть файл

@ -1,3 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict"; "use strict";
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");

Просмотреть файл

@ -0,0 +1,221 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const EventEmitter = require("devtools/shared/event-emitter");
const { AddonAwareADBScanner } = require("devtools/shared/adb/addon-aware-adb-scanner");
/**
* For the scanner mock, we create an object with spies for each of the public methods
* used by the AddonAwareADBScanner, and the ability to emit events.
*/
function prepareMockScanner() {
const mockScanner = {
enable: sinon.spy(),
disable: sinon.spy(),
scan: sinon.spy(),
listRuntimes: sinon.spy()
};
EventEmitter.decorate(mockScanner);
return mockScanner;
}
/**
* For the addon mock, we simply need an object that is able to emit events and has a
* status.
*/
function prepareMockAddon() {
const mockAddon = {
status: "unknown",
};
EventEmitter.decorate(mockAddon);
return mockAddon;
}
/**
* Prepare all mocks needed for the scanner tests.
*/
function prepareMocks() {
const mockScanner = prepareMockScanner();
const mockAddon = prepareMockAddon();
const addonAwareAdbScanner = new AddonAwareADBScanner(mockScanner, mockAddon);
return { addonAwareAdbScanner, mockAddon, mockScanner };
}
/**
* This test covers basic usage of enable() on the AddonAwareADBScanner, and checks the
* different behaviors based on the addon status.
*/
add_task(async function testCallingEnable() {
const { mockScanner, mockAddon, addonAwareAdbScanner } = prepareMocks();
// Check that enable() is not called if the addon is uninstalled
mockAddon.status = "uninstalled";
addonAwareAdbScanner.enable();
ok(mockScanner.enable.notCalled, "enable() was not called");
mockScanner.enable.reset();
// Check that enable() is called if the addon is installed
mockAddon.status = "installed";
addonAwareAdbScanner.enable();
ok(mockScanner.enable.called, "enable() was called");
mockScanner.enable.reset();
});
/**
* This test checks that enable()/disable() methods from the internal ADBScanner are
* called when the addon is installed or uninstalled.
*/
add_task(async function testUpdatingAddonEnablesDisablesScanner() {
const { mockScanner, mockAddon, addonAwareAdbScanner } = prepareMocks();
// Enable the addon aware scanner
addonAwareAdbScanner.enable();
ok(mockScanner.enable.notCalled, "enable() was not called initially");
// Check that enable() is called automatically when the addon is installed
mockAddon.status = "installed";
mockAddon.emit("update");
ok(mockScanner.enable.called, "enable() was called when installing the addon");
ok(mockScanner.disable.notCalled, "disable() was not called when installing the addon");
mockScanner.enable.reset();
mockScanner.disable.reset();
// Check that disabled() is called automatically when the addon is uninstalled
mockAddon.status = "uninstalled";
mockAddon.emit("update");
ok(mockScanner.enable.notCalled, "enable() was not called when uninstalling the addon");
ok(mockScanner.disable.called, "disable() was called when uninstalling the addon");
mockScanner.enable.reset();
mockScanner.disable.reset();
// Check that enable() is called again when the addon is reinstalled
mockAddon.status = "installed";
mockAddon.emit("update");
ok(mockScanner.enable.called, "enable() was called when installing the addon");
ok(mockScanner.disable.notCalled, "disable() was not called when installing the addon");
mockScanner.enable.reset();
mockScanner.disable.reset();
});
/**
* This test checks that disable() is forwarded from the AddonAwareADBScanner to the real
* scanner even if the addon is uninstalled. We might miss the addon uninstall
* notification, so it is safer to always proceed with disabling.
*/
add_task(async function testScannerIsDisabledWhenMissingAddonUpdate() {
const { mockScanner, mockAddon, addonAwareAdbScanner } = prepareMocks();
// Enable the addon aware scanner
mockAddon.status = "installed";
addonAwareAdbScanner.enable();
ok(mockScanner.enable.called, "enable() was called initially");
mockScanner.enable.reset();
// Uninstall the addon without firing any event
mockAddon.status = "uninstalled";
// Programmatically call disable, check that the scanner's disable is called even though
// the addon was uninstalled.
addonAwareAdbScanner.disable();
ok(mockScanner.disable.called, "disable() was called when uninstalling the addon");
mockScanner.disable.reset();
});
/**
* This test checks that when the AddonAwareADBScanner is disabled, then enable/disable
* are not called on the inner scanner when the addon status changes.
*/
add_task(async function testInnerEnableIsNotCalledIfNotStarted() {
const { mockScanner, mockAddon, addonAwareAdbScanner } = prepareMocks();
// Check that enable() is not called on the inner scanner when the addon is installed
// if the AddonAwareADBScanner was not enabled
mockAddon.status = "installed";
mockAddon.emit("update");
ok(mockScanner.enable.notCalled, "enable() was not called");
// Same for disable() and "uninstall"
mockAddon.status = "uninstalled";
mockAddon.emit("update");
ok(mockScanner.disable.notCalled, "disable() was not called");
// Enable the addon aware scanner
addonAwareAdbScanner.enable();
ok(mockScanner.enable.notCalled, "enable() was not called");
ok(mockScanner.disable.notCalled, "disable() was not called");
});
/**
* This test checks that when the AddonAwareADBScanner is disabled, installing the addon
* no longer enables the internal ADBScanner.
*/
add_task(async function testEnableIsNoLongerCalledAfterDisabling() {
const { mockScanner, mockAddon, addonAwareAdbScanner } = prepareMocks();
// Start with the addon installed
mockAddon.status = "installed";
addonAwareAdbScanner.enable();
ok(mockScanner.enable.called, "enable() was called since addon was already installed");
mockScanner.enable.reset();
// Here we call enable again to check that we will not add too many events.
// A single call to disable() should stop all listeners, even if we called enable()
// several times.
addonAwareAdbScanner.enable();
ok(mockScanner.enable.called, "enable() was called again");
mockScanner.enable.reset();
// Disable the scanner
addonAwareAdbScanner.disable();
ok(mockScanner.disable.called, "disable() was called");
mockScanner.disable.reset();
// Emit an addon update event
mockAddon.emit("update");
ok(mockScanner.enable.notCalled,
"enable() is not called since the main scanner is disabled");
});
/**
* Basic check that the "runtime-list-updated" event is forwarded.
*/
add_task(async function testListUpdatedEventForwarding() {
const { mockScanner, addonAwareAdbScanner } = prepareMocks();
const spy = sinon.spy();
addonAwareAdbScanner.on("runtime-list-updated", spy);
mockScanner.emit("runtime-list-updated");
ok(spy.called, "The runtime-list-updated event was forwarded from ADBScanner");
addonAwareAdbScanner.off("runtime-list-updated", spy);
});
/**
* Basic check that calls to scan() are forwarded.
*/
add_task(async function testScanCallForwarding() {
const { mockScanner, addonAwareAdbScanner } = prepareMocks();
ok(mockScanner.scan.notCalled, "ADBScanner scan() is not called initially");
addonAwareAdbScanner.scan();
mockScanner.emit("runtime-list-updated");
ok(mockScanner.scan.called, "ADBScanner scan() was called");
mockScanner.scan.reset();
});
/**
* Basic check that calls to scan() are forwarded.
*/
add_task(async function testListRuntimesCallForwarding() {
const { mockScanner, addonAwareAdbScanner } = prepareMocks();
ok(mockScanner.listRuntimes.notCalled,
"ADBScanner listRuntimes() is not called initially");
addonAwareAdbScanner.listRuntimes();
mockScanner.emit("runtime-list-updated");
ok(mockScanner.listRuntimes.called, "ADBScanner listRuntimes() was called");
mockScanner.scan.reset();
});

Просмотреть файл

@ -6,3 +6,12 @@
/* eslint no-unused-vars: [2, {"vars": "local"}] */ /* eslint no-unused-vars: [2, {"vars": "local"}] */
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {}); const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
const Services = require("Services");
// ================================================
// Load mocking/stubbing library, sinon
// docs: http://sinonjs.org/releases/v2.3.2/
ChromeUtils.import("resource://gre/modules/Timer.jsm");
Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js", this);
/* globals sinon */
// ================================================

Просмотреть файл

@ -8,3 +8,4 @@ support-files =
[test_adb.js] [test_adb.js]
run-sequentially = An extension having the same id is installed/uninstalled in different tests run-sequentially = An extension having the same id is installed/uninstalled in different tests
[test_addon-aware-adb-scanner.js]