522 lines
11 KiB
JavaScript
522 lines
11 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
// Tests for the FxA push service.
|
|
|
|
/* eslint-disable mozilla/use-chromeutils-generateqi */
|
|
|
|
const {
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE,
|
|
ONLOGOUT_NOTIFICATION,
|
|
ON_ACCOUNT_DESTROYED_NOTIFICATION,
|
|
ON_DEVICE_CONNECTED_NOTIFICATION,
|
|
ON_DEVICE_DISCONNECTED_NOTIFICATION,
|
|
ON_PASSWORD_CHANGED_NOTIFICATION,
|
|
ON_PASSWORD_RESET_NOTIFICATION,
|
|
ON_PROFILE_CHANGE_NOTIFICATION,
|
|
ON_PROFILE_UPDATED_NOTIFICATION,
|
|
ON_VERIFY_LOGIN_NOTIFICATION,
|
|
log,
|
|
} = ChromeUtils.importESModule(
|
|
"resource://gre/modules/FxAccountsCommon.sys.mjs"
|
|
);
|
|
|
|
const { FxAccountsPushService } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/FxAccountsPush.sys.mjs"
|
|
);
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(
|
|
this,
|
|
"PushService",
|
|
"@mozilla.org/push/Service;1",
|
|
"nsIPushService"
|
|
);
|
|
|
|
initTestLogging("Trace");
|
|
log.level = Log.Level.Trace;
|
|
|
|
const MOCK_ENDPOINT = "http://mochi.test:8888";
|
|
|
|
// tests do not allow external connections, mock the PushService
|
|
let mockPushService = {
|
|
pushTopic: PushService.pushTopic,
|
|
subscriptionChangeTopic: PushService.subscriptionChangeTopic,
|
|
subscribe(scope, principal, cb) {
|
|
cb(Cr.NS_OK, {
|
|
endpoint: MOCK_ENDPOINT,
|
|
});
|
|
},
|
|
unsubscribe(scope, principal, cb) {
|
|
cb(Cr.NS_OK, true);
|
|
},
|
|
};
|
|
|
|
let mockFxAccounts = {
|
|
checkVerificationStatus() {},
|
|
updateDeviceRegistration() {},
|
|
};
|
|
|
|
let mockLog = {
|
|
trace() {},
|
|
debug() {},
|
|
warn() {},
|
|
error() {},
|
|
};
|
|
|
|
add_task(async function initialize() {
|
|
let pushService = new FxAccountsPushService();
|
|
equal(pushService.initialize(), false);
|
|
});
|
|
|
|
add_task(async function registerPushEndpointSuccess() {
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: mockFxAccounts,
|
|
});
|
|
|
|
let subscription = await pushService.registerPushEndpoint();
|
|
equal(subscription.endpoint, MOCK_ENDPOINT);
|
|
});
|
|
|
|
add_task(async function registerPushEndpointFailure() {
|
|
let failPushService = Object.assign(mockPushService, {
|
|
subscribe(scope, principal, cb) {
|
|
cb(Cr.NS_ERROR_ABORT);
|
|
},
|
|
});
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: failPushService,
|
|
fxai: mockFxAccounts,
|
|
});
|
|
|
|
let subscription = await pushService.registerPushEndpoint();
|
|
equal(subscription, null);
|
|
});
|
|
|
|
add_task(async function unsubscribeSuccess() {
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: mockFxAccounts,
|
|
});
|
|
|
|
let result = await pushService.unsubscribe();
|
|
equal(result, true);
|
|
});
|
|
|
|
add_task(async function unsubscribeFailure() {
|
|
let failPushService = Object.assign(mockPushService, {
|
|
unsubscribe(scope, principal, cb) {
|
|
cb(Cr.NS_ERROR_ABORT);
|
|
},
|
|
});
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: failPushService,
|
|
fxai: mockFxAccounts,
|
|
});
|
|
|
|
let result = await pushService.unsubscribe();
|
|
equal(result, null);
|
|
});
|
|
|
|
add_test(function observeLogout() {
|
|
let customLog = Object.assign(mockLog, {
|
|
trace(msg) {
|
|
if (msg === "FxAccountsPushService unsubscribe") {
|
|
// logout means we unsubscribe
|
|
run_next_test();
|
|
}
|
|
},
|
|
});
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
log: customLog,
|
|
});
|
|
|
|
pushService.observe(null, ONLOGOUT_NOTIFICATION);
|
|
});
|
|
|
|
add_test(function observePushTopicVerify() {
|
|
let emptyMsg = {
|
|
QueryInterface() {
|
|
return this;
|
|
},
|
|
};
|
|
let customAccounts = Object.assign(mockFxAccounts, {
|
|
checkVerificationStatus() {
|
|
// checking verification status on push messages without data
|
|
run_next_test();
|
|
},
|
|
});
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: customAccounts,
|
|
});
|
|
|
|
pushService.observe(
|
|
emptyMsg,
|
|
mockPushService.pushTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
});
|
|
|
|
add_test(function observePushTopicDeviceConnected() {
|
|
let msg = {
|
|
data: {
|
|
json: () => ({
|
|
command: ON_DEVICE_CONNECTED_NOTIFICATION,
|
|
data: {
|
|
deviceName: "My phone",
|
|
},
|
|
}),
|
|
},
|
|
QueryInterface() {
|
|
return this;
|
|
},
|
|
};
|
|
let obs = (subject, topic) => {
|
|
Services.obs.removeObserver(obs, topic);
|
|
run_next_test();
|
|
};
|
|
Services.obs.addObserver(obs, ON_DEVICE_CONNECTED_NOTIFICATION);
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: mockFxAccounts,
|
|
});
|
|
|
|
pushService.observe(
|
|
msg,
|
|
mockPushService.pushTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
});
|
|
|
|
add_task(async function observePushTopicDeviceDisconnected_current_device() {
|
|
const deviceId = "bogusid";
|
|
let msg = {
|
|
data: {
|
|
json: () => ({
|
|
command: ON_DEVICE_DISCONNECTED_NOTIFICATION,
|
|
data: {
|
|
id: deviceId,
|
|
},
|
|
}),
|
|
},
|
|
QueryInterface() {
|
|
return this;
|
|
},
|
|
};
|
|
|
|
let signoutCalled = false;
|
|
let { FxAccounts } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/FxAccounts.sys.mjs"
|
|
);
|
|
const fxAccountsMock = new FxAccounts({
|
|
newAccountState() {
|
|
return {
|
|
async getUserAccountData() {
|
|
return { device: { id: deviceId } };
|
|
},
|
|
};
|
|
},
|
|
signOut() {
|
|
signoutCalled = true;
|
|
},
|
|
})._internal;
|
|
|
|
const deviceDisconnectedNotificationObserved = new Promise(resolve => {
|
|
Services.obs.addObserver(function obs(subject, topic, data) {
|
|
Services.obs.removeObserver(obs, topic);
|
|
equal(data, JSON.stringify({ isLocalDevice: true }));
|
|
resolve();
|
|
}, ON_DEVICE_DISCONNECTED_NOTIFICATION);
|
|
});
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: fxAccountsMock,
|
|
});
|
|
|
|
pushService.observe(
|
|
msg,
|
|
mockPushService.pushTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
|
|
await deviceDisconnectedNotificationObserved;
|
|
ok(signoutCalled);
|
|
});
|
|
|
|
add_task(async function observePushTopicDeviceDisconnected_another_device() {
|
|
const deviceId = "bogusid";
|
|
let msg = {
|
|
data: {
|
|
json: () => ({
|
|
command: ON_DEVICE_DISCONNECTED_NOTIFICATION,
|
|
data: {
|
|
id: deviceId,
|
|
},
|
|
}),
|
|
},
|
|
QueryInterface() {
|
|
return this;
|
|
},
|
|
};
|
|
|
|
let signoutCalled = false;
|
|
let { FxAccounts } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/FxAccounts.sys.mjs"
|
|
);
|
|
const fxAccountsMock = new FxAccounts({
|
|
newAccountState() {
|
|
return {
|
|
async getUserAccountData() {
|
|
return { device: { id: "thelocaldevice" } };
|
|
},
|
|
};
|
|
},
|
|
signOut() {
|
|
signoutCalled = true;
|
|
},
|
|
})._internal;
|
|
|
|
const deviceDisconnectedNotificationObserved = new Promise(resolve => {
|
|
Services.obs.addObserver(function obs(subject, topic, data) {
|
|
Services.obs.removeObserver(obs, topic);
|
|
equal(data, JSON.stringify({ isLocalDevice: false }));
|
|
resolve();
|
|
}, ON_DEVICE_DISCONNECTED_NOTIFICATION);
|
|
});
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: fxAccountsMock,
|
|
});
|
|
|
|
pushService.observe(
|
|
msg,
|
|
mockPushService.pushTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
|
|
await deviceDisconnectedNotificationObserved;
|
|
ok(!signoutCalled);
|
|
});
|
|
|
|
add_test(function observePushTopicAccountDestroyed() {
|
|
const uid = "bogusuid";
|
|
let msg = {
|
|
data: {
|
|
json: () => ({
|
|
command: ON_ACCOUNT_DESTROYED_NOTIFICATION,
|
|
data: {
|
|
uid,
|
|
},
|
|
}),
|
|
},
|
|
QueryInterface() {
|
|
return this;
|
|
},
|
|
};
|
|
let customAccounts = Object.assign(mockFxAccounts, {
|
|
_handleAccountDestroyed() {
|
|
// checking verification status on push messages without data
|
|
run_next_test();
|
|
},
|
|
});
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: customAccounts,
|
|
});
|
|
|
|
pushService.observe(
|
|
msg,
|
|
mockPushService.pushTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
});
|
|
|
|
add_test(function observePushTopicVerifyLogin() {
|
|
let url = "http://localhost/newLogin";
|
|
let title = "bogustitle";
|
|
let body = "bogusbody";
|
|
let msg = {
|
|
data: {
|
|
json: () => ({
|
|
command: ON_VERIFY_LOGIN_NOTIFICATION,
|
|
data: {
|
|
body,
|
|
title,
|
|
url,
|
|
},
|
|
}),
|
|
},
|
|
QueryInterface() {
|
|
return this;
|
|
},
|
|
};
|
|
let obs = (subject, topic, data) => {
|
|
Services.obs.removeObserver(obs, topic);
|
|
Assert.equal(data, JSON.stringify(msg.data.json().data));
|
|
run_next_test();
|
|
};
|
|
Services.obs.addObserver(obs, ON_VERIFY_LOGIN_NOTIFICATION);
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: mockFxAccounts,
|
|
});
|
|
|
|
pushService.observe(
|
|
msg,
|
|
mockPushService.pushTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
});
|
|
|
|
add_test(function observePushTopicProfileUpdated() {
|
|
let msg = {
|
|
data: {
|
|
json: () => ({
|
|
command: ON_PROFILE_UPDATED_NOTIFICATION,
|
|
}),
|
|
},
|
|
QueryInterface() {
|
|
return this;
|
|
},
|
|
};
|
|
let obs = (subject, topic) => {
|
|
Services.obs.removeObserver(obs, topic);
|
|
run_next_test();
|
|
};
|
|
Services.obs.addObserver(obs, ON_PROFILE_CHANGE_NOTIFICATION);
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: mockFxAccounts,
|
|
});
|
|
|
|
pushService.observe(
|
|
msg,
|
|
mockPushService.pushTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
});
|
|
|
|
add_test(function observePushTopicPasswordChanged() {
|
|
let msg = {
|
|
data: {
|
|
json: () => ({
|
|
command: ON_PASSWORD_CHANGED_NOTIFICATION,
|
|
}),
|
|
},
|
|
QueryInterface() {
|
|
return this;
|
|
},
|
|
};
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
});
|
|
|
|
pushService._onPasswordChanged = function () {
|
|
run_next_test();
|
|
};
|
|
|
|
pushService.observe(
|
|
msg,
|
|
mockPushService.pushTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
});
|
|
|
|
add_test(function observePushTopicPasswordReset() {
|
|
let msg = {
|
|
data: {
|
|
json: () => ({
|
|
command: ON_PASSWORD_RESET_NOTIFICATION,
|
|
}),
|
|
},
|
|
QueryInterface() {
|
|
return this;
|
|
},
|
|
};
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
});
|
|
|
|
pushService._onPasswordChanged = function () {
|
|
run_next_test();
|
|
};
|
|
|
|
pushService.observe(
|
|
msg,
|
|
mockPushService.pushTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
});
|
|
|
|
add_task(async function commandReceived() {
|
|
let msg = {
|
|
data: {
|
|
json: () => ({
|
|
command: "fxaccounts:command_received",
|
|
data: {
|
|
url: "https://api.accounts.firefox.com/auth/v1/account/device/commands?index=42&limit=1",
|
|
},
|
|
}),
|
|
},
|
|
QueryInterface() {
|
|
return this;
|
|
},
|
|
};
|
|
|
|
let fxAccountsMock = {};
|
|
const promiseConsumeRemoteMessagesCalled = new Promise(res => {
|
|
fxAccountsMock.commands = {
|
|
pollDeviceCommands() {
|
|
res();
|
|
},
|
|
};
|
|
});
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: fxAccountsMock,
|
|
});
|
|
|
|
pushService.observe(
|
|
msg,
|
|
mockPushService.pushTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
await promiseConsumeRemoteMessagesCalled;
|
|
});
|
|
|
|
add_test(function observeSubscriptionChangeTopic() {
|
|
let customAccounts = Object.assign(mockFxAccounts, {
|
|
updateDeviceRegistration() {
|
|
// subscription change means updating the device registration
|
|
run_next_test();
|
|
},
|
|
});
|
|
|
|
let pushService = new FxAccountsPushService({
|
|
pushService: mockPushService,
|
|
fxai: customAccounts,
|
|
});
|
|
|
|
pushService.observe(
|
|
null,
|
|
mockPushService.subscriptionChangeTopic,
|
|
FXA_PUSH_SCOPE_ACCOUNT_UPDATE
|
|
);
|
|
});
|