mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1150683 - Add xpcshell tests for nsIPushNotificationService. r=dougt
--- dom/push/moz.build | 4 + dom/push/test/xpcshell/head.js | 450 +++++++++++++++++++++ dom/push/test/xpcshell/test_notification_ack.js | 127 ++++++ .../test/xpcshell/test_notification_duplicate.js | 82 ++++ dom/push/test/xpcshell/test_notification_error.js | 127 ++++++ .../test/xpcshell/test_notification_incomplete.js | 109 +++++ .../xpcshell/test_notification_version_string.js | 72 ++++ dom/push/test/xpcshell/test_register_case.js | 64 +++ dom/push/test/xpcshell/test_register_flush.js | 103 +++++ .../test/xpcshell/test_register_invalid_channel.js | 60 +++ .../xpcshell/test_register_invalid_endpoint.js | 62 +++ .../test/xpcshell/test_register_invalid_json.js | 61 +++ dom/push/test/xpcshell/test_register_no_id.js | 65 +++ .../test/xpcshell/test_register_request_queue.js | 65 +++ dom/push/test/xpcshell/test_register_rollback.js | 88 ++++ dom/push/test/xpcshell/test_register_success.js | 76 ++++ dom/push/test/xpcshell/test_register_timeout.js | 102 +++++ dom/push/test/xpcshell/test_register_wrong_id.js | 71 ++++ dom/push/test/xpcshell/test_register_wrong_type.js | 67 +++ dom/push/test/xpcshell/test_registration_error.js | 39 ++ .../xpcshell/test_registration_missing_scope.js | 28 ++ dom/push/test/xpcshell/test_registration_none.js | 28 ++ .../test/xpcshell/test_registration_success.js | 67 +++ .../test/xpcshell/test_unregister_empty_scope.js | 37 ++ dom/push/test/xpcshell/test_unregister_error.js | 65 +++ .../test/xpcshell/test_unregister_invalid_json.js | 78 ++++ .../test/xpcshell/test_unregister_not_found.js | 35 ++ dom/push/test/xpcshell/test_unregister_success.js | 60 +++ dom/push/test/xpcshell/xpcshell.ini | 32 ++ 29 files changed, 2324 insertions(+) create mode 100644 dom/push/test/xpcshell/head.js create mode 100644 dom/push/test/xpcshell/test_notification_ack.js create mode 100644 dom/push/test/xpcshell/test_notification_duplicate.js create mode 100644 dom/push/test/xpcshell/test_notification_error.js create mode 100644 dom/push/test/xpcshell/test_notification_incomplete.js create mode 100644 dom/push/test/xpcshell/test_notification_version_string.js create mode 100644 dom/push/test/xpcshell/test_register_case.js create mode 100644 dom/push/test/xpcshell/test_register_flush.js create mode 100644 dom/push/test/xpcshell/test_register_invalid_channel.js create mode 100644 dom/push/test/xpcshell/test_register_invalid_endpoint.js create mode 100644 dom/push/test/xpcshell/test_register_invalid_json.js create mode 100644 dom/push/test/xpcshell/test_register_no_id.js create mode 100644 dom/push/test/xpcshell/test_register_request_queue.js create mode 100644 dom/push/test/xpcshell/test_register_rollback.js create mode 100644 dom/push/test/xpcshell/test_register_success.js create mode 100644 dom/push/test/xpcshell/test_register_timeout.js create mode 100644 dom/push/test/xpcshell/test_register_wrong_id.js create mode 100644 dom/push/test/xpcshell/test_register_wrong_type.js create mode 100644 dom/push/test/xpcshell/test_registration_error.js create mode 100644 dom/push/test/xpcshell/test_registration_missing_scope.js create mode 100644 dom/push/test/xpcshell/test_registration_none.js create mode 100644 dom/push/test/xpcshell/test_registration_success.js create mode 100644 dom/push/test/xpcshell/test_unregister_empty_scope.js create mode 100644 dom/push/test/xpcshell/test_unregister_error.js create mode 100644 dom/push/test/xpcshell/test_unregister_invalid_json.js create mode 100644 dom/push/test/xpcshell/test_unregister_not_found.js create mode 100644 dom/push/test/xpcshell/test_unregister_success.js create mode 100644 dom/push/test/xpcshell/xpcshell.ini
This commit is contained in:
parent
cce6e2c54e
commit
8bba6b8775
@ -16,3 +16,7 @@ EXTRA_PP_JS_MODULES += [
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'test/mochitest.ini',
|
||||
]
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += [
|
||||
'test/xpcshell/xpcshell.ini',
|
||||
]
|
||||
|
450
dom/push/test/xpcshell/head.js
Normal file
450
dom/push/test/xpcshell/head.js
Normal file
@ -0,0 +1,450 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/Timer.jsm');
|
||||
Cu.import('resource://gre/modules/Promise.jsm');
|
||||
Cu.import('resource://gre/modules/Preferences.jsm');
|
||||
|
||||
const serviceExports = Cu.import('resource://gre/modules/PushService.jsm', {});
|
||||
const servicePrefs = new Preferences('dom.push.');
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"PushNotificationService",
|
||||
"@mozilla.org/push/NotificationService;1",
|
||||
"nsIPushNotificationService"
|
||||
);
|
||||
|
||||
const DEFAULT_TIMEOUT = 5000;
|
||||
|
||||
const WEBSOCKET_CLOSE_GOING_AWAY = 1001;
|
||||
|
||||
// Stop and clean up after the PushService.
|
||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
||||
Services.obs.removeObserver(observe, topic, false);
|
||||
serviceExports.PushService.uninit();
|
||||
// Occasionally, `profile-change-teardown` and `xpcom-shutdown` will fire
|
||||
// before the PushService and AlarmService finish writing to IndexedDB. This
|
||||
// causes spurious errors and crashes, so we spin the event loop to let the
|
||||
// writes finish.
|
||||
let done = false;
|
||||
setTimeout(() => done = true, 1000);
|
||||
let thread = Services.tm.mainThread;
|
||||
while (!done) {
|
||||
try {
|
||||
thread.processNextEvent(true);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
}, 'profile-change-net-teardown', false);
|
||||
|
||||
/**
|
||||
* Gates a function so that it is called only after the wrapper is called a
|
||||
* given number of times.
|
||||
*
|
||||
* @param {Number} times The number of wrapper calls before |func| is called.
|
||||
* @param {Function} func The function to gate.
|
||||
* @returns {Function} The gated function wrapper.
|
||||
*/
|
||||
function after(times, func) {
|
||||
return function afterFunc() {
|
||||
if (--times <= 0) {
|
||||
return func.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a Push database in a proxy that returns promises for all asynchronous
|
||||
* methods. This makes it easier to test the database code with Task.jsm.
|
||||
*
|
||||
* @param {PushDB} db A Push database.
|
||||
* @returns {Proxy} A proxy that traps function property gets and returns
|
||||
* promisified functions.
|
||||
*/
|
||||
function promisifyDatabase(db) {
|
||||
return new Proxy(db, {
|
||||
get(target, property) {
|
||||
let method = target[property];
|
||||
if (typeof method != 'function') {
|
||||
return method;
|
||||
}
|
||||
return function(...params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
method.call(target, ...params, resolve, reject);
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears and closes an open Push database.
|
||||
*
|
||||
* @param {PushDB} db A Push database.
|
||||
* @returns {Promise} A promise that fulfills when the database is closed.
|
||||
*/
|
||||
function cleanupDatabase(db) {
|
||||
return new Promise(resolve => {
|
||||
function close() {
|
||||
db.close();
|
||||
resolve();
|
||||
}
|
||||
db.drop(close, close);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Defers one or more callbacks until the next turn of the event loop. Multiple
|
||||
* callbacks are executed in order.
|
||||
*
|
||||
* @param {Function[]} callbacks The callbacks to execute. One callback will be
|
||||
* executed per tick.
|
||||
*/
|
||||
function waterfall(...callbacks) {
|
||||
callbacks.reduce((promise, callback) => promise.then(() => {
|
||||
callback();
|
||||
}), Promise.resolve()).catch(Cu.reportError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for an observer notification to fire.
|
||||
*
|
||||
* @param {String} topic The notification topic.
|
||||
* @returns {Promise} A promise that fulfills when the notification is fired.
|
||||
*/
|
||||
function promiseObserverNotification(topic, matchFunc) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
||||
let matches = typeof matchFunc != 'function' || matchFunc(subject, data);
|
||||
if (!matches) {
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(observe, topic, false);
|
||||
resolve({subject, data});
|
||||
}, topic, false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a promise to settle. Returns a rejected promise if the promise
|
||||
* is not resolved or rejected within the given delay.
|
||||
*
|
||||
* @param {Promise} promise The pending promise.
|
||||
* @param {Number} delay The time to wait before rejecting the promise.
|
||||
* @param {String} [message] The rejection message if the promise times out.
|
||||
* @returns {Promise} A promise that settles with the value of the pending
|
||||
* promise, or rejects if the pending promise times out.
|
||||
*/
|
||||
function waitForPromise(promise, delay, message = 'Timed out waiting on promise') {
|
||||
let timeoutDefer = Promise.defer();
|
||||
let id = setTimeout(() => timeoutDefer.reject(new Error(message)), delay);
|
||||
return Promise.race([
|
||||
promise.then(value => {
|
||||
clearTimeout(id);
|
||||
return value;
|
||||
}, error => {
|
||||
clearTimeout(id);
|
||||
throw error;
|
||||
}),
|
||||
timeoutDefer.promise
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an object in a proxy that traps property gets and returns stubs. If
|
||||
* the stub is a function, the original value will be passed as the first
|
||||
* argument. If the original value is a function, the proxy returns a wrapper
|
||||
* that calls the stub; otherwise, the stub is called as a getter.
|
||||
*
|
||||
* @param {Object} target The object to wrap.
|
||||
* @param {Object} stubs An object containing stubbed values and functions.
|
||||
* @returns {Proxy} A proxy that returns stubs for property gets.
|
||||
*/
|
||||
function makeStub(target, stubs) {
|
||||
return new Proxy(target, {
|
||||
get(target, property) {
|
||||
if (!stubs || typeof stubs != 'object' || !(property in stubs)) {
|
||||
return target[property];
|
||||
}
|
||||
let stub = stubs[property];
|
||||
if (typeof stub != 'function') {
|
||||
return stub;
|
||||
}
|
||||
let original = target[property];
|
||||
if (typeof original != 'function') {
|
||||
return stub.call(this, original);
|
||||
}
|
||||
return function callStub(...params) {
|
||||
return stub.call(this, original, ...params);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables `push` and `pushsubscriptionchange` service worker events for the
|
||||
* given scopes. These events cause crashes in xpcshell, so we disable them
|
||||
* for testing nsIPushNotificationService.
|
||||
*
|
||||
* @param {String[]} scopes A list of scope URLs.
|
||||
*/
|
||||
function disableServiceWorkerEvents(...scopes) {
|
||||
for (let scope of scopes) {
|
||||
Services.perms.add(
|
||||
Services.io.newURI(scope, null, null),
|
||||
'push',
|
||||
Ci.nsIPermissionManager.DENY_ACTION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default PushService preferences. All pref names are prefixed with
|
||||
* `dom.push.`; any additional preferences will override the defaults.
|
||||
*
|
||||
* @param {Object} [prefs] Additional preferences to set.
|
||||
*/
|
||||
function setPrefs(prefs = {}) {
|
||||
let defaultPrefs = Object.assign({
|
||||
debug: true,
|
||||
serverURL: 'wss://push.example.org',
|
||||
'connection.enabled': true,
|
||||
userAgentID: '',
|
||||
enabled: true,
|
||||
// Disable adaptive pings and UDP wake-up by default; these are
|
||||
// tested separately.
|
||||
'adaptive.enabled': false,
|
||||
'udp.wakeupEnabled': false,
|
||||
// Defaults taken from /b2g/app/b2g.js.
|
||||
requestTimeout: 10000,
|
||||
retryBaseInterval: 5000,
|
||||
pingInterval: 30 * 60 * 1000,
|
||||
'pingInterval.default': 3 * 60 * 1000,
|
||||
'pingInterval.mobile': 3 * 60 * 1000,
|
||||
'pingInterval.wifi': 3 * 60 * 1000,
|
||||
'adaptive.lastGoodPingInterval': 3 * 60 * 1000,
|
||||
'adaptive.lastGoodPingInterval.mobile': 3 * 60 * 1000,
|
||||
'adaptive.lastGoodPingInterval.wifi': 3 * 60 * 1000,
|
||||
'adaptive.gap': 60000,
|
||||
'adaptive.upperLimit': 29 * 60 * 1000,
|
||||
// Misc. defaults.
|
||||
'adaptive.mobile': ''
|
||||
}, prefs);
|
||||
for (let pref in defaultPrefs) {
|
||||
servicePrefs.set(pref, defaultPrefs[pref]);
|
||||
}
|
||||
}
|
||||
|
||||
function compareAscending(a, b) {
|
||||
return a > b ? 1 : a < b ? -1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock WebSocket object that implements a subset of the
|
||||
* nsIWebSocketChannel interface used by the PushService.
|
||||
*
|
||||
* The given protocol handlers are invoked for each Simple Push command sent
|
||||
* by the PushService. The ping handler is optional; all others will throw if
|
||||
* the PushService sends a command for which no handler is registered.
|
||||
*
|
||||
* All nsIWebSocketListener methods will be called asynchronously.
|
||||
* serverSendMsg() and serverClose() can be used to respond to client messages
|
||||
* and close the "server" end of the connection, respectively.
|
||||
*
|
||||
* @param {nsIURI} originalURI The original WebSocket URL.
|
||||
* @param {Function} options.onHello The "hello" handshake command handler.
|
||||
* @param {Function} options.onRegister The "register" command handler.
|
||||
* @param {Function} options.onUnregister The "unregister" command handler.
|
||||
* @param {Function} options.onACK The "ack" command handler.
|
||||
* @param {Function} [options.onPing] An optional ping handler.
|
||||
*/
|
||||
function MockWebSocket(originalURI, handlers = {}) {
|
||||
this._originalURI = originalURI;
|
||||
this._onHello = handlers.onHello;
|
||||
this._onRegister = handlers.onRegister;
|
||||
this._onUnregister = handlers.onUnregister;
|
||||
this._onACK = handlers.onACK;
|
||||
this._onPing = handlers.onPing;
|
||||
}
|
||||
|
||||
MockWebSocket.prototype = {
|
||||
_originalURI: null,
|
||||
_onHello: null,
|
||||
_onRegister: null,
|
||||
_onUnregister: null,
|
||||
_onACK: null,
|
||||
_onPing: null,
|
||||
|
||||
_listener: null,
|
||||
_context: null,
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsISupports,
|
||||
Ci.nsIWebSocketChannel
|
||||
]),
|
||||
|
||||
get originalURI() {
|
||||
return this._originalURI;
|
||||
},
|
||||
|
||||
asyncOpen(uri, origin, listener, context) {
|
||||
this._listener = listener;
|
||||
this._context = context;
|
||||
waterfall(() => this._listener.onStart(this._context));
|
||||
},
|
||||
|
||||
_handleMessage(msg) {
|
||||
let messageType, request;
|
||||
if (msg == '{}') {
|
||||
request = {};
|
||||
messageType = 'ping';
|
||||
} else {
|
||||
request = JSON.parse(msg);
|
||||
messageType = request.messageType;
|
||||
}
|
||||
switch (messageType) {
|
||||
case 'hello':
|
||||
if (typeof this._onHello != 'function') {
|
||||
throw new Error('Unexpected handshake request');
|
||||
}
|
||||
this._onHello(request);
|
||||
break;
|
||||
|
||||
case 'register':
|
||||
if (typeof this._onRegister != 'function') {
|
||||
throw new Error('Unexpected register request');
|
||||
}
|
||||
this._onRegister(request);
|
||||
break;
|
||||
|
||||
case 'unregister':
|
||||
if (typeof this._onUnregister != 'function') {
|
||||
throw new Error('Unexpected unregister request');
|
||||
}
|
||||
this._onUnregister(request);
|
||||
break;
|
||||
|
||||
case 'ack':
|
||||
if (typeof this._onACK != 'function') {
|
||||
throw new Error('Unexpected acknowledgement');
|
||||
}
|
||||
this._onACK(request);
|
||||
break;
|
||||
|
||||
case 'ping':
|
||||
if (typeof this._onPing == 'function') {
|
||||
this._onPing(request);
|
||||
} else {
|
||||
// Echo ping packets.
|
||||
this.serverSendMsg('{}');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error('Unexpected message: ' + messageType);
|
||||
}
|
||||
},
|
||||
|
||||
sendMsg(msg) {
|
||||
this._handleMessage(msg);
|
||||
},
|
||||
|
||||
close(code, reason) {
|
||||
waterfall(() => this._listener.onStop(this._context, Cr.NS_OK));
|
||||
},
|
||||
|
||||
/**
|
||||
* Responds with the given message, calling onMessageAvailable() and
|
||||
* onAcknowledge() synchronously. Throws if the message is not a string.
|
||||
* Used by the tests to respond to client commands.
|
||||
*
|
||||
* @param {String} msg The message to send to the client.
|
||||
*/
|
||||
serverSendMsg(msg) {
|
||||
if (typeof msg != 'string') {
|
||||
throw new Error('Invalid response message');
|
||||
}
|
||||
waterfall(
|
||||
() => this._listener.onMessageAvailable(this._context, msg),
|
||||
() => this._listener.onAcknowledge(this._context, 0)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the server end of the connection, calling onServerClose()
|
||||
* followed by onStop(). Used to test abrupt connection termination
|
||||
* and UDP wake-up.
|
||||
*
|
||||
* @param {Number} [statusCode] The WebSocket connection close code.
|
||||
* @param {String} [reason] The connection close reason.
|
||||
*/
|
||||
serverClose(statusCode, reason = '') {
|
||||
if (!isFinite(statusCode)) {
|
||||
statusCode = WEBSOCKET_CLOSE_GOING_AWAY;
|
||||
}
|
||||
waterfall(
|
||||
() => this._listener.onServerClose(this._context, statusCode, reason),
|
||||
() => this._listener.onStop(this._context, Cr.NS_BASE_STREAM_CLOSED)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an object that exposes the same interface as NetworkInfo, used
|
||||
* to simulate network status changes on Desktop. All methods returns empty
|
||||
* carrier data.
|
||||
*/
|
||||
function MockDesktopNetworkInfo() {}
|
||||
|
||||
MockDesktopNetworkInfo.prototype = {
|
||||
getNetworkInformation() {
|
||||
return {mcc: '', mnc: '', ip: ''};
|
||||
},
|
||||
|
||||
getNetworkState(callback) {
|
||||
callback({mcc: '', mnc: '', ip: '', netid: ''});
|
||||
},
|
||||
|
||||
getNetworkStateChangeEventName() {
|
||||
return 'network:offline-status-changed';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an object that exposes the same interface as NetworkInfo, used
|
||||
* to simulate network status changes on B2G.
|
||||
*
|
||||
* @param {String} [info.mcc] The mobile country code.
|
||||
* @param {String} [info.mnc] The mobile network code.
|
||||
* @param {String} [info.ip] The carrier IP address.
|
||||
* @param {String} [info.netid] The resolved network ID for UDP wake-up.
|
||||
*/
|
||||
function MockMobileNetworkInfo(info = {}) {
|
||||
this._info = info;
|
||||
}
|
||||
|
||||
MockMobileNetworkInfo.prototype = {
|
||||
_info: null,
|
||||
|
||||
getNetworkInformation() {
|
||||
let {mcc, mnc, ip} = this._info;
|
||||
return {mcc, mnc, ip};
|
||||
},
|
||||
|
||||
getNetworkState(callback) {
|
||||
let {mcc, mnc, ip, netid} = this._info;
|
||||
callback({mcc, mnc, ip, netid});
|
||||
},
|
||||
|
||||
getNetworkStateChangeEventName() {
|
||||
return 'network-active-changed';
|
||||
}
|
||||
};
|
127
dom/push/test/xpcshell/test_notification_ack.js
Normal file
127
dom/push/test/xpcshell/test_notification_ack.js
Normal file
@ -0,0 +1,127 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
let userAgentID = '5ab1d1df-7a3d-4024-a469-b9e1bb399fad';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({userAgentID});
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.org/1',
|
||||
'https://example.org/2',
|
||||
'https://example.org/3'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_notification_ack() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
let records = [{
|
||||
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
|
||||
pushEndpoint: 'https://example.com/update/1',
|
||||
scope: 'https://example.org/1',
|
||||
version: 1
|
||||
}, {
|
||||
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
|
||||
pushEndpoint: 'https://example.com/update/2',
|
||||
scope: 'https://example.org/2',
|
||||
version: 2
|
||||
}, {
|
||||
channelID: '5477bfda-22db-45d4-9614-fee369630260',
|
||||
pushEndpoint: 'https://example.com/update/3',
|
||||
scope: 'https://example.org/3',
|
||||
version: 3
|
||||
}];
|
||||
for (let record of records) {
|
||||
yield promiseDB.put(record);
|
||||
}
|
||||
|
||||
let notifyPromise = Promise.all([
|
||||
promiseObserverNotification('push-notification'),
|
||||
promiseObserverNotification('push-notification'),
|
||||
promiseObserverNotification('push-notification')
|
||||
]);
|
||||
|
||||
let acks = 0;
|
||||
let ackDefer = Promise.defer();
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
equal(request.uaid, userAgentID,
|
||||
'Should send matching device IDs in handshake');
|
||||
deepEqual(request.channelIDs.sort(), [
|
||||
'21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
|
||||
'5477bfda-22db-45d4-9614-fee369630260',
|
||||
'9a5ff87f-47c9-4215-b2b8-0bdd38b4b305'
|
||||
], 'Should send matching channel IDs in handshake');
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
uaid: userAgentID,
|
||||
status: 200
|
||||
}));
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'notification',
|
||||
updates: [{
|
||||
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
|
||||
version: 2
|
||||
}]
|
||||
}));
|
||||
},
|
||||
onACK(request) {
|
||||
equal(request.messageType, 'ack', 'Should send acknowledgements');
|
||||
let updates = request.updates;
|
||||
ok(Array.isArray(updates),
|
||||
'Should send an array of acknowledged updates');
|
||||
equal(updates.length, 1,
|
||||
'Should send one acknowledged update per packet');
|
||||
switch (++acks) {
|
||||
case 1:
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'notification',
|
||||
updates: [{
|
||||
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
|
||||
version: 4
|
||||
}, {
|
||||
channelID: '5477bfda-22db-45d4-9614-fee369630260',
|
||||
version: 6
|
||||
}]
|
||||
}));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
deepEqual([{
|
||||
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
|
||||
version: 4
|
||||
}], updates, 'Wrong updates for acknowledgement 2');
|
||||
break;
|
||||
|
||||
case 3:
|
||||
deepEqual([{
|
||||
channelID: '5477bfda-22db-45d4-9614-fee369630260',
|
||||
version: 6
|
||||
}], updates, 'Wrong updates for acknowledgement 3');
|
||||
ackDefer.resolve();
|
||||
break;
|
||||
|
||||
default:
|
||||
ok(false, 'Unexpected acknowledgement ' + acks);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield waitForPromise(notifyPromise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for notifications');
|
||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for multiple acknowledgements');
|
||||
});
|
82
dom/push/test/xpcshell/test_notification_duplicate.js
Normal file
82
dom/push/test/xpcshell/test_notification_duplicate.js
Normal file
@ -0,0 +1,82 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.com/1',
|
||||
'https://example.com/2'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Should acknowledge duplicate notifications, but not notify apps.
|
||||
add_task(function* test_notification_duplicate() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
let records = [{
|
||||
channelID: '8d2d9400-3597-4c5a-8a38-c546b0043bcc',
|
||||
pushEndpoint: 'https://example.org/update/1',
|
||||
scope: 'https://example.com/1',
|
||||
version: 2
|
||||
}, {
|
||||
channelID: '27d1e393-03ef-4c72-a5e6-9e890dfccad0',
|
||||
pushEndpoint: 'https://example.org/update/2',
|
||||
scope: 'https://example.com/2',
|
||||
version: 2
|
||||
}];
|
||||
for (let record of records) {
|
||||
yield promiseDB.put(record);
|
||||
}
|
||||
|
||||
let notifyPromise = promiseObserverNotification('push-notification');
|
||||
|
||||
let acks = 0;
|
||||
let ackDefer = Promise.defer();
|
||||
let ackDone = after(2, ackDefer.resolve);
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: '1500e7d9-8cbe-4ee6-98da-7fa5d6a39852'
|
||||
}));
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'notification',
|
||||
updates: [{
|
||||
channelID: '8d2d9400-3597-4c5a-8a38-c546b0043bcc',
|
||||
version: 2
|
||||
}, {
|
||||
channelID: '27d1e393-03ef-4c72-a5e6-9e890dfccad0',
|
||||
version: 3
|
||||
}]
|
||||
}));
|
||||
},
|
||||
onACK: ackDone
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield waitForPromise(notifyPromise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for notifications');
|
||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for stale acknowledgement');
|
||||
|
||||
let staleRecord = yield promiseDB.getByChannelID(
|
||||
'8d2d9400-3597-4c5a-8a38-c546b0043bcc');
|
||||
strictEqual(staleRecord.version, 2, 'Wrong stale record version');
|
||||
|
||||
let updatedRecord = yield promiseDB.getByChannelID(
|
||||
'27d1e393-03ef-4c72-a5e6-9e890dfccad0');
|
||||
strictEqual(updatedRecord.version, 3, 'Wrong updated record version');
|
||||
});
|
127
dom/push/test/xpcshell/test_notification_error.js
Normal file
127
dom/push/test/xpcshell/test_notification_error.js
Normal file
@ -0,0 +1,127 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.com/a',
|
||||
'https://example.com/b',
|
||||
'https://example.com/c'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_notification_error() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
let records = [{
|
||||
channelID: 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
||||
pushEndpoint: 'https://example.org/update/success-1',
|
||||
scope: 'https://example.com/a',
|
||||
version: 1
|
||||
}, {
|
||||
channelID: '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
||||
pushEndpoint: 'https://example.org/update/error',
|
||||
scope: 'https://example.com/b',
|
||||
version: 2
|
||||
}, {
|
||||
channelID: 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
||||
pushEndpoint: 'https://example.org/update/success-2',
|
||||
scope: 'https://example.com/c',
|
||||
version: 3
|
||||
}];
|
||||
for (let record of records) {
|
||||
yield promiseDB.put(record);
|
||||
}
|
||||
|
||||
let notifyPromise = Promise.all([
|
||||
promiseObserverNotification(
|
||||
'push-notification',
|
||||
(subject, data) => data == 'https://example.com/a'
|
||||
),
|
||||
promiseObserverNotification(
|
||||
'push-notification',
|
||||
(subject, data) => data == 'https://example.com/c'
|
||||
)
|
||||
]);
|
||||
|
||||
let ackDefer = Promise.defer();
|
||||
let ackDone = after(records.length, ackDefer.resolve);
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db: makeStub(db, {
|
||||
getByChannelID(prev, channelID, successCb, failureCb) {
|
||||
if (channelID == '3c3930ba-44de-40dc-a7ca-8a133ec1a866') {
|
||||
return failureCb('splines not reticulated');
|
||||
}
|
||||
return prev.call(this, channelID, successCb, failureCb);
|
||||
}
|
||||
}),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
deepEqual(request.channelIDs.sort(), [
|
||||
'3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
||||
'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
||||
'f04f1e46-9139-4826-b2d1-9411b0821283'
|
||||
], 'Wrong channel list');
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: '3c7462fc-270f-45be-a459-b9d631b0d093'
|
||||
}));
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'notification',
|
||||
updates: records.map(({channelID, version}) =>
|
||||
({channelID, version: ++version}))
|
||||
}));
|
||||
},
|
||||
// Should acknowledge all received updates, even if updating
|
||||
// IndexedDB fails.
|
||||
onACK: ackDone
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let [a, c] = yield waitForPromise(
|
||||
notifyPromise,
|
||||
DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for notifications'
|
||||
);
|
||||
let aPush = a.subject.QueryInterface(Ci.nsIPushObserverNotification);
|
||||
equal(aPush.pushEndpoint, 'https://example.org/update/success-1',
|
||||
'Wrong endpoint for notification A');
|
||||
equal(aPush.version, 2, 'Wrong version for notification A');
|
||||
|
||||
let cPush = c.subject.QueryInterface(Ci.nsIPushObserverNotification);
|
||||
equal(cPush.pushEndpoint, 'https://example.org/update/success-2',
|
||||
'Wrong endpoint for notification C');
|
||||
equal(cPush.version, 4, 'Wrong version for notification C');
|
||||
|
||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for acknowledgements');
|
||||
|
||||
let aRecord = yield promiseDB.getByScope('https://example.com/a');
|
||||
equal(aRecord.channelID, 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
||||
'Wrong channel ID for record A');
|
||||
strictEqual(aRecord.version, 2,
|
||||
'Should return the new version for record A');
|
||||
|
||||
let bRecord = yield promiseDB.getByScope('https://example.com/b');
|
||||
equal(bRecord.channelID, '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
||||
'Wrong channel ID for record B');
|
||||
strictEqual(bRecord.version, 2,
|
||||
'Should return the previous version for record B');
|
||||
|
||||
let cRecord = yield promiseDB.getByScope('https://example.com/c');
|
||||
equal(cRecord.channelID, 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
||||
'Wrong channel ID for record C');
|
||||
strictEqual(cRecord.version, 4,
|
||||
'Should return the new version for record C');
|
||||
});
|
109
dom/push/test/xpcshell/test_notification_incomplete.js
Normal file
109
dom/push/test/xpcshell/test_notification_incomplete.js
Normal file
@ -0,0 +1,109 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.com/page/1',
|
||||
'https://example.com/page/2',
|
||||
'https://example.com/page/3',
|
||||
'https://example.com/page/4'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_notification_incomplete() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
let records = [{
|
||||
channelID: '123',
|
||||
pushEndpoint: 'https://example.org/update/1',
|
||||
scope: 'https://example.com/page/1',
|
||||
version: 1
|
||||
}, {
|
||||
channelID: '3ad1ed95-d37a-4d88-950f-22cbe2e240d7',
|
||||
pushEndpoint: 'https://example.org/update/2',
|
||||
scope: 'https://example.com/page/2',
|
||||
version: 1
|
||||
}, {
|
||||
channelID: 'd239498b-1c85-4486-b99b-205866e82d1f',
|
||||
pushEndpoint: 'https://example.org/update/3',
|
||||
scope: 'https://example.com/page/3',
|
||||
version: 3
|
||||
}, {
|
||||
channelID: 'a50de97d-b496-43ce-8b53-05522feb78db',
|
||||
pushEndpoint: 'https://example.org/update/4',
|
||||
scope: 'https://example.com/page/4',
|
||||
version: 10
|
||||
}];
|
||||
for (let record of records) {
|
||||
promiseDB.put(record);
|
||||
}
|
||||
|
||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
||||
ok(false, 'Should not deliver malformed updates');
|
||||
}, 'push-notification', false);
|
||||
|
||||
let notificationDefer = Promise.defer();
|
||||
let notificationDone = after(2, notificationDefer.resolve);
|
||||
let prevHandler = PushService._handleNotificationReply;
|
||||
PushService._handleNotificationReply = function _handleNotificationReply() {
|
||||
notificationDone();
|
||||
return prevHandler.apply(this, arguments);
|
||||
};
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: '1ca1cf66-eeb4-4df7-87c1-d5c92906ab90'
|
||||
}));
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
// Missing "updates" field; should ignore message.
|
||||
messageType: 'notification'
|
||||
}));
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'notification',
|
||||
updates: [{
|
||||
// Wrong channel ID field type.
|
||||
channelID: 123,
|
||||
version: 3
|
||||
}, {
|
||||
// Missing version field.
|
||||
channelID: '3ad1ed95-d37a-4d88-950f-22cbe2e240d7'
|
||||
}, {
|
||||
// Wrong version field type.
|
||||
channelID: 'd239498b-1c85-4486-b99b-205866e82d1f',
|
||||
version: true
|
||||
}, {
|
||||
// Negative versions should be ignored.
|
||||
channelID: 'a50de97d-b496-43ce-8b53-05522feb78db',
|
||||
version: -5
|
||||
}]
|
||||
}));
|
||||
},
|
||||
onACK() {
|
||||
ok(false, 'Should not acknowledge malformed updates');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield waitForPromise(notificationDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for incomplete notifications');
|
||||
|
||||
let storeRecords = yield promiseDB.getAllChannelIDs();
|
||||
storeRecords.sort(({pushEndpoint: a}, {pushEndpoint: b}) =>
|
||||
compareAscending(a, b));
|
||||
deepEqual(records, storeRecords, 'Should not update malformed records');
|
||||
});
|
72
dom/push/test/xpcshell/test_notification_version_string.js
Normal file
72
dom/push/test/xpcshell/test_notification_version_string.js
Normal file
@ -0,0 +1,72 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.net/case'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_notification_version_string() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
yield promiseDB.put({
|
||||
channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
|
||||
pushEndpoint: 'https://example.org/updates/1',
|
||||
scope: 'https://example.com/page/1',
|
||||
version: 2
|
||||
});
|
||||
|
||||
let notifyPromise = promiseObserverNotification('push-notification');
|
||||
|
||||
let ackDefer = Promise.defer();
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: 'ba31ac13-88d4-4984-8e6b-8731315a7cf8'
|
||||
}));
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'notification',
|
||||
updates: [{
|
||||
channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
|
||||
version: '4'
|
||||
}]
|
||||
}));
|
||||
},
|
||||
onACK: ackDefer.resolve
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let {subject: notification, data: scope} = yield waitForPromise(
|
||||
notifyPromise,
|
||||
DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for string notification'
|
||||
);
|
||||
let message = notification.QueryInterface(Ci.nsIPushObserverNotification);
|
||||
equal(scope, 'https://example.com/page/1', 'Wrong scope');
|
||||
equal(message.pushEndpoint, 'https://example.org/updates/1',
|
||||
'Wrong push endpoint');
|
||||
strictEqual(message.version, 4, 'Wrong version');
|
||||
|
||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for string acknowledgement');
|
||||
|
||||
let storeRecord = yield promiseDB.getByChannelID(
|
||||
'6ff97d56-d0c0-43bc-8f5b-61b855e1d93b');
|
||||
strictEqual(storeRecord.version, 4, 'Wrong record version');
|
||||
});
|
64
dom/push/test/xpcshell/test_register_case.js
Normal file
64
dom/push/test/xpcshell/test_register_case.js
Normal file
@ -0,0 +1,64 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = '1760b1f5-c3ba-40e3-9344-adef7c18ab12';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.net/case'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_case() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'HELLO',
|
||||
uaid: userAgentID,
|
||||
status: 200
|
||||
}));
|
||||
},
|
||||
onRegister(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'ReGiStEr',
|
||||
uaid: userAgentID,
|
||||
channelID: request.channelID,
|
||||
status: 200,
|
||||
pushEndpoint: 'https://example.com/update/case'
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let newRecord = yield waitForPromise(
|
||||
PushNotificationService.register('https://example.net/case'),
|
||||
DEFAULT_TIMEOUT,
|
||||
'Mixed-case register response timed out'
|
||||
);
|
||||
equal(newRecord.pushEndpoint, 'https://example.com/update/case',
|
||||
'Wrong push endpoint in registration record');
|
||||
equal(newRecord.scope, 'https://example.net/case',
|
||||
'Wrong scope in registration record');
|
||||
|
||||
let record = yield promiseDB.getByChannelID(newRecord.channelID);
|
||||
equal(record.pushEndpoint, 'https://example.com/update/case',
|
||||
'Wrong push endpoint in database record');
|
||||
equal(record.scope, 'https://example.net/case',
|
||||
'Wrong scope in database record');
|
||||
});
|
103
dom/push/test/xpcshell/test_register_flush.js
Normal file
103
dom/push/test/xpcshell/test_register_flush.js
Normal file
@ -0,0 +1,103 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = '9ce1e6d3-7bdb-4fe9-90a5-def1d64716f1';
|
||||
const channelID = 'c26892c5-6e08-4c16-9f0c-0044697b4d85';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
userAgentID,
|
||||
requestTimeout: 1000,
|
||||
retryBaseInterval: 150
|
||||
});
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.com/page/1',
|
||||
'https://example.com/page/2'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_flush() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
let record = {
|
||||
channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
|
||||
pushEndpoint: 'https://example.org/update/1',
|
||||
scope: 'https://example.com/page/1',
|
||||
version: 2
|
||||
};
|
||||
yield promiseDB.put(record);
|
||||
|
||||
let notifyPromise = promiseObserverNotification('push-notification');
|
||||
|
||||
let ackDefer = Promise.defer();
|
||||
let ackDone = after(2, ackDefer.resolve);
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID
|
||||
}));
|
||||
},
|
||||
onRegister(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'notification',
|
||||
updates: [{
|
||||
channelID: request.channelID,
|
||||
version: 2
|
||||
}, {
|
||||
channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
|
||||
version: 3
|
||||
}]
|
||||
}));
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'register',
|
||||
status: 200,
|
||||
channelID: request.channelID,
|
||||
uaid: userAgentID,
|
||||
pushEndpoint: 'https://example.org/update/2'
|
||||
}));
|
||||
},
|
||||
onACK: ackDone
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let newRecord = yield PushNotificationService.register(
|
||||
'https://example.com/page/2'
|
||||
);
|
||||
equal(newRecord.pushEndpoint, 'https://example.org/update/2',
|
||||
'Wrong push endpoint in record');
|
||||
equal(newRecord.scope, 'https://example.com/page/2',
|
||||
'Wrong scope in record');
|
||||
|
||||
let {data: scope} = yield waitForPromise(notifyPromise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for notification');
|
||||
equal(scope, 'https://example.com/page/1', 'Wrong notification scope');
|
||||
|
||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for acknowledgements');
|
||||
|
||||
let prevRecord = yield promiseDB.getByChannelID(
|
||||
'9bcc7efb-86c7-4457-93ea-e24e6eb59b74');
|
||||
equal(prevRecord.pushEndpoint, 'https://example.org/update/1',
|
||||
'Wrong existing push endpoint');
|
||||
strictEqual(prevRecord.version, 3,
|
||||
'Should record version updates sent before register responses');
|
||||
|
||||
let registeredRecord = yield promiseDB.getByChannelID(newRecord.channelID);
|
||||
equal(registeredRecord.pushEndpoint, 'https://example.org/update/2',
|
||||
'Wrong new push endpoint');
|
||||
ok(!registeredRecord.version, 'Should not record premature updates');
|
||||
});
|
60
dom/push/test/xpcshell/test_register_invalid_channel.js
Normal file
60
dom/push/test/xpcshell/test_register_invalid_channel.js
Normal file
@ -0,0 +1,60 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = '52b2b04c-b6cc-42c6-abdf-bef9cbdbea00';
|
||||
const channelID = 'cafed00d';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.com/invalid-channel'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_invalid_channel() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
uaid: userAgentID,
|
||||
status: 200
|
||||
}));
|
||||
},
|
||||
onRegister(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'register',
|
||||
status: 403,
|
||||
channelID,
|
||||
error: 'Invalid channel ID'
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield rejects(
|
||||
PushNotificationService.register('https://example.com/invalid-channel'),
|
||||
function(error) {
|
||||
return error == 'Invalid channel ID';
|
||||
},
|
||||
'Wrong error for invalid channel ID'
|
||||
);
|
||||
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
ok(!record, 'Should not store records for error responses');
|
||||
});
|
62
dom/push/test/xpcshell/test_register_invalid_endpoint.js
Normal file
62
dom/push/test/xpcshell/test_register_invalid_endpoint.js
Normal file
@ -0,0 +1,62 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = 'c9a12e81-ea5e-40f9-8bf4-acee34621671';
|
||||
const channelID = 'c0660af8-b532-4931-81f0-9fd27a12d6ab';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.net/page/invalid-endpoint'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_invalid_endpoint() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID,
|
||||
}));
|
||||
},
|
||||
onRegister(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'register',
|
||||
status: 200,
|
||||
channelID,
|
||||
uaid: userAgentID,
|
||||
pushEndpoint: '!@#$%^&*'
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield rejects(
|
||||
PushNotificationService.register(
|
||||
'https://example.net/page/invalid-endpoint'),
|
||||
function(error) {
|
||||
return error && error.contains('Invalid pushEndpoint');
|
||||
},
|
||||
'Wrong error for invalid endpoint'
|
||||
);
|
||||
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
ok(!record, 'Should not store records with invalid endpoints');
|
||||
});
|
61
dom/push/test/xpcshell/test_register_invalid_json.js
Normal file
61
dom/push/test/xpcshell/test_register_invalid_json.js
Normal file
@ -0,0 +1,61 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = '8271186b-8073-43a3-adf6-225bd44a8b0a';
|
||||
const channelID = '2d08571e-feab-48a0-9f05-8254c3c7e61f';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
requestTimeout: 1000,
|
||||
retryBaseInterval: 150
|
||||
});
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.net/page/invalid-json'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_invalid_json() {
|
||||
let helloDefer = Promise.defer();
|
||||
let helloDone = after(2, helloDefer.resolve);
|
||||
let registers = 0;
|
||||
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID
|
||||
}));
|
||||
helloDone();
|
||||
},
|
||||
onRegister(request) {
|
||||
equal(request.channelID, channelID, 'Register: wrong channel ID');
|
||||
this.serverSendMsg(');alert(1);(');
|
||||
registers++;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield rejects(
|
||||
PushNotificationService.register('https://example.net/page/invalid-json'),
|
||||
function(error) {
|
||||
return error == 'TimeoutError';
|
||||
},
|
||||
'Wrong error for invalid JSON response'
|
||||
);
|
||||
|
||||
yield waitForPromise(helloDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Reconnect after invalid JSON response timed out');
|
||||
equal(registers, 1, 'Wrong register count');
|
||||
});
|
65
dom/push/test/xpcshell/test_register_no_id.js
Normal file
65
dom/push/test/xpcshell/test_register_no_id.js
Normal file
@ -0,0 +1,65 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
let userAgentID = '9a2f9efe-2ebb-4bcb-a5d9-9e2b73d30afe';
|
||||
let channelID = '264c2ba0-f6db-4e84-acdb-bd225b62d9e3';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
userAgentID,
|
||||
requestTimeout: 1000,
|
||||
retryBaseInterval: 150
|
||||
});
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.com/incomplete'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_no_id() {
|
||||
let registers = 0;
|
||||
let helloDefer = Promise.defer();
|
||||
let helloDone = after(2, helloDefer.resolve);
|
||||
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID
|
||||
}));
|
||||
helloDone();
|
||||
},
|
||||
onRegister(request) {
|
||||
registers++;
|
||||
equal(request.channelID, channelID, 'Register: wrong channel ID');
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'register',
|
||||
status: 200
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield rejects(
|
||||
PushNotificationService.register('https://example.com/incomplete'),
|
||||
function(error) {
|
||||
return error == 'TimeoutError';
|
||||
},
|
||||
'Wrong error for incomplete register response'
|
||||
);
|
||||
|
||||
yield waitForPromise(helloDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Reconnect after incomplete register response timed out');
|
||||
equal(registers, 1, 'Wrong register count');
|
||||
});
|
65
dom/push/test/xpcshell/test_register_request_queue.js
Normal file
65
dom/push/test/xpcshell/test_register_request_queue.js
Normal file
@ -0,0 +1,65 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
requestTimeout: 1000,
|
||||
retryBaseInterval: 150
|
||||
});
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.com/page/1'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_request_queue() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
|
||||
let helloDefer = Promise.defer();
|
||||
let onHello = after(2, function onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: '54b08a9e-59c6-4ed7-bb54-f4fd60d6f606'
|
||||
}));
|
||||
helloDefer.resolve();
|
||||
});
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello,
|
||||
onRegister() {
|
||||
ok(false, 'Should cancel timed-out requests');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let firstRegister = PushNotificationService.register(
|
||||
'https://example.com/page/1'
|
||||
);
|
||||
let secondRegister = PushNotificationService.register(
|
||||
'https://example.com/page/1'
|
||||
);
|
||||
|
||||
yield waitForPromise(Promise.all([
|
||||
rejects(firstRegister, function(error) {
|
||||
return error == 'TimeoutError';
|
||||
}, 'Should time out the first request'),
|
||||
rejects(secondRegister, function(error) {
|
||||
return error == 'TimeoutError';
|
||||
}, 'Should time out the second request')
|
||||
]), DEFAULT_TIMEOUT, 'Queued requests did not time out');
|
||||
|
||||
yield waitForPromise(helloDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for reconnect');
|
||||
});
|
88
dom/push/test/xpcshell/test_register_rollback.js
Normal file
88
dom/push/test/xpcshell/test_register_rollback.js
Normal file
@ -0,0 +1,88 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = 'b2546987-4f63-49b1-99f7-739cd3c40e44';
|
||||
const channelID = '35a820f7-d7dd-43b3-af21-d65352212ae3';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
userAgentID,
|
||||
requestTimeout: 1000,
|
||||
retryBaseInterval: 150
|
||||
});
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.com/storage-error'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_rollback() {
|
||||
let db = new PushDB();
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
|
||||
let handshakes = 0;
|
||||
let registers = 0;
|
||||
let unregisterDefer = Promise.defer();
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db: makeStub(db, {
|
||||
put(prev, record, successCb, failureCb) {
|
||||
failureCb('universe has imploded');
|
||||
}
|
||||
}),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
handshakes++;
|
||||
equal(request.uaid, userAgentID, 'Handshake: wrong device ID');
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID
|
||||
}));
|
||||
},
|
||||
onRegister(request) {
|
||||
equal(request.channelID, channelID, 'Register: wrong channel ID');
|
||||
registers++;
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'register',
|
||||
status: 200,
|
||||
uaid: userAgentID,
|
||||
channelID,
|
||||
pushEndpoint: 'https://example.com/update/rollback'
|
||||
}));
|
||||
},
|
||||
onUnregister(request) {
|
||||
equal(request.channelID, channelID, 'Unregister: wrong channel ID');
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'unregister',
|
||||
status: 200,
|
||||
channelID
|
||||
}));
|
||||
unregisterDefer.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Should return a rejected promise if storage fails.
|
||||
yield rejects(
|
||||
PushNotificationService.register('https://example.com/storage-error'),
|
||||
function(error) {
|
||||
return error == 'universe has imploded';
|
||||
},
|
||||
'Wrong error for unregister database failure'
|
||||
);
|
||||
|
||||
// Should send an out-of-band unregister request.
|
||||
yield waitForPromise(unregisterDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Unregister request timed out');
|
||||
equal(handshakes, 1, 'Wrong handshake count');
|
||||
equal(registers, 1, 'Wrong register count');
|
||||
});
|
76
dom/push/test/xpcshell/test_register_success.js
Normal file
76
dom/push/test/xpcshell/test_register_success.js
Normal file
@ -0,0 +1,76 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = 'bd744428-f125-436a-b6d0-dd0c9845837f';
|
||||
const channelID = '0ef2ad4a-6c49-41ad-af6e-95d2425276bf';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
userAgentID,
|
||||
requestTimeout: 1000,
|
||||
retryBaseInterval: 150
|
||||
});
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.org/1'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_success() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(data) {
|
||||
equal(data.messageType, 'hello', 'Handshake: wrong message type');
|
||||
equal(data.uaid, userAgentID, 'Handshake: wrong device ID');
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID
|
||||
}));
|
||||
},
|
||||
onRegister(data) {
|
||||
equal(data.messageType, 'register', 'Register: wrong message type');
|
||||
equal(data.channelID, channelID, 'Register: wrong channel ID');
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'register',
|
||||
status: 200,
|
||||
channelID: channelID,
|
||||
uaid: userAgentID,
|
||||
pushEndpoint: 'https://example.com/update/1',
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let newRecord = yield PushNotificationService.register(
|
||||
'https://example.org/1'
|
||||
);
|
||||
equal(newRecord.channelID, channelID,
|
||||
'Wrong channel ID in registration record');
|
||||
equal(newRecord.pushEndpoint, 'https://example.com/update/1',
|
||||
'Wrong push endpoint in registration record');
|
||||
equal(newRecord.scope, 'https://example.org/1',
|
||||
'Wrong scope in registration record');
|
||||
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
equal(record.channelID, channelID,
|
||||
'Wrong channel ID in database record');
|
||||
equal(record.pushEndpoint, 'https://example.com/update/1',
|
||||
'Wrong push endpoint in database record');
|
||||
equal(record.scope, 'https://example.org/1',
|
||||
'Wrong scope in database record');
|
||||
});
|
102
dom/push/test/xpcshell/test_register_timeout.js
Normal file
102
dom/push/test/xpcshell/test_register_timeout.js
Normal file
@ -0,0 +1,102 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = 'a4be0df9-b16d-4b5f-8f58-0f93b6f1e23d';
|
||||
const channelID = 'e1944e0b-48df-45e7-bdc0-d1fbaa7986d3';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
requestTimeout: 1000,
|
||||
retryBaseInterval: 150
|
||||
});
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.net/page/timeout'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_timeout() {
|
||||
let handshakes = 0;
|
||||
let timeoutDefer = Promise.defer();
|
||||
let registers = 0;
|
||||
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
|
||||
PushService._generateID = () => channelID;
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
switch (handshakes) {
|
||||
case 0:
|
||||
equal(request.uaid, null, 'Should not include device ID');
|
||||
deepEqual(request.channelIDs, [],
|
||||
'Should include empty channel list');
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Should use the previously-issued device ID when reconnecting,
|
||||
// but should not include the timed-out channel ID.
|
||||
equal(request.uaid, userAgentID,
|
||||
'Should include device ID on reconnect');
|
||||
deepEqual(request.channelIDs, [],
|
||||
'Should not include failed channel ID');
|
||||
break;
|
||||
|
||||
default:
|
||||
ok(false, 'Unexpected reconnect attempt ' + handshakes);
|
||||
}
|
||||
handshakes++;
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID,
|
||||
}));
|
||||
},
|
||||
onRegister(request) {
|
||||
equal(request.channelID, channelID,
|
||||
'Wrong channel ID in register request');
|
||||
setTimeout(() => {
|
||||
// Should ignore replies for timed-out requests.
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'register',
|
||||
status: 200,
|
||||
channelID: channelID,
|
||||
uaid: userAgentID,
|
||||
pushEndpoint: 'https://example.com/update/timeout',
|
||||
}));
|
||||
timeoutDefer.resolve();
|
||||
}, 2000);
|
||||
registers++;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield rejects(
|
||||
PushNotificationService.register('https://example.net/page/timeout'),
|
||||
function(error) {
|
||||
return error == 'TimeoutError';
|
||||
},
|
||||
'Wrong error for request timeout'
|
||||
);
|
||||
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
ok(!record, 'Should not store records for timed-out responses');
|
||||
|
||||
yield waitForPromise(
|
||||
timeoutDefer.promise,
|
||||
DEFAULT_TIMEOUT,
|
||||
'Reconnect timed out'
|
||||
);
|
||||
equal(registers, 1, 'Should not handle timed-out register requests');
|
||||
});
|
71
dom/push/test/xpcshell/test_register_wrong_id.js
Normal file
71
dom/push/test/xpcshell/test_register_wrong_id.js
Normal file
@ -0,0 +1,71 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = '84afc774-6995-40d1-9c90-8c34ddcd0cb4';
|
||||
const clientChannelID = '4b42a681c99e4dfbbb166a7e01a09b8b';
|
||||
const serverChannelID = '3f5aeb89c6e8405a9569619522783436';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
userAgentID,
|
||||
requestTimeout: 1000,
|
||||
retryBaseInterval: 150
|
||||
});
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.com/mismatched'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_wrong_id() {
|
||||
// Should reconnect after the register request times out.
|
||||
let registers = 0;
|
||||
let helloDefer = Promise.defer();
|
||||
let helloDone = after(2, helloDefer.resolve);
|
||||
|
||||
PushService._generateID = () => clientChannelID;
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID
|
||||
}));
|
||||
helloDone();
|
||||
},
|
||||
onRegister(request) {
|
||||
equal(request.channelID, clientChannelID,
|
||||
'Register: wrong channel ID');
|
||||
registers++;
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'register',
|
||||
status: 200,
|
||||
// Reply with a different channel ID. Since the ID is used as a
|
||||
// nonce, the registration request will time out.
|
||||
channelID: serverChannelID
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield rejects(
|
||||
PushNotificationService.register('https://example.com/mismatched'),
|
||||
function(error) {
|
||||
return error == 'TimeoutError';
|
||||
},
|
||||
'Wrong error for mismatched register reply'
|
||||
);
|
||||
|
||||
yield waitForPromise(helloDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Reconnect after mismatched register reply timed out');
|
||||
equal(registers, 1, 'Wrong register count');
|
||||
});
|
67
dom/push/test/xpcshell/test_register_wrong_type.js
Normal file
67
dom/push/test/xpcshell/test_register_wrong_type.js
Normal file
@ -0,0 +1,67 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = 'c293fdc5-a75e-4eb1-af88-a203991c0787';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
requestTimeout: 1000,
|
||||
retryBaseInterval: 150
|
||||
});
|
||||
disableServiceWorkerEvents(
|
||||
'https://example.com/mistyped'
|
||||
);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_register_wrong_type() {
|
||||
let registers = 0;
|
||||
let helloDefer = Promise.defer();
|
||||
let helloDone = after(2, helloDefer.resolve);
|
||||
|
||||
PushService._generateID = () => '1234';
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID
|
||||
}));
|
||||
helloDone();
|
||||
},
|
||||
onRegister(request) {
|
||||
registers++;
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'register',
|
||||
status: 200,
|
||||
channelID: 1234,
|
||||
uaid: userAgentID,
|
||||
pushEndpoint: 'https://example.org/update/wrong-type'
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let promise =
|
||||
|
||||
yield rejects(
|
||||
PushNotificationService.register('https://example.com/mistyped'),
|
||||
function(error) {
|
||||
return error == 'TimeoutError';
|
||||
},
|
||||
'Wrong error for non-string channel ID'
|
||||
);
|
||||
|
||||
yield waitForPromise(helloDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Reconnect after sending non-string channel ID timed out');
|
||||
equal(registers, 1, 'Wrong register count');
|
||||
});
|
39
dom/push/test/xpcshell/test_registration_error.js
Normal file
39
dom/push/test/xpcshell/test_registration_error.js
Normal file
@ -0,0 +1,39 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
userAgentID: '6faed1f0-1439-4aac-a978-db21c81cd5eb'
|
||||
});
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_registrations_error() {
|
||||
let db = new PushDB();
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db: makeStub(db, {
|
||||
getByScope(prev, scope, successCb, failureCb) {
|
||||
failureCb('oops');
|
||||
}
|
||||
}),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri);
|
||||
}
|
||||
});
|
||||
|
||||
yield rejects(
|
||||
PushNotificationService.registration('https://example.net/1'),
|
||||
function(error) {
|
||||
return error == 'Database error';
|
||||
},
|
||||
'Wrong message'
|
||||
);
|
||||
});
|
28
dom/push/test/xpcshell/test_registration_missing_scope.js
Normal file
28
dom/push/test/xpcshell/test_registration_missing_scope.js
Normal file
@ -0,0 +1,28 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_registration_missing_scope() {
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri);
|
||||
}
|
||||
});
|
||||
yield rejects(
|
||||
PushNotificationService.registration(''),
|
||||
function(error) {
|
||||
return error == 'Database error';
|
||||
},
|
||||
'Record missing page and manifest URLs'
|
||||
);
|
||||
});
|
28
dom/push/test/xpcshell/test_registration_none.js
Normal file
28
dom/push/test/xpcshell/test_registration_none.js
Normal file
@ -0,0 +1,28 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = 'a722e448-c481-4c48-aea0-fc411cb7c9ed';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({userAgentID});
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Should not open a connection if the client has no registrations.
|
||||
add_task(function* test_registration_none() {
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri);
|
||||
}
|
||||
});
|
||||
|
||||
let registration = yield PushNotificationService.registration(
|
||||
'https://example.net/1');
|
||||
ok(!registration, 'Should not open a connection without registration');
|
||||
});
|
67
dom/push/test/xpcshell/test_registration_success.js
Normal file
67
dom/push/test/xpcshell/test_registration_success.js
Normal file
@ -0,0 +1,67 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = '997ee7ba-36b1-4526-ae9e-2d3f38d6efe8';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({userAgentID});
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_registration_success() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
let records = [{
|
||||
channelID: 'bf001fe0-2684-42f2-bc4d-a3e14b11dd5b',
|
||||
pushEndpoint: 'https://example.com/update/same-manifest/1',
|
||||
scope: 'https://example.net/a',
|
||||
version: 5
|
||||
}, {
|
||||
channelID: 'f6edfbcd-79d6-49b8-9766-48b9dcfeff0f',
|
||||
pushEndpoint: 'https://example.com/update/same-manifest/2',
|
||||
scope: 'https://example.net/b',
|
||||
version: 10
|
||||
}, {
|
||||
channelID: 'b1cf38c9-6836-4d29-8a30-a3e98d59b728',
|
||||
pushEndpoint: 'https://example.org/update/different-manifest',
|
||||
scope: 'https://example.org/c',
|
||||
version: 15
|
||||
}];
|
||||
for (let record of records) {
|
||||
yield promiseDB.put(record);
|
||||
}
|
||||
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
equal(request.uaid, userAgentID, 'Wrong device ID in handshake');
|
||||
deepEqual(request.channelIDs.sort(), [
|
||||
'b1cf38c9-6836-4d29-8a30-a3e98d59b728',
|
||||
'bf001fe0-2684-42f2-bc4d-a3e14b11dd5b',
|
||||
'f6edfbcd-79d6-49b8-9766-48b9dcfeff0f',
|
||||
], 'Wrong channel list in handshake');
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let registration = yield PushNotificationService.registration(
|
||||
'https://example.net/a');
|
||||
deepEqual(registration, {
|
||||
pushEndpoint: 'https://example.com/update/same-manifest/1',
|
||||
version: 5
|
||||
}, 'Should include registrations for all pages with this manifest');
|
||||
});
|
37
dom/push/test/xpcshell/test_unregister_empty_scope.js
Normal file
37
dom/push/test/xpcshell/test_unregister_empty_scope.js
Normal file
@ -0,0 +1,37 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_unregister_empty_scope() {
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: '5619557c-86fe-4711-8078-d1fd6987aef7'
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield rejects(
|
||||
PushNotificationService.unregister(''),
|
||||
function(error) {
|
||||
return error == 'NotFoundError';
|
||||
},
|
||||
'Wrong error for empty endpoint'
|
||||
);
|
||||
});
|
65
dom/push/test/xpcshell/test_unregister_error.js
Normal file
65
dom/push/test/xpcshell/test_unregister_error.js
Normal file
@ -0,0 +1,65 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const channelID = '00c7fa13-7b71-447d-bd27-a91abc09d1b2';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_unregister_error() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
yield promiseDB.put({
|
||||
channelID: channelID,
|
||||
pushEndpoint: 'https://example.org/update/failure',
|
||||
scope: 'https://example.net/page/failure',
|
||||
version: 1
|
||||
});
|
||||
|
||||
let unregisterDefer = Promise.defer();
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: '083e6c17-1063-4677-8638-ab705aebebc2'
|
||||
}));
|
||||
},
|
||||
onUnregister(request) {
|
||||
// The server is notified out-of-band. Since channels may be pruned,
|
||||
// any failures are swallowed.
|
||||
equal(request.channelID, channelID, 'Unregister: wrong channel ID');
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'unregister',
|
||||
status: 500,
|
||||
error: 'omg, everything is exploding',
|
||||
channelID
|
||||
}));
|
||||
unregisterDefer.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield PushNotificationService.unregister(
|
||||
'https://example.net/page/failure');
|
||||
|
||||
let result = yield promiseDB.getByChannelID(channelID);
|
||||
ok(!result, 'Deleted push record exists');
|
||||
|
||||
// Make sure we send a request to the server.
|
||||
yield waitForPromise(unregisterDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for unregister');
|
||||
});
|
78
dom/push/test/xpcshell/test_unregister_invalid_json.js
Normal file
78
dom/push/test/xpcshell/test_unregister_invalid_json.js
Normal file
@ -0,0 +1,78 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const userAgentID = '7f0af1bb-7e1f-4fb8-8e4a-e8de434abde3';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs({
|
||||
userAgentID,
|
||||
requestTimeout: 150,
|
||||
retryBaseInterval: 150
|
||||
});
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_unregister_invalid_json() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
let records = [{
|
||||
channelID: '87902e90-c57e-4d18-8354-013f4a556559',
|
||||
pushEndpoint: 'https://example.org/update/1',
|
||||
scope: 'https://example.edu/page/1',
|
||||
version: 1
|
||||
}, {
|
||||
channelID: '057caa8f-9b99-47ff-891c-adad18ce603e',
|
||||
pushEndpoint: 'https://example.com/update/2',
|
||||
scope: 'https://example.net/page/1',
|
||||
version: 1
|
||||
}];
|
||||
for (let record of records) {
|
||||
yield promiseDB.put(record);
|
||||
}
|
||||
|
||||
let unregisterDefer = Promise.defer();
|
||||
let unregisterDone = after(2, unregisterDefer.resolve);
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: userAgentID
|
||||
}));
|
||||
},
|
||||
onUnregister(request) {
|
||||
this.serverSendMsg(');alert(1);(');
|
||||
unregisterDone();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// "unregister" is fire-and-forget: it's sent via _send(), not
|
||||
// _sendRequest().
|
||||
yield PushNotificationService.unregister(
|
||||
'https://example.edu/page/1');
|
||||
let record = yield promiseDB.getByChannelID(
|
||||
'87902e90-c57e-4d18-8354-013f4a556559');
|
||||
ok(!record, 'Failed to delete unregistered record');
|
||||
|
||||
yield PushNotificationService.unregister(
|
||||
'https://example.net/page/1');
|
||||
record = yield promiseDB.getByChannelID(
|
||||
'057caa8f-9b99-47ff-891c-adad18ce603e');
|
||||
ok(!record,
|
||||
'Failed to delete unregistered record after receiving invalid JSON');
|
||||
|
||||
yield waitForPromise(unregisterDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for unregister');
|
||||
});
|
35
dom/push/test/xpcshell/test_unregister_not_found.js
Normal file
35
dom/push/test/xpcshell/test_unregister_not_found.js
Normal file
@ -0,0 +1,35 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_unregister_not_found() {
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: 'f074ed80-d479-44fa-ba65-792104a79ea9'
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let promise = PushNotificationService.unregister(
|
||||
'https://example.net/nonexistent');
|
||||
yield rejects(promise, function(error) {
|
||||
return error == 'NotFoundError';
|
||||
}, 'Wrong error for nonexistent scope');
|
||||
});
|
60
dom/push/test/xpcshell/test_unregister_success.js
Normal file
60
dom/push/test/xpcshell/test_unregister_success.js
Normal file
@ -0,0 +1,60 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {PushDB, PushService} = serviceExports;
|
||||
|
||||
const channelID = 'db0a7021-ec2d-4bd3-8802-7a6966f10ed8';
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
setPrefs();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_unregister_success() {
|
||||
let db = new PushDB();
|
||||
let promiseDB = promisifyDatabase(db);
|
||||
do_register_cleanup(() => cleanupDatabase(db));
|
||||
yield promiseDB.put({
|
||||
channelID,
|
||||
pushEndpoint: 'https://example.org/update/unregister-success',
|
||||
scope: 'https://example.com/page/unregister-success',
|
||||
version: 1
|
||||
});
|
||||
|
||||
let unregisterDefer = Promise.defer();
|
||||
PushService.init({
|
||||
networkInfo: new MockDesktopNetworkInfo(),
|
||||
db,
|
||||
makeWebSocket(uri) {
|
||||
return new MockWebSocket(uri, {
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'hello',
|
||||
status: 200,
|
||||
uaid: 'fbe865a6-aeb8-446f-873c-aeebdb8d493c'
|
||||
}));
|
||||
},
|
||||
onUnregister(request) {
|
||||
equal(request.channelID, channelID, 'Should include the channel ID');
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: 'unregister',
|
||||
status: 200,
|
||||
channelID
|
||||
}));
|
||||
unregisterDefer.resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
yield PushNotificationService.unregister(
|
||||
'https://example.com/page/unregister-success');
|
||||
let record = yield promiseDB.getByChannelID(channelID);
|
||||
ok(!record, 'Unregister did not remove record');
|
||||
|
||||
yield waitForPromise(unregisterDefer.promise, DEFAULT_TIMEOUT,
|
||||
'Timed out waiting for unregister');
|
||||
});
|
32
dom/push/test/xpcshell/xpcshell.ini
Normal file
32
dom/push/test/xpcshell/xpcshell.ini
Normal file
@ -0,0 +1,32 @@
|
||||
[DEFAULT]
|
||||
head = head.js
|
||||
tail =
|
||||
# Push notifications and alarms are currently disabled on Android.
|
||||
skip-if = toolkit == 'android'
|
||||
|
||||
[test_notification_ack.js]
|
||||
[test_notification_duplicate.js]
|
||||
[test_notification_error.js]
|
||||
[test_notification_incomplete.js]
|
||||
[test_notification_version_string.js]
|
||||
[test_register_case.js]
|
||||
[test_register_flush.js]
|
||||
[test_register_invalid_channel.js]
|
||||
[test_register_invalid_endpoint.js]
|
||||
[test_register_invalid_json.js]
|
||||
[test_register_no_id.js]
|
||||
[test_register_request_queue.js]
|
||||
[test_register_rollback.js]
|
||||
[test_register_success.js]
|
||||
[test_register_timeout.js]
|
||||
[test_register_wrong_id.js]
|
||||
[test_register_wrong_type.js]
|
||||
[test_registration_error.js]
|
||||
[test_registration_missing_scope.js]
|
||||
[test_registration_none.js]
|
||||
[test_registration_success.js]
|
||||
[test_unregister_empty_scope.js]
|
||||
[test_unregister_error.js]
|
||||
[test_unregister_invalid_json.js]
|
||||
[test_unregister_not_found.js]
|
||||
[test_unregister_success.js]
|
Loading…
Reference in New Issue
Block a user