diff --git a/script/lib/dbus_mock.py b/script/lib/dbus_mock.py new file mode 100644 index 000000000000..76f39fc26973 --- /dev/null +++ b/script/lib/dbus_mock.py @@ -0,0 +1,13 @@ +from dbusmock import DBusTestCase + +import atexit + +def cleanup(): + DBusTestCase.stop_dbus(DBusTestCase.system_bus_pid) + + +atexit.register(cleanup) +DBusTestCase.start_system_bus() +# create a mock for "org.freedesktop.login1" using python-dbusmock +# preconfigured template +(logind_mock, logind) = DBusTestCase.spawn_server_template('logind') diff --git a/script/test.py b/script/test.py index b09cff582806..67292997348b 100755 --- a/script/test.py +++ b/script/test.py @@ -10,6 +10,20 @@ from lib.config import enable_verbose_mode from lib.util import electron_gyp, execute_stdout, rm_rf +if sys.platform == 'linux2': + # On Linux we use python-dbusmock to create a fake system bus and test + # powerMonitor interaction with org.freedesktop.login1 service. The + # dbus_mock module takes care of setting up the fake server with mock, + # while also setting DBUS_SYSTEM_BUS_ADDRESS environment variable, which + # will be picked up by electron. + try: + import lib.dbus_mock + except ImportError: + # If not available, the powerMonitor tests will be skipped since + # DBUS_SYSTEM_BUS_ADDRESS will not be set + pass + + SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) PROJECT_NAME = electron_gyp()['project_name%'] diff --git a/spec/api-power-monitor-spec.js b/spec/api-power-monitor-spec.js new file mode 100644 index 000000000000..5b8b84fc655d --- /dev/null +++ b/spec/api-power-monitor-spec.js @@ -0,0 +1,89 @@ +// For these tests we use a fake DBus daemon to verify powerMonitor module +// interaction with the system bus. This requires python-dbusmock installed and +// running (with the DBUS_SYSTEM_BUS_ADDRESS environment variable set). +// script/test.py will take care of spawning the fake DBus daemon and setting +// DBUS_SYSTEM_BUS_ADDRESS when python-dbusmock is installed. +// +// See https://pypi.python.org/pypi/python-dbusmock for more information about +// python-dbusmock. +const assert = require('assert') +const dbus = require('dbus-native') +const Promise = require('bluebird') + +const skip = process.platform !== 'linux' || !process.env.DBUS_SYSTEM_BUS_ADDRESS; + +(skip ? describe.skip : describe)('powerMonitor', () => { + let logindMock, powerMonitor, getCalls, emitSignal, reset + + before(async () => { + const systemBus = dbus.systemBus() + const loginService = systemBus.getService('org.freedesktop.login1') + const getInterface = Promise.promisify(loginService.getInterface, {context: loginService}) + logindMock = await getInterface('/org/freedesktop/login1', 'org.freedesktop.DBus.Mock') + getCalls = Promise.promisify(logindMock.GetCalls, {context: logindMock}) + emitSignal = Promise.promisify(logindMock.EmitSignal, {context: logindMock}) + reset = Promise.promisify(logindMock.Reset, {context: logindMock}) + }) + + after(async () => { + await reset() + }) + + describe('when powerMonitor module is loaded', () => { + function onceMethodCalled (done) { + function cb () { + logindMock.removeListener('MethodCalled', cb) + } + done() + return cb + } + + before((done) => { + logindMock.on('MethodCalled', onceMethodCalled(done)) + // lazy load powerMonitor after we listen to MethodCalled mock signal + powerMonitor = require('electron').remote.powerMonitor + }) + + it('should call Inhibit to delay suspend', async () => { + const calls = await getCalls() + assert.equal(calls.length, 1) + assert.deepEqual(calls[0].slice(1), [ + 'Inhibit', [ + [[{type: 's', child: []}], ['sleep']], + [[{type: 's', child: []}], ['electron']], + [[{type: 's', child: []}], ['Application cleanup before suspend']], + [[{type: 's', child: []}], ['delay']] + ] + ]) + }) + + describe('when PrepareForSleep(true) signal is sent by logind', () => { + it('should emit "suspend" event', (done) => { + powerMonitor.once('suspend', () => done()) + emitSignal('org.freedesktop.login1.Manager', 'PrepareForSleep', + 'b', [['b', true]]) + }) + + describe('when PrepareForSleep(false) signal is sent by logind', () => { + it('should emit "resume" event', (done) => { + powerMonitor.once('resume', () => done()) + emitSignal('org.freedesktop.login1.Manager', 'PrepareForSleep', + 'b', [['b', false]]) + }) + + it('should have called Inhibit again', async () => { + const calls = await getCalls() + assert.equal(calls.length, 2) + assert.deepEqual(calls[1].slice(1), [ + 'Inhibit', [ + [[{type: 's', child: []}], ['sleep']], + [[{type: 's', child: []}], ['electron']], + [[{type: 's', child: []}], ['Application cleanup before suspend']], + [[{type: 's', child: []}], ['delay']] + ] + ]) + }) + }) + }) + }) +}) diff --git a/spec/package.json b/spec/package.json index de51b96468d9..b873554cac52 100644 --- a/spec/package.json +++ b/spec/package.json @@ -5,8 +5,10 @@ "version": "0.1.0", "devDependencies": { "basic-auth": "^1.0.4", + "bluebird": "^3.5.1", "chai": "^4.1.2", "coffee-script": "1.12.7", + "dbus-native": "^0.2.3", "graceful-fs": "^4.1.9", "mkdirp": "^0.5.1", "mocha": "^3.1.0",