Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
"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 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",
},
}),
},
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
);
});