Remove healthreport telemetry module from Sync + tests

This commit is contained in:
wolfbeast 2018-11-30 08:45:46 +01:00 committed by Roy Tam
commit b2be364394
8 changed files with 0 additions and 1089 deletions

View file

@ -1,262 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = [
"SyncProvider",
];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Metrics.jsm", this);
Cu.import("resource://gre/modules/Promise.jsm", this);
Cu.import("resource://gre/modules/Services.jsm", this);
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
const DAILY_LAST_NUMERIC_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_NUMERIC};
const DAILY_LAST_TEXT_FIELD = {type: Metrics.Storage.FIELD_DAILY_LAST_TEXT};
const DAILY_COUNTER_FIELD = {type: Metrics.Storage.FIELD_DAILY_COUNTER};
XPCOMUtils.defineLazyModuleGetter(this, "Weave",
"resource://services-sync/main.js");
function SyncMeasurement1() {
Metrics.Measurement.call(this);
}
SyncMeasurement1.prototype = Object.freeze({
__proto__: Metrics.Measurement.prototype,
name: "sync",
version: 1,
fields: {
enabled: DAILY_LAST_NUMERIC_FIELD,
preferredProtocol: DAILY_LAST_TEXT_FIELD,
activeProtocol: DAILY_LAST_TEXT_FIELD,
syncStart: DAILY_COUNTER_FIELD,
syncSuccess: DAILY_COUNTER_FIELD,
syncError: DAILY_COUNTER_FIELD,
},
});
function SyncDevicesMeasurement1() {
Metrics.Measurement.call(this);
}
SyncDevicesMeasurement1.prototype = Object.freeze({
__proto__: Metrics.Measurement.prototype,
name: "devices",
version: 1,
fields: {},
shouldIncludeField: function (name) {
return true;
},
fieldType: function (name) {
return Metrics.Storage.FIELD_DAILY_COUNTER;
},
});
function SyncMigrationMeasurement1() {
Metrics.Measurement.call(this);
}
SyncMigrationMeasurement1.prototype = Object.freeze({
__proto__: Metrics.Measurement.prototype,
name: "migration",
version: 1,
fields: {
state: DAILY_LAST_TEXT_FIELD, // last "user" or "internal" state we saw for the day
accepted: DAILY_COUNTER_FIELD, // number of times user tried to start migration
declined: DAILY_COUNTER_FIELD, // number of times user closed nagging infobar
unlinked: DAILY_LAST_NUMERIC_FIELD, // did the user decline and unlink
},
});
this.SyncProvider = function () {
Metrics.Provider.call(this);
};
SyncProvider.prototype = Object.freeze({
__proto__: Metrics.Provider.prototype,
name: "org.mozilla.sync",
measurementTypes: [
SyncDevicesMeasurement1,
SyncMeasurement1,
SyncMigrationMeasurement1,
],
_OBSERVERS: [
"weave:service:sync:start",
"weave:service:sync:finish",
"weave:service:sync:error",
"fxa-migration:state-changed",
"fxa-migration:internal-state-changed",
"fxa-migration:internal-telemetry",
],
postInit: function () {
for (let o of this._OBSERVERS) {
Services.obs.addObserver(this, o, false);
}
return Promise.resolve();
},
onShutdown: function () {
for (let o of this._OBSERVERS) {
Services.obs.removeObserver(this, o);
}
return Promise.resolve();
},
observe: function (subject, topic, data) {
switch (topic) {
case "weave:service:sync:start":
case "weave:service:sync:finish":
case "weave:service:sync:error":
return this._observeSync(subject, topic, data);
case "fxa-migration:state-changed":
case "fxa-migration:internal-state-changed":
case "fxa-migration:internal-telemetry":
return this._observeMigration(subject, topic, data);
}
Cu.reportError("unexpected topic in sync healthreport provider: " + topic);
},
_observeSync: function (subject, topic, data) {
let field;
switch (topic) {
case "weave:service:sync:start":
field = "syncStart";
break;
case "weave:service:sync:finish":
field = "syncSuccess";
break;
case "weave:service:sync:error":
field = "syncError";
break;
default:
Cu.reportError("unexpected sync topic in sync healthreport provider: " + topic);
return;
}
let m = this.getMeasurement(SyncMeasurement1.prototype.name,
SyncMeasurement1.prototype.version);
return this.enqueueStorageOperation(function recordSyncEvent() {
return m.incrementDailyCounter(field);
});
},
_observeMigration: function(subject, topic, data) {
switch (topic) {
case "fxa-migration:state-changed":
case "fxa-migration:internal-state-changed": {
// We record both "user" and "internal" states in the same field. This
// works for us as user state is always null when there is an internal
// state.
if (!data) {
return; // we don't count the |null| state
}
let m = this.getMeasurement(SyncMigrationMeasurement1.prototype.name,
SyncMigrationMeasurement1.prototype.version);
return this.enqueueStorageOperation(function() {
return m.setDailyLastText("state", data);
});
}
case "fxa-migration:internal-telemetry": {
// |data| is our field name.
let m = this.getMeasurement(SyncMigrationMeasurement1.prototype.name,
SyncMigrationMeasurement1.prototype.version);
return this.enqueueStorageOperation(function() {
switch (data) {
case "accepted":
case "declined":
return m.incrementDailyCounter(data);
case "unlinked":
return m.setDailyLastNumeric(data, 1);
default:
Cu.reportError("Unexpected migration field in sync healthreport provider: " + data);
return Promise.resolve();
}
});
}
default:
Cu.reportError("unexpected migration topic in sync healthreport provider: " + topic);
return;
}
},
collectDailyData: function () {
return this.storage.enqueueTransaction(this._populateDailyData.bind(this));
},
_populateDailyData: function* () {
let m = this.getMeasurement(SyncMeasurement1.prototype.name,
SyncMeasurement1.prototype.version);
let svc = Cc["@mozilla.org/weave/service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject;
let enabled = svc.enabled;
yield m.setDailyLastNumeric("enabled", enabled ? 1 : 0);
// preferredProtocol is constant and only changes as the client
// evolves.
yield m.setDailyLastText("preferredProtocol", "1.5");
let protocol = svc.fxAccountsEnabled ? "1.5" : "1.1";
yield m.setDailyLastText("activeProtocol", protocol);
if (!enabled) {
return;
}
// Before grabbing more information, be sure the Sync service
// is fully initialized. This has the potential to initialize
// Sync on the spot. This may be undesired if Sync appears to
// be enabled but it really isn't. That responsibility should
// be up to svc.enabled to not return false positives, however.
yield svc.whenLoaded();
if (Weave.Status.service != Weave.STATUS_OK) {
return;
}
// Device types are dynamic. So we need to dynamically create fields if
// they don't exist.
let dm = this.getMeasurement(SyncDevicesMeasurement1.prototype.name,
SyncDevicesMeasurement1.prototype.version);
let devices = Weave.Service.clientsEngine.deviceTypes;
for (let [field, count] of devices) {
let hasField = this.storage.hasFieldFromMeasurement(dm.id, field,
this.storage.FIELD_DAILY_LAST_NUMERIC);
let fieldID;
if (hasField) {
fieldID = this.storage.fieldIDFromMeasurement(dm.id, field);
} else {
fieldID = yield this.storage.registerField(dm.id, field,
this.storage.FIELD_DAILY_LAST_NUMERIC);
}
yield this.storage.setDailyLastNumericFromFieldID(fieldID, count);
}
},
});

View file

@ -21,7 +21,6 @@ EXTRA_JS_MODULES['services-sync'] += [
'modules/addonutils.js',
'modules/browserid_identity.js',
'modules/engines.js',
'modules/healthreport.jsm',
'modules/identity.js',
'modules/jpakeclient.js',
'modules/keys.js',

View file

@ -1,37 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://services-sync/main.js");
Cu.import("resource://services-sync/util.js");
// Simple test for block/unblock.
add_task(function *() {
Assert.ok(!Weave.Service.scheduler.isBlocked, "sync is not blocked.")
Assert.ok(!Svc.Prefs.has("scheduler.blocked-until"), "have no blocked pref");
Weave.Service.scheduler.blockSync();
Assert.ok(Weave.Service.scheduler.isBlocked, "sync is blocked.")
Assert.ok(Svc.Prefs.has("scheduler.blocked-until"), "have the blocked pref");
Weave.Service.scheduler.unblockSync();
Assert.ok(!Weave.Service.scheduler.isBlocked, "sync is not blocked.")
Assert.ok(!Svc.Prefs.has("scheduler.blocked-until"), "have no blocked pref");
// now check the "until" functionality.
let until = Date.now() + 1000;
Weave.Service.scheduler.blockSync(until);
Assert.ok(Weave.Service.scheduler.isBlocked, "sync is blocked.")
Assert.ok(Svc.Prefs.has("scheduler.blocked-until"), "have the blocked pref");
// wait for 'until' to pass.
yield new Promise((resolve, reject) => {
CommonUtils.namedTimer(resolve, 1000, {}, "timer");
});
// should have automagically unblocked and removed the pref.
Assert.ok(!Weave.Service.scheduler.isBlocked, "sync is not blocked.")
Assert.ok(!Svc.Prefs.has("scheduler.blocked-until"), "have no blocked pref");
});
function run_test() {
run_next_test();
}

View file

@ -1,279 +0,0 @@
// Test the FxAMigration module
Cu.import("resource://services-sync/FxaMigrator.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/FxAccounts.jsm");
Cu.import("resource://gre/modules/FxAccountsCommon.js");
Cu.import("resource://services-sync/browserid_identity.js");
// Set our username pref early so sync initializes with the legacy provider.
Services.prefs.setCharPref("services.sync.username", "foo");
// And ensure all debug messages end up being printed.
Services.prefs.setCharPref("services.sync.log.appender.dump", "Debug");
// Now import sync
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/util.js");
// And reset the username.
Services.prefs.clearUserPref("services.sync.username");
Cu.import("resource://testing-common/services/sync/utils.js");
Cu.import("resource://testing-common/services/common/logging.js");
Cu.import("resource://testing-common/services/sync/rotaryengine.js");
const FXA_USERNAME = "someone@somewhere";
// Utilities
function promiseOneObserver(topic) {
return new Promise((resolve, reject) => {
let observer = function(subject, topic, data) {
Services.obs.removeObserver(observer, topic);
resolve({ subject: subject, data: data });
}
Services.obs.addObserver(observer, topic, false);
});
}
function promiseStopServer(server) {
return new Promise((resolve, reject) => {
server.stop(resolve);
});
}
// Helpers
function configureLegacySync() {
let engine = new RotaryEngine(Service);
engine.enabled = true;
Svc.Prefs.set("registerEngines", engine.name);
Svc.Prefs.set("log.logger.engine.rotary", "Trace");
let contents = {
meta: {global: {engines: {rotary: {version: engine.version,
syncID: engine.syncID}}}},
crypto: {},
rotary: {}
};
const USER = "foo";
const PASSPHRASE = "abcdeabcdeabcdeabcdeabcdea";
setBasicCredentials(USER, "password", PASSPHRASE);
let onRequest = function(request, response) {
// ideally we'd only do this while a legacy user is configured, but WTH.
response.setHeader("x-weave-alert", JSON.stringify({code: "soft-eol"}));
}
let server = new SyncServer({onRequest: onRequest});
server.registerUser(USER, "password");
server.createContents(USER, contents);
server.start();
Service.serverURL = server.baseURI;
Service.clusterURL = server.baseURI;
Service.identity.username = USER;
Service._updateCachedURLs();
Service.engineManager._engines[engine.name] = engine;
return [engine, server];
}
function configureFxa() {
Services.prefs.setCharPref("identity.fxaccounts.auth.uri", "http://localhost");
}
add_task(function *testMigration() {
configureFxa();
// when we do a .startOver we want the new provider.
let oldValue = Services.prefs.getBoolPref("services.sync-testing.startOverKeepIdentity");
Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", false);
// disable the addons engine - this engine choice is arbitrary, but we
// want to check it remains disabled after migration.
Services.prefs.setBoolPref("services.sync.engine.addons", false);
do_register_cleanup(() => {
Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", oldValue)
Services.prefs.setBoolPref("services.sync.engine.addons", true);
});
// No sync user - that should report no user-action necessary.
Assert.deepEqual((yield fxaMigrator._queueCurrentUserState()), null,
"no user state when complete");
// Arrange for a legacy sync user and manually bump the migrator
let [engine, server] = configureLegacySync();
// Check our disabling of the "addons" engine worked, and for good measure,
// that the "passwords" engine is enabled.
Assert.ok(!Service.engineManager.get("addons").enabled, "addons is disabled");
Assert.ok(Service.engineManager.get("passwords").enabled, "passwords is enabled");
// monkey-patch the migration sentinel code so we know it was called.
let haveStartedSentinel = false;
let origSetFxAMigrationSentinel = Service.setFxAMigrationSentinel;
let promiseSentinelWritten = new Promise((resolve, reject) => {
Service.setFxAMigrationSentinel = function(arg) {
haveStartedSentinel = true;
return origSetFxAMigrationSentinel.call(Service, arg).then(result => {
Service.setFxAMigrationSentinel = origSetFxAMigrationSentinel;
resolve(result);
return result;
});
}
});
// We are now configured for legacy sync, but we aren't in an EOL state yet,
// so should still be not waiting for a user.
Assert.deepEqual((yield fxaMigrator._queueCurrentUserState()), null,
"no user state before server EOL");
// Start a sync - this will cause an EOL notification which the migrator's
// observer will notice.
let promise = promiseOneObserver("fxa-migration:state-changed");
_("Starting sync");
Service.sync();
_("Finished sync");
// We should have seen the observer, so be waiting for an FxA user.
Assert.equal((yield promise).data, fxaMigrator.STATE_USER_FXA, "now waiting for FxA.")
// Re-calling our user-state promise should also reflect the same state.
Assert.equal((yield fxaMigrator._queueCurrentUserState()),
fxaMigrator.STATE_USER_FXA,
"still waiting for FxA.");
// arrange for an unverified FxA user.
let config = makeIdentityConfig({username: FXA_USERNAME});
let fxa = new FxAccounts({});
config.fxaccount.user.email = config.username;
delete config.fxaccount.user.verified;
// *sob* - shouldn't need this boilerplate
fxa.internal.currentAccountState.getCertificate = function(data, keyPair, mustBeValidUntil) {
this.cert = {
validUntil: fxa.internal.now() + CERT_LIFETIME,
cert: "certificate",
};
return Promise.resolve(this.cert.cert);
};
// As soon as we set the FxA user the observers should fire and magically
// transition.
promise = promiseOneObserver("fxa-migration:state-changed");
fxAccounts.setSignedInUser(config.fxaccount.user);
let observerInfo = yield promise;
Assert.equal(observerInfo.data,
fxaMigrator.STATE_USER_FXA_VERIFIED,
"now waiting for verification");
Assert.ok(observerInfo.subject instanceof Ci.nsISupportsString,
"email was passed to observer");
Assert.equal(observerInfo.subject.data,
FXA_USERNAME,
"email passed to observer is correct");
// should have seen the user set, so state should automatically update.
Assert.equal((yield fxaMigrator._queueCurrentUserState()),
fxaMigrator.STATE_USER_FXA_VERIFIED,
"now waiting for verification");
// Before we verify the user, fire off a sync that calls us back during
// the sync and before it completes - this way we can ensure we do the right
// thing in terms of blocking sync and waiting for it to complete.
let wasWaiting = false;
// This is a PITA as sync is pseudo-blocking.
engine._syncFinish = function () {
// We aren't in a generator here, so use a helper to block on promises.
function getState() {
let cb = Async.makeSpinningCallback();
fxaMigrator._queueCurrentUserState().then(state => cb(null, state));
return cb.wait();
}
// should still be waiting for verification.
Assert.equal(getState(), fxaMigrator.STATE_USER_FXA_VERIFIED,
"still waiting for verification");
// arrange for the user to be verified. The fxAccount's mock story is
// broken, so go behind its back.
config.fxaccount.user.verified = true;
fxAccounts.setSignedInUser(config.fxaccount.user);
Services.obs.notifyObservers(null, ONVERIFIED_NOTIFICATION, null);
// spinningly wait for the migrator to catch up - sync is running so
// we should be in a 'null' user-state as there is no user-action
// necessary.
let cb = Async.makeSpinningCallback();
promiseOneObserver("fxa-migration:state-changed").then(({ data: state }) => cb(null, state));
Assert.equal(cb.wait(), null, "no user action necessary while sync completes.");
// We must not have started writing the sentinel yet.
Assert.ok(!haveStartedSentinel, "haven't written a sentinel yet");
// sync should be blocked from continuing
Assert.ok(Service.scheduler.isBlocked, "sync is blocked.")
wasWaiting = true;
throw ex;
};
_("Starting sync");
Service.sync();
_("Finished sync");
// mock sync so we can ensure the final sync is scheduled with the FxA user.
// (letting a "normal" sync complete is a PITA without mocking huge amounts
// of FxA infra)
let promiseFinalSync = new Promise((resolve, reject) => {
let oldSync = Service.sync;
Service.sync = function() {
Service.sync = oldSync;
resolve();
}
});
Assert.ok(wasWaiting, "everything was good while sync was running.")
// The migration is now going to run to completion.
// sync should still be "blocked"
Assert.ok(Service.scheduler.isBlocked, "sync is blocked.");
// We should see the migration sentinel written and it should return true.
Assert.ok((yield promiseSentinelWritten), "wrote the sentinel");
// And we should see a new sync start
yield promiseFinalSync;
// and we should be configured for FxA
let WeaveService = Cc["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
Assert.ok(WeaveService.fxAccountsEnabled, "FxA is enabled");
Assert.ok(Service.identity instanceof BrowserIDManager,
"sync is configured with the browserid_identity provider.");
Assert.equal(Service.identity.username, config.username, "correct user configured")
Assert.ok(!Service.scheduler.isBlocked, "sync is not blocked.")
// and the user state should remain null.
Assert.deepEqual((yield fxaMigrator._queueCurrentUserState()),
null,
"still no user action necessary");
// and our engines should be in the same enabled/disabled state as before.
Assert.ok(!Service.engineManager.get("addons").enabled, "addons is still disabled");
Assert.ok(Service.engineManager.get("passwords").enabled, "passwords is still enabled");
// aaaand, we are done - clean up.
yield promiseStopServer(server);
});
function run_test() {
initTestLogging();
do_register_cleanup(() => {
fxaMigrator.finalize();
Svc.Prefs.resetBranch("");
});
run_next_test();
}

View file

@ -1,150 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test the reading and writing of the sync migration sentinel.
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/FxAccounts.jsm");
Cu.import("resource://gre/modules/FxAccountsCommon.js");
Cu.import("resource://testing-common/services/sync/utils.js");
Cu.import("resource://testing-common/services/common/logging.js");
Cu.import("resource://services-sync/record.js");
// Set our username pref early so sync initializes with the legacy provider.
Services.prefs.setCharPref("services.sync.username", "foo");
// Now import sync
Cu.import("resource://services-sync/service.js");
const USER = "foo";
const PASSPHRASE = "abcdeabcdeabcdeabcdeabcdea";
function promiseStopServer(server) {
return new Promise((resolve, reject) => {
server.stop(resolve);
});
}
let numServerRequests = 0;
// Helpers
function configureLegacySync() {
let contents = {
meta: {global: {}},
crypto: {},
};
setBasicCredentials(USER, "password", PASSPHRASE);
numServerRequests = 0;
let server = new SyncServer({
onRequest: () => {
++numServerRequests
}
});
server.registerUser(USER, "password");
server.createContents(USER, contents);
server.start();
Service.serverURL = server.baseURI;
Service.clusterURL = server.baseURI;
Service.identity.username = USER;
Service._updateCachedURLs();
return server;
}
// Test a simple round-trip of the get/set functions.
add_task(function *() {
// Arrange for a legacy sync user.
let server = configureLegacySync();
Assert.equal((yield Service.getFxAMigrationSentinel()), null, "no sentinel to start");
let sentinel = {foo: "bar"};
yield Service.setFxAMigrationSentinel(sentinel);
Assert.deepEqual((yield Service.getFxAMigrationSentinel()), sentinel, "got the sentinel back");
yield promiseStopServer(server);
});
// Test the records are cached by the record manager.
add_task(function *() {
// Arrange for a legacy sync user.
let server = configureLegacySync();
Service.login();
// Reset the request count here as the login would have made some.
numServerRequests = 0;
Assert.equal((yield Service.getFxAMigrationSentinel()), null, "no sentinel to start");
Assert.equal(numServerRequests, 1, "first fetch should hit the server");
let sentinel = {foo: "bar"};
yield Service.setFxAMigrationSentinel(sentinel);
Assert.equal(numServerRequests, 2, "setting sentinel should hit the server");
Assert.deepEqual((yield Service.getFxAMigrationSentinel()), sentinel, "got the sentinel back");
Assert.equal(numServerRequests, 2, "second fetch should not should hit the server");
// Clobber the caches and ensure we still get the correct value back when we
// do hit the server.
Service.recordManager.clearCache();
Assert.deepEqual((yield Service.getFxAMigrationSentinel()), sentinel, "got the sentinel back");
Assert.equal(numServerRequests, 3, "should have re-hit the server with empty caches");
yield promiseStopServer(server);
});
// Test the records are cached by a sync.
add_task(function* () {
let server = configureLegacySync();
// A first sync clobbers meta/global due to it being empty, so we first
// do a sync which forces a good set of data on the server.
Service.sync();
// Now create a sentinel exists on the server. It's encrypted, so we need to
// put an encrypted version.
let cryptoWrapper = new CryptoWrapper("meta", "fxa_credentials");
let sentinel = {foo: "bar"};
cryptoWrapper.cleartext = {
id: "fxa_credentials",
sentinel: sentinel,
deleted: false,
}
cryptoWrapper.encrypt(Service.identity.syncKeyBundle);
let payload = {
ciphertext: cryptoWrapper.ciphertext,
IV: cryptoWrapper.IV,
hmac: cryptoWrapper.hmac,
};
server.createContents(USER, {
meta: {fxa_credentials: payload},
crypto: {},
});
// Another sync - this will cause the encrypted record to be fetched.
Service.sync();
// Reset the request count here as the sync will have made many!
numServerRequests = 0;
// Asking for the sentinel should use the copy cached in the record manager.
Assert.deepEqual((yield Service.getFxAMigrationSentinel()), sentinel, "got it");
Assert.equal(numServerRequests, 0, "should not have hit the server");
// And asking for it again should work (we have to work around the fact the
// ciphertext is clobbered on first decrypt...)
Assert.deepEqual((yield Service.getFxAMigrationSentinel()), sentinel, "got it again");
Assert.equal(numServerRequests, 0, "should not have hit the server");
yield promiseStopServer(server);
});
function run_test() {
initTestLogging();
run_next_test();
}

View file

@ -1,194 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://gre/modules/Metrics.jsm", this);
Cu.import("resource://gre/modules/Preferences.jsm", this);
Cu.import("resource://gre/modules/Promise.jsm", this);
Cu.import("resource://services-sync/main.js", this);
Cu.import("resource://services-sync/healthreport.jsm", this);
Cu.import("resource://testing-common/services/common/logging.js", this);
Cu.import("resource://testing-common/services/healthreport/utils.jsm", this);
function run_test() {
initTestLogging();
run_next_test();
}
add_task(function test_constructor() {
let provider = new SyncProvider();
});
// Provider can initialize and de-initialize properly.
add_task(function* test_init() {
let storage = yield Metrics.Storage("init");
let provider = new SyncProvider();
yield provider.init(storage);
yield provider.shutdown();
yield storage.close();
});
add_task(function* test_collect() {
let storage = yield Metrics.Storage("collect");
let provider = new SyncProvider();
yield provider.init(storage);
// Initially nothing should be configured.
let now = new Date();
yield provider.collectDailyData();
let m = provider.getMeasurement("sync", 1);
let values = yield m.getValues();
Assert.equal(values.days.size, 1);
Assert.ok(values.days.hasDay(now));
let day = values.days.getDay(now);
Assert.ok(day.has("enabled"));
Assert.ok(day.has("activeProtocol"));
Assert.ok(day.has("preferredProtocol"));
Assert.equal(day.get("enabled"), 0);
Assert.equal(day.get("preferredProtocol"), "1.5");
Assert.equal(day.get("activeProtocol"), "1.5",
"Protocol without setup should be FX Accounts version.");
// Now check for old Sync setup.
let branch = new Preferences("services.sync.");
branch.set("username", "foo");
branch.reset("fxaccounts.enabled");
yield provider.collectDailyData();
values = yield m.getValues();
Assert.equal(values.days.getDay(now).get("activeProtocol"), "1.1",
"Protocol with old Sync setup is correct.");
Assert.equal(Weave.Status.__authManager, undefined, "Detect code changes");
// Let's enable Sync so we can get more useful data.
// We need to do this because the FHR probe only records more info if Sync
// is configured properly.
Weave.Service.identity.account = "johndoe";
Weave.Service.identity.basicPassword = "ilovejane";
Weave.Service.identity.syncKey = Weave.Utils.generatePassphrase();
Weave.Service.clusterURL = "http://localhost/";
Assert.equal(Weave.Status.checkSetup(), Weave.STATUS_OK);
yield provider.collectDailyData();
values = yield m.getValues();
day = values.days.getDay(now);
Assert.equal(day.get("enabled"), 1);
// An empty account should have 1 device: us.
let dm = provider.getMeasurement("devices", 1);
values = yield dm.getValues();
Assert.ok(values.days.hasDay(now));
day = values.days.getDay(now);
Assert.equal(day.size, 1);
let engine = Weave.Service.clientsEngine;
Assert.ok(engine);
Assert.ok(day.has(engine.localType));
Assert.equal(day.get(engine.localType), 1);
// Add some devices and ensure they show up.
engine._store._remoteClients["id1"] = {type: "mobile"};
engine._store._remoteClients["id2"] = {type: "tablet"};
engine._store._remoteClients["id3"] = {type: "mobile"};
yield provider.collectDailyData();
values = yield dm.getValues();
day = values.days.getDay(now);
let expected = {
"foobar": 0,
"tablet": 1,
"mobile": 2,
"desktop": 0,
};
for (let type in expected) {
let count = expected[type];
if (engine.localType == type) {
count++;
}
if (!count) {
Assert.ok(!day.has(type));
} else {
Assert.ok(day.has(type));
Assert.equal(day.get(type), count);
}
}
engine._store._remoteClients = {};
yield provider.shutdown();
yield storage.close();
});
add_task(function* test_sync_events() {
let storage = yield Metrics.Storage("sync_events");
let provider = new SyncProvider();
yield provider.init(storage);
let m = provider.getMeasurement("sync", 1);
for (let i = 0; i < 5; i++) {
Services.obs.notifyObservers(null, "weave:service:sync:start", null);
}
for (let i = 0; i < 3; i++) {
Services.obs.notifyObservers(null, "weave:service:sync:finish", null);
}
for (let i = 0; i < 2; i++) {
Services.obs.notifyObservers(null, "weave:service:sync:error", null);
}
// Wait for storage to complete.
yield m.storage.enqueueOperation(() => {
return Promise.resolve();
});
let values = yield m.getValues();
let now = new Date();
Assert.ok(values.days.hasDay(now));
let day = values.days.getDay(now);
Assert.ok(day.has("syncStart"));
Assert.ok(day.has("syncSuccess"));
Assert.ok(day.has("syncError"));
Assert.equal(day.get("syncStart"), 5);
Assert.equal(day.get("syncSuccess"), 3);
Assert.equal(day.get("syncError"), 2);
yield provider.shutdown();
yield storage.close();
});
add_task(function* test_healthreporter_json() {
let reporter = yield getHealthReporter("healthreporter_json");
yield reporter.init();
try {
yield reporter._providerManager.registerProvider(new SyncProvider());
yield reporter.collectMeasurements();
let payload = yield reporter.getJSONPayload(true);
let now = new Date();
let today = reporter._formatDate(now);
Assert.ok(today in payload.data.days);
let day = payload.data.days[today];
Assert.ok("org.mozilla.sync.sync" in day);
Assert.ok("org.mozilla.sync.devices" in day);
let devices = day["org.mozilla.sync.devices"];
let engine = Weave.Service.clientsEngine;
Assert.ok(engine);
let type = engine.localType;
Assert.ok(type);
Assert.ok(type in devices);
Assert.equal(devices[type], 1);
} finally {
reporter._shutdown();
}
});

View file

@ -1,155 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://gre/modules/Metrics.jsm", this);
Cu.import("resource://gre/modules/Preferences.jsm", this);
Cu.import("resource://gre/modules/Promise.jsm", this);
Cu.import("resource://services-sync/healthreport.jsm", this);
Cu.import("resource://services-sync/FxaMigrator.jsm", this);
Cu.import("resource://testing-common/services/common/logging.js", this);
Cu.import("resource://testing-common/services/healthreport/utils.jsm", this);
function run_test() {
initTestLogging();
run_next_test();
}
add_task(function* test_no_data() {
let storage = yield Metrics.Storage("collect");
let provider = new SyncProvider();
yield provider.init(storage);
try {
// Initially nothing should be configured.
let now = new Date();
yield provider.collectDailyData();
let m = provider.getMeasurement("migration", 1);
let values = yield m.getValues();
Assert.equal(values.days.size, 0);
Assert.ok(!values.days.hasDay(now));
} finally {
yield provider.shutdown();
yield storage.close();
}
});
function checkCorrectStateRecorded(provider, state) {
// Wait for storage to complete.
yield m.storage.enqueueOperation(() => {
return Promise.resolve();
});
let m = provider.getMeasurement("migration", 1);
let values = yield m.getValues();
Assert.equal(values.days.size, 1);
Assert.ok(values.days.hasDay(now));
let day = values.days.getDay(now);
Assert.ok(day.has("state"));
Assert.equal(day.get("state"), state);
}
add_task(function* test_state() {
let storage = yield Metrics.Storage("collect");
let provider = new SyncProvider();
yield provider.init(storage);
try {
// Initially nothing should be configured.
let now = new Date();
// We record both a "user" and "internal" state in the same field.
// So simulate a "user" state first.
Services.obs.notifyObservers(null, "fxa-migration:state-changed",
fxaMigrator.STATE_USER_FXA_VERIFIED);
checkCorrectStateRecorded(provider, fxaMigrator.STATE_USER_FXA_VERIFIED);
// And an internal state.
Services.obs.notifyObservers(null, "fxa-migration:internal-state-changed",
fxaMigrator.STATE_INTERNAL_WAITING_SYNC_COMPLETE);
checkCorrectStateRecorded(provider, fxaMigrator.STATE_INTERNAL_WAITING_SYNC_COMPLETE);
} finally {
yield provider.shutdown();
yield storage.close();
}
});
add_task(function* test_flags() {
let storage = yield Metrics.Storage("collect");
let provider = new SyncProvider();
yield provider.init(storage);
try {
// Initially nothing should be configured.
let now = new Date();
let m = provider.getMeasurement("migration", 1);
let record = function*(what) {
Services.obs.notifyObservers(null, "fxa-migration:internal-telemetry", what);
// Wait for storage to complete.
yield m.storage.enqueueOperation(Promise.resolve);
let values = yield m.getValues();
Assert.equal(values.days.size, 1);
return values.days.getDay(now);
}
let values = yield m.getValues();
Assert.equal(values.days.size, 1);
let day = values.days.getDay(now);
Assert.ok(!day.has(fxaMigrator.TELEMETRY_ACCEPTED));
Assert.ok(!day.has(fxaMigrator.TELEMETRY_DECLINED));
Assert.ok(!day.has(fxaMigrator.TELEMETRY_UNLINKED));
// let's send an unknown value to ensure our error mitigation works.
day = yield record("unknown");
Assert.ok(!day.has(fxaMigrator.TELEMETRY_ACCEPTED));
Assert.ok(!day.has(fxaMigrator.TELEMETRY_DECLINED));
Assert.ok(!day.has(fxaMigrator.TELEMETRY_UNLINKED));
// record an fxaMigrator.TELEMETRY_ACCEPTED state.
day = yield record(fxaMigrator.TELEMETRY_ACCEPTED);
Assert.ok(day.has(fxaMigrator.TELEMETRY_ACCEPTED));
Assert.ok(!day.has(fxaMigrator.TELEMETRY_DECLINED));
Assert.ok(!day.has(fxaMigrator.TELEMETRY_UNLINKED));
Assert.equal(day.get(fxaMigrator.TELEMETRY_ACCEPTED), 1);
// and again - it should get 2.
day = yield record(fxaMigrator.TELEMETRY_ACCEPTED);
Assert.equal(day.get(fxaMigrator.TELEMETRY_ACCEPTED), 2);
// record fxaMigrator.TELEMETRY_DECLINED - also a counter.
day = yield record(fxaMigrator.TELEMETRY_DECLINED);
Assert.ok(day.has(fxaMigrator.TELEMETRY_ACCEPTED));
Assert.ok(day.has(fxaMigrator.TELEMETRY_DECLINED));
Assert.ok(!day.has(fxaMigrator.TELEMETRY_UNLINKED));
Assert.equal(day.get(fxaMigrator.TELEMETRY_ACCEPTED), 2);
Assert.equal(day.get(fxaMigrator.TELEMETRY_DECLINED), 1);
day = yield record(fxaMigrator.TELEMETRY_DECLINED);
Assert.ok(day.has(fxaMigrator.TELEMETRY_ACCEPTED));
Assert.ok(day.has(fxaMigrator.TELEMETRY_DECLINED));
Assert.ok(!day.has(fxaMigrator.TELEMETRY_UNLINKED));
Assert.equal(day.get(fxaMigrator.TELEMETRY_ACCEPTED), 2);
Assert.equal(day.get(fxaMigrator.TELEMETRY_DECLINED), 2);
// and fxaMigrator.TELEMETRY_UNLINKED - this is conceptually a "daily bool".
// (ie, it's DAILY_LAST_NUMERIC_FIELD and only ever has |1| written to it)
day = yield record(fxaMigrator.TELEMETRY_UNLINKED);
Assert.ok(day.has(fxaMigrator.TELEMETRY_ACCEPTED));
Assert.ok(day.has(fxaMigrator.TELEMETRY_DECLINED));
Assert.ok(day.has(fxaMigrator.TELEMETRY_UNLINKED));
Assert.equal(day.get(fxaMigrator.TELEMETRY_UNLINKED), 1);
// and doing it again still leaves us with |1|
day = yield record(fxaMigrator.TELEMETRY_UNLINKED);
Assert.equal(day.get(fxaMigrator.TELEMETRY_UNLINKED), 1);
} finally {
yield provider.shutdown();
yield storage.close();
}
});

View file

@ -168,15 +168,4 @@ skip-if = debug
[test_tab_store.js]
[test_tab_tracker.js]
[test_healthreport.js]
skip-if = ! healthreport
[test_healthreport_migration.js]
skip-if = ! healthreport
[test_warn_on_truncated_response.js]
# FxA migration
[test_block_sync.js]
[test_fxa_migration.js]
[test_fxa_migration_sentinel.js]