mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 08:18:41 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
15
browser/experiments/test/xpcshell/.eslintrc.js
Normal file
15
browser/experiments/test/xpcshell/.eslintrc.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
],
|
||||
|
||||
"rules": {
|
||||
"no-unused-vars": ["error", {
|
||||
"vars": "all",
|
||||
"varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$",
|
||||
"args": "none"
|
||||
}]
|
||||
}
|
||||
};
|
||||
19
browser/experiments/test/xpcshell/experiments_1.manifest
Normal file
19
browser/experiments/test/xpcshell/experiments_1.manifest
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"version": 1,
|
||||
"experiments": [
|
||||
{
|
||||
"id": "test-experiment-1@tests.mozilla.org",
|
||||
"xpiURL": "https://experiments.mozilla.org/foo.xpi",
|
||||
"xpiHash": "sha1:cb1eb32b89d86d78b7326f416cf404548c5e0099",
|
||||
"startTime": 1393000000,
|
||||
"endTime": 1394000000,
|
||||
"appName": ["Firefox", "Fennec"],
|
||||
"minVersion": "28",
|
||||
"maxVersion": "30",
|
||||
"maxActiveSeconds": 60,
|
||||
"os": ["windows", "linux", "osx"],
|
||||
"channel": ["daily", "weekly", "nightly"],
|
||||
"jsfilter": "function filter(context) { return true; }"
|
||||
}
|
||||
]
|
||||
}
|
||||
199
browser/experiments/test/xpcshell/head.js
Normal file
199
browser/experiments/test/xpcshell/head.js
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* exported PREF_EXPERIMENTS_ENABLED, PREF_LOGGING_LEVEL, PREF_LOGGING_DUMP
|
||||
PREF_MANIFEST_URI, PREF_FETCHINTERVAL, EXPERIMENT1_ID,
|
||||
EXPERIMENT1_NAME, EXPERIMENT1_XPI_SHA1, EXPERIMENT1A_NAME,
|
||||
EXPERIMENT1A_XPI_SHA1, EXPERIMENT2_ID, EXPERIMENT2_XPI_SHA1,
|
||||
EXPERIMENT3_ID, EXPERIMENT4_ID, FAKE_EXPERIMENTS_1,
|
||||
FAKE_EXPERIMENTS_2, gAppInfo, removeCacheFile, defineNow,
|
||||
futureDate, dateToSeconds, loadAddonManager, promiseRestartManager,
|
||||
startAddonManagerOnly, getExperimentAddons, replaceExperiments */
|
||||
|
||||
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://testing-common/AddonManagerTesting.jsm");
|
||||
Cu.import("resource://testing-common/AddonTestUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
|
||||
const PREF_LOGGING_LEVEL = "experiments.logging.level";
|
||||
const PREF_LOGGING_DUMP = "experiments.logging.dump";
|
||||
const PREF_MANIFEST_URI = "experiments.manifest.uri";
|
||||
const PREF_FETCHINTERVAL = "experiments.manifest.fetchIntervalSeconds";
|
||||
const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled";
|
||||
|
||||
function getExperimentPath(base) {
|
||||
let p = do_get_cwd();
|
||||
p.append(base);
|
||||
return p.path;
|
||||
}
|
||||
|
||||
function sha1File(path) {
|
||||
let f = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsILocalFile);
|
||||
f.initWithPath(path);
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"]
|
||||
.createInstance(Ci.nsICryptoHash);
|
||||
hasher.init(hasher.SHA1);
|
||||
|
||||
let is = Cc["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
is.init(f, -1, 0, 0);
|
||||
hasher.updateFromStream(is, Math.pow(2, 32) - 1);
|
||||
is.close();
|
||||
let bytes = hasher.finish(false);
|
||||
|
||||
let rv = "";
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
rv += ("0" + bytes.charCodeAt(i).toString(16)).substr(-2);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
const EXPERIMENT1_ID = "test-experiment-1@tests.mozilla.org";
|
||||
const EXPERIMENT1_XPI_NAME = "experiment-1.xpi";
|
||||
const EXPERIMENT1_NAME = "Test experiment 1";
|
||||
const EXPERIMENT1_PATH = getExperimentPath(EXPERIMENT1_XPI_NAME);
|
||||
const EXPERIMENT1_XPI_SHA1 = "sha1:" + sha1File(EXPERIMENT1_PATH);
|
||||
|
||||
|
||||
const EXPERIMENT1A_XPI_NAME = "experiment-1a.xpi";
|
||||
const EXPERIMENT1A_NAME = "Test experiment 1.1";
|
||||
const EXPERIMENT1A_PATH = getExperimentPath(EXPERIMENT1A_XPI_NAME);
|
||||
const EXPERIMENT1A_XPI_SHA1 = "sha1:" + sha1File(EXPERIMENT1A_PATH);
|
||||
|
||||
const EXPERIMENT2_ID = "test-experiment-2@tests.mozilla.org"
|
||||
const EXPERIMENT2_XPI_NAME = "experiment-2.xpi";
|
||||
const EXPERIMENT2_PATH = getExperimentPath(EXPERIMENT2_XPI_NAME);
|
||||
const EXPERIMENT2_XPI_SHA1 = "sha1:" + sha1File(EXPERIMENT2_PATH);
|
||||
|
||||
const EXPERIMENT3_ID = "test-experiment-3@tests.mozilla.org";
|
||||
const EXPERIMENT4_ID = "test-experiment-4@tests.mozilla.org";
|
||||
|
||||
const FAKE_EXPERIMENTS_1 = [
|
||||
{
|
||||
id: "id1",
|
||||
name: "experiment1",
|
||||
description: "experiment 1",
|
||||
active: true,
|
||||
detailUrl: "https://dummy/experiment1",
|
||||
branch: "foo",
|
||||
},
|
||||
];
|
||||
|
||||
const FAKE_EXPERIMENTS_2 = [
|
||||
{
|
||||
id: "id2",
|
||||
name: "experiment2",
|
||||
description: "experiment 2",
|
||||
active: false,
|
||||
endDate: new Date(2014, 2, 11, 2, 4, 35, 42).getTime(),
|
||||
detailUrl: "https://dummy/experiment2",
|
||||
branch: null,
|
||||
},
|
||||
{
|
||||
id: "id1",
|
||||
name: "experiment1",
|
||||
description: "experiment 1",
|
||||
active: false,
|
||||
endDate: new Date(2014, 2, 10, 0, 0, 0, 0).getTime(),
|
||||
detailURL: "https://dummy/experiment1",
|
||||
branch: null,
|
||||
},
|
||||
];
|
||||
|
||||
var gAppInfo = null;
|
||||
|
||||
function removeCacheFile() {
|
||||
let path = OS.Path.join(OS.Constants.Path.profileDir, "experiments.json");
|
||||
return OS.File.remove(path);
|
||||
}
|
||||
|
||||
function patchPolicy(policy, data) {
|
||||
for (let key of Object.keys(data)) {
|
||||
Object.defineProperty(policy, key, {
|
||||
value: data[key],
|
||||
writable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function defineNow(policy, time) {
|
||||
patchPolicy(policy, { now: () => new Date(time) });
|
||||
}
|
||||
|
||||
function futureDate(date, offset) {
|
||||
return new Date(date.getTime() + offset);
|
||||
}
|
||||
|
||||
function dateToSeconds(date) {
|
||||
return date.getTime() / 1000;
|
||||
}
|
||||
|
||||
var gGlobalScope = this;
|
||||
function loadAddonManager() {
|
||||
AddonTestUtils.init(gGlobalScope);
|
||||
AddonTestUtils.overrideCertDB();
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
return AddonTestUtils.promiseStartupManager();
|
||||
}
|
||||
|
||||
const {
|
||||
promiseRestartManager,
|
||||
} = AddonTestUtils;
|
||||
|
||||
// Starts the addon manager without creating app info. We can't directly use
|
||||
// |loadAddonManager| defined above in test_conditions.js as it would make the test fail.
|
||||
function startAddonManagerOnly() {
|
||||
let addonManager = Cc["@mozilla.org/addons/integration;1"]
|
||||
.getService(Ci.nsIObserver)
|
||||
.QueryInterface(Ci.nsITimerCallback);
|
||||
addonManager.observe(null, "addons-startup", null);
|
||||
}
|
||||
|
||||
function getExperimentAddons(previous=false) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
AddonManager.getAddonsByTypes(["experiment"], (addons) => {
|
||||
if (previous) {
|
||||
deferred.resolve(addons);
|
||||
} else {
|
||||
deferred.resolve(addons.filter(a => !a.appDisabled));
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function createAppInfo(ID="xpcshell@tests.mozilla.org", name="XPCShell",
|
||||
version="1.0", platformVersion="1.0") {
|
||||
AddonTestUtils.createAppInfo(ID, name, version, platformVersion);
|
||||
gAppInfo = AddonTestUtils.appInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the experiments on an Experiments with a new list.
|
||||
*
|
||||
* This monkeypatches getExperiments(). It doesn't monkeypatch the internal
|
||||
* experiments list. So its utility is not as great as it could be.
|
||||
*/
|
||||
function replaceExperiments(experiment, list) {
|
||||
Object.defineProperty(experiment, "getExperiments", {
|
||||
writable: true,
|
||||
value: () => {
|
||||
return Promise.resolve(list);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Experiments require Telemetry to be enabled, and that's not true for debug
|
||||
// builds. Let's just enable it here instead of going through each test.
|
||||
Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
|
||||
151
browser/experiments/test/xpcshell/test_activate.js
Normal file
151
browser/experiments/test/xpcshell/test_activate.js
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource:///modules/experiments/Experiments.jsm");
|
||||
|
||||
const SEC_IN_ONE_DAY = 24 * 60 * 60;
|
||||
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
|
||||
|
||||
var gHttpServer = null;
|
||||
var gHttpRoot = null;
|
||||
var gPolicy = null;
|
||||
|
||||
function ManifestEntry(data) {
|
||||
this.id = data.id || EXPERIMENT1_ID;
|
||||
this.xpiURL = data.xpiURL || gHttpRoot + EXPERIMENT1_XPI_NAME;
|
||||
this.xpiHash = data.xpiHash || EXPERIMENT1_XPI_SHA1;
|
||||
this.appName = data.appName || ["XPCShell"];
|
||||
this.channel = data.appName || ["nightly"];
|
||||
this.startTime = data.startTime || new Date(2010, 0, 1, 12).getTime() / 1000;
|
||||
this.endTime = data.endTime || new Date(9001, 0, 1, 12).getTime() / 1000;
|
||||
this.maxActiveSeconds = data.maxActiveSeconds || 5 * SEC_IN_ONE_DAY;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_setup() {
|
||||
loadAddonManager();
|
||||
gPolicy = new Experiments.Policy();
|
||||
|
||||
gHttpServer = new HttpServer();
|
||||
gHttpServer.start(-1);
|
||||
let port = gHttpServer.identity.primaryPort;
|
||||
gHttpRoot = "http://localhost:" + port + "/";
|
||||
gHttpServer.registerDirectory("/", do_get_cwd());
|
||||
do_register_cleanup(() => gHttpServer.stop(() => {}));
|
||||
|
||||
patchPolicy(gPolicy, {
|
||||
updatechannel: () => "nightly",
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
|
||||
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
|
||||
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
|
||||
});
|
||||
|
||||
function isApplicable(experiment) {
|
||||
let deferred = Promise.defer();
|
||||
experiment.isApplicable().then(
|
||||
result => deferred.resolve({ applicable: true, reason: null }),
|
||||
reason => deferred.resolve({ applicable: false, reason: reason })
|
||||
);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
add_task(function* test_startStop() {
|
||||
let baseDate = new Date(2014, 5, 1, 12);
|
||||
let startDate = futureDate(baseDate, 30 * MS_IN_ONE_DAY);
|
||||
let endDate = futureDate(baseDate, 60 * MS_IN_ONE_DAY);
|
||||
let manifestData = new ManifestEntry({
|
||||
startTime: dateToSeconds(startDate),
|
||||
endTime: dateToSeconds(endDate),
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
});
|
||||
let experiment = new Experiments.ExperimentEntry(gPolicy);
|
||||
experiment.initFromManifestData(manifestData);
|
||||
|
||||
// We need to associate it with the singleton so the onInstallStarted
|
||||
// Addon Manager listener will know about it.
|
||||
Experiments.instance()._experiments = new Map();
|
||||
Experiments.instance()._experiments.set(experiment.id, experiment);
|
||||
|
||||
let result;
|
||||
|
||||
defineNow(gPolicy, baseDate);
|
||||
result = yield isApplicable(experiment);
|
||||
Assert.equal(result.applicable, false, "Experiment should not be applicable.");
|
||||
Assert.equal(experiment.enabled, false, "Experiment should not be enabled.");
|
||||
|
||||
let addons = yield getExperimentAddons();
|
||||
Assert.equal(addons.length, 0, "No experiment add-ons are installed.");
|
||||
|
||||
defineNow(gPolicy, futureDate(startDate, 5 * MS_IN_ONE_DAY));
|
||||
result = yield isApplicable(experiment);
|
||||
Assert.equal(result.applicable, true, "Experiment should now be applicable.");
|
||||
Assert.equal(experiment.enabled, false, "Experiment should not be enabled.");
|
||||
|
||||
let changes = yield experiment.start();
|
||||
Assert.equal(changes, experiment.ADDON_CHANGE_INSTALL, "Add-on was installed.");
|
||||
addons = yield getExperimentAddons();
|
||||
Assert.equal(experiment.enabled, true, "Experiment should now be enabled.");
|
||||
Assert.equal(addons.length, 1, "1 experiment add-on is installed.");
|
||||
Assert.equal(addons[0].id, experiment._addonId, "The add-on is the one we expect.");
|
||||
Assert.equal(addons[0].userDisabled, false, "The add-on is not userDisabled.");
|
||||
Assert.ok(addons[0].isActive, "The add-on is active.");
|
||||
|
||||
changes = yield experiment.stop();
|
||||
Assert.equal(changes, experiment.ADDON_CHANGE_UNINSTALL, "Add-on was uninstalled.");
|
||||
addons = yield getExperimentAddons();
|
||||
Assert.equal(experiment.enabled, false, "Experiment should not be enabled.");
|
||||
Assert.equal(addons.length, 0, "Experiment should be uninstalled from the Addon Manager.");
|
||||
|
||||
changes = yield experiment.start();
|
||||
Assert.equal(changes, experiment.ADDON_CHANGE_INSTALL, "Add-on was installed.");
|
||||
addons = yield getExperimentAddons();
|
||||
Assert.equal(experiment.enabled, true, "Experiment should now be enabled.");
|
||||
Assert.equal(addons.length, 1, "1 experiment add-on is installed.");
|
||||
Assert.equal(addons[0].id, experiment._addonId, "The add-on is the one we expect.");
|
||||
Assert.equal(addons[0].userDisabled, false, "The add-on is not userDisabled.");
|
||||
Assert.ok(addons[0].isActive, "The add-on is active.");
|
||||
|
||||
result = yield experiment.shouldStop();
|
||||
Assert.equal(result.shouldStop, false, "shouldStop should be false.");
|
||||
Assert.equal(experiment.enabled, true, "Experiment should be enabled.");
|
||||
addons = yield getExperimentAddons();
|
||||
Assert.equal(addons.length, 1, "Experiment still in add-ons manager.");
|
||||
Assert.ok(addons[0].isActive, "The add-on is still active.");
|
||||
|
||||
defineNow(gPolicy, futureDate(endDate, MS_IN_ONE_DAY));
|
||||
result = yield experiment.shouldStop();
|
||||
Assert.equal(result.shouldStop, true, "shouldStop should now be true.");
|
||||
changes = yield experiment.stop();
|
||||
Assert.equal(changes, experiment.ADDON_CHANGE_UNINSTALL, "Add-on should be uninstalled.");
|
||||
Assert.equal(experiment.enabled, false, "Experiment should be disabled.");
|
||||
addons = yield getExperimentAddons();
|
||||
Assert.equal(addons.length, 0, "Experiment add-on is uninstalled.");
|
||||
|
||||
// Ensure hash validation works.
|
||||
// We set an incorrect hash and expect the install to fail.
|
||||
experiment._manifestData.xpiHash = "sha1:41014dcc66b4dcedcd973491a1530a32f0517d8a";
|
||||
let errored = false;
|
||||
try {
|
||||
yield experiment.start();
|
||||
} catch (ex) {
|
||||
errored = true;
|
||||
}
|
||||
Assert.ok(experiment._failedStart, "Experiment failed to start.");
|
||||
Assert.ok(errored, "start() threw an exception.");
|
||||
|
||||
// Make sure "ignore hashes" mode works.
|
||||
gPolicy.ignoreHashes = true;
|
||||
changes = yield experiment.start();
|
||||
Assert.equal(changes, experiment.ADDON_CHANGE_INSTALL);
|
||||
yield experiment.stop();
|
||||
gPolicy.ignoreHashes = false;
|
||||
});
|
||||
1647
browser/experiments/test/xpcshell/test_api.js
Normal file
1647
browser/experiments/test/xpcshell/test_api.js
Normal file
File diff suppressed because it is too large
Load diff
399
browser/experiments/test/xpcshell/test_cache.js
Normal file
399
browser/experiments/test/xpcshell/test_cache.js
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
|
||||
"resource:///modules/experiments/Experiments.jsm");
|
||||
|
||||
const MANIFEST_HANDLER = "manifests/handler";
|
||||
|
||||
const SEC_IN_ONE_DAY = 24 * 60 * 60;
|
||||
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
|
||||
|
||||
var gHttpServer = null;
|
||||
var gHttpRoot = null;
|
||||
var gDataRoot = null;
|
||||
var gPolicy = null;
|
||||
var gManifestObject = null;
|
||||
var gManifestHandlerURI = null;
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_setup() {
|
||||
loadAddonManager();
|
||||
yield removeCacheFile();
|
||||
|
||||
gHttpServer = new HttpServer();
|
||||
gHttpServer.start(-1);
|
||||
let port = gHttpServer.identity.primaryPort;
|
||||
gHttpRoot = "http://localhost:" + port + "/";
|
||||
gDataRoot = gHttpRoot + "data/";
|
||||
gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER;
|
||||
gHttpServer.registerDirectory("/data/", do_get_cwd());
|
||||
gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => {
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
response.write(JSON.stringify(gManifestObject));
|
||||
response.processAsync();
|
||||
response.finish();
|
||||
});
|
||||
do_register_cleanup(() => gHttpServer.stop(() => {}));
|
||||
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
|
||||
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
|
||||
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
|
||||
Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI);
|
||||
Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0);
|
||||
|
||||
gPolicy = new Experiments.Policy();
|
||||
patchPolicy(gPolicy, {
|
||||
updatechannel: () => "nightly",
|
||||
oneshotTimer: (callback, timeout, thisObj, name) => {},
|
||||
});
|
||||
});
|
||||
|
||||
function checkExperimentListsEqual(list, list2) {
|
||||
Assert.equal(list.length, list2.length, "Lists should have the same length.")
|
||||
|
||||
for (let i=0; i<list.length; ++i) {
|
||||
for (let k of Object.keys(list[i])) {
|
||||
Assert.equal(list[i][k], list2[i][k],
|
||||
"Field '" + k + "' should match for list entry " + i + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkExperimentSerializations(experimentEntryIterator) {
|
||||
for (let experiment of experimentEntryIterator) {
|
||||
let experiment2 = new Experiments.ExperimentEntry(gPolicy);
|
||||
let jsonStr = JSON.stringify(experiment.toJSON());
|
||||
Assert.ok(experiment2.initFromCacheData(JSON.parse(jsonStr)),
|
||||
"Should have initialized successfully from JSON serialization.");
|
||||
Assert.equal(JSON.stringify(experiment), JSON.stringify(experiment2),
|
||||
"Object stringifications should match.");
|
||||
}
|
||||
}
|
||||
|
||||
function validateCache(cachedExperiments, experimentIds) {
|
||||
let cachedExperimentIds = new Set(cachedExperiments);
|
||||
Assert.equal(cachedExperimentIds.size, experimentIds.length,
|
||||
"The number of cached experiments does not match with the provided list");
|
||||
for (let id of experimentIds) {
|
||||
Assert.ok(cachedExperimentIds.has(id), "The cache must contain the experiment with id " + id);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up an experiments instance and check if it is properly restored from cache.
|
||||
|
||||
add_task(function* test_cache() {
|
||||
// The manifest data we test with.
|
||||
|
||||
gManifestObject = {
|
||||
"version": 1,
|
||||
experiments: [
|
||||
{
|
||||
id: EXPERIMENT1_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
|
||||
xpiHash: EXPERIMENT1_XPI_SHA1,
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
{
|
||||
id: EXPERIMENT2_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
|
||||
xpiHash: EXPERIMENT2_XPI_SHA1,
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
{
|
||||
id: EXPERIMENT3_ID,
|
||||
xpiURL: "https://inval.id/foo.xpi",
|
||||
xpiHash: "sha1:0000000000000000000000000000000000000000",
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Setup dates for the experiments.
|
||||
|
||||
let baseDate = new Date(2014, 5, 1, 12);
|
||||
let startDates = [];
|
||||
let endDates = [];
|
||||
|
||||
for (let i=0; i<gManifestObject.experiments.length; ++i) {
|
||||
let experiment = gManifestObject.experiments[i];
|
||||
startDates.push(futureDate(baseDate, (50 + (150 * i)) * MS_IN_ONE_DAY));
|
||||
endDates .push(futureDate(startDates[i], 50 * MS_IN_ONE_DAY));
|
||||
experiment.startTime = dateToSeconds(startDates[i]);
|
||||
experiment.endTime = dateToSeconds(endDates[i]);
|
||||
}
|
||||
|
||||
// Data to compare the result of Experiments.getExperiments() against.
|
||||
|
||||
let experimentListData = [
|
||||
{
|
||||
id: EXPERIMENT2_ID,
|
||||
name: "Test experiment 2",
|
||||
description: "And yet another experiment that experiments experimentally.",
|
||||
},
|
||||
{
|
||||
id: EXPERIMENT1_ID,
|
||||
name: EXPERIMENT1_NAME,
|
||||
description: "Yet another experiment that experiments experimentally.",
|
||||
},
|
||||
];
|
||||
|
||||
// Trigger update & re-init, clock set to before any activation.
|
||||
|
||||
let now = baseDate;
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
let experiments = new Experiments.Experiments(gPolicy);
|
||||
yield experiments.updateManifest();
|
||||
let list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 0, "Experiment list should be empty.");
|
||||
checkExperimentSerializations(experiments._experiments.values());
|
||||
|
||||
yield promiseRestartManager();
|
||||
experiments = new Experiments.Experiments(gPolicy);
|
||||
|
||||
yield experiments._run();
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 0, "Experiment list should be empty.");
|
||||
checkExperimentSerializations(experiments._experiments.values());
|
||||
|
||||
// Re-init, clock set for experiment 1 to start.
|
||||
|
||||
now = futureDate(startDates[0], 5 * MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield promiseRestartManager();
|
||||
experiments = new Experiments.Experiments(gPolicy);
|
||||
yield experiments._run();
|
||||
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
|
||||
|
||||
experimentListData[1].active = true;
|
||||
experimentListData[1].endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
|
||||
checkExperimentListsEqual(experimentListData.slice(1), list);
|
||||
checkExperimentSerializations(experiments._experiments.values());
|
||||
|
||||
let branch = yield experiments.getExperimentBranch(EXPERIMENT1_ID);
|
||||
Assert.strictEqual(branch, null);
|
||||
|
||||
yield experiments.setExperimentBranch(EXPERIMENT1_ID, "testbranch");
|
||||
branch = yield experiments.getExperimentBranch(EXPERIMENT1_ID);
|
||||
Assert.strictEqual(branch, "testbranch");
|
||||
|
||||
// Re-init, clock set for experiment 1 to stop.
|
||||
|
||||
now = futureDate(now, 20 * MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield promiseRestartManager();
|
||||
experiments = new Experiments.Experiments(gPolicy);
|
||||
yield experiments._run();
|
||||
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
|
||||
|
||||
experimentListData[1].active = false;
|
||||
experimentListData[1].endDate = now.getTime();
|
||||
checkExperimentListsEqual(experimentListData.slice(1), list);
|
||||
checkExperimentSerializations(experiments._experiments.values());
|
||||
|
||||
branch = yield experiments.getExperimentBranch(EXPERIMENT1_ID);
|
||||
Assert.strictEqual(branch, "testbranch");
|
||||
|
||||
// Re-init, clock set for experiment 2 to start.
|
||||
|
||||
now = futureDate(startDates[1], 20 * MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield promiseRestartManager();
|
||||
experiments = new Experiments.Experiments(gPolicy);
|
||||
yield experiments._run();
|
||||
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 2, "Experiment list should have 2 entries.");
|
||||
|
||||
experimentListData[0].active = true;
|
||||
experimentListData[0].endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
|
||||
checkExperimentListsEqual(experimentListData, list);
|
||||
checkExperimentSerializations(experiments._experiments.values());
|
||||
|
||||
// Re-init, clock set for experiment 2 to stop.
|
||||
|
||||
now = futureDate(now, 20 * MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield promiseRestartManager();
|
||||
experiments = new Experiments.Experiments(gPolicy);
|
||||
yield experiments._run();
|
||||
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 2, "Experiment list should have 2 entries.");
|
||||
|
||||
experimentListData[0].active = false;
|
||||
experimentListData[0].endDate = now.getTime();
|
||||
checkExperimentListsEqual(experimentListData, list);
|
||||
checkExperimentSerializations(experiments._experiments.values());
|
||||
|
||||
// Cleanup.
|
||||
|
||||
yield experiments._toggleExperimentsEnabled(false);
|
||||
yield promiseRestartManager();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
||||
add_task(function* test_expiration() {
|
||||
// The manifest data we test with.
|
||||
gManifestObject = {
|
||||
"version": 1,
|
||||
experiments: [
|
||||
{
|
||||
id: EXPERIMENT1_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
|
||||
xpiHash: EXPERIMENT1_XPI_SHA1,
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
{
|
||||
id: EXPERIMENT2_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
|
||||
xpiHash: EXPERIMENT2_XPI_SHA1,
|
||||
maxActiveSeconds: 50 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
// The 3rd experiment will never run, so it's ok to use experiment's 2 data.
|
||||
{
|
||||
id: EXPERIMENT3_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
|
||||
xpiHash: EXPERIMENT2_XPI_SHA1,
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
// Data to compare the result of Experiments.getExperiments() against.
|
||||
let experimentListData = [
|
||||
{
|
||||
id: EXPERIMENT2_ID,
|
||||
name: "Test experiment 2",
|
||||
description: "And yet another experiment that experiments experimentally.",
|
||||
},
|
||||
{
|
||||
id: EXPERIMENT1_ID,
|
||||
name: EXPERIMENT1_NAME,
|
||||
description: "Yet another experiment that experiments experimentally.",
|
||||
},
|
||||
];
|
||||
|
||||
// Setup dates for the experiments.
|
||||
let baseDate = new Date(2014, 5, 1, 12);
|
||||
let startDates = [];
|
||||
let endDates = [];
|
||||
|
||||
for (let i=0; i<gManifestObject.experiments.length; ++i) {
|
||||
let experiment = gManifestObject.experiments[i];
|
||||
// Spread out experiments in time so that one experiment can end and expire while
|
||||
// the next is still running.
|
||||
startDates.push(futureDate(baseDate, (50 + (200 * i)) * MS_IN_ONE_DAY));
|
||||
endDates .push(futureDate(startDates[i], 50 * MS_IN_ONE_DAY));
|
||||
experiment.startTime = dateToSeconds(startDates[i]);
|
||||
experiment.endTime = dateToSeconds(endDates[i]);
|
||||
}
|
||||
|
||||
let now = null;
|
||||
let experiments = null;
|
||||
|
||||
let setDateAndRestartExperiments = new Task.async(function* (newDate) {
|
||||
now = newDate;
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield promiseRestartManager();
|
||||
experiments = new Experiments.Experiments(gPolicy);
|
||||
yield experiments._run();
|
||||
});
|
||||
|
||||
// Trigger update & re-init, clock set to before any activation.
|
||||
now = baseDate;
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
experiments = new Experiments.Experiments(gPolicy);
|
||||
yield experiments.updateManifest();
|
||||
let list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 0, "Experiment list should be empty.");
|
||||
|
||||
// Re-init, clock set for experiment 1 to start...
|
||||
yield setDateAndRestartExperiments(startDates[0]);
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "The first experiment should have started.");
|
||||
|
||||
// ... init again, and set the clock so that the first experiment ends.
|
||||
yield setDateAndRestartExperiments(endDates[0]);
|
||||
|
||||
// The experiment just ended, it should still be in the cache, but marked
|
||||
// as finished.
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
|
||||
|
||||
experimentListData[1].active = false;
|
||||
experimentListData[1].endDate = now.getTime();
|
||||
checkExperimentListsEqual(experimentListData.slice(1), list);
|
||||
validateCache([...experiments._experiments.keys()], [EXPERIMENT1_ID, EXPERIMENT2_ID, EXPERIMENT3_ID]);
|
||||
|
||||
// Start the second experiment.
|
||||
yield setDateAndRestartExperiments(startDates[1]);
|
||||
|
||||
// The experiments cache should contain the finished experiment and the
|
||||
// one that's still running.
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 2, "Experiment list should have 2 entries.");
|
||||
|
||||
experimentListData[0].active = true;
|
||||
experimentListData[0].endDate = now.getTime() + 50 * MS_IN_ONE_DAY;
|
||||
checkExperimentListsEqual(experimentListData, list);
|
||||
|
||||
// Move the clock in the future, just 31 days after the start date of the second experiment,
|
||||
// so that the cache for the first experiment expires and the second experiment is still running.
|
||||
yield setDateAndRestartExperiments(futureDate(startDates[1], 31 * MS_IN_ONE_DAY));
|
||||
validateCache([...experiments._experiments.keys()], [EXPERIMENT2_ID, EXPERIMENT3_ID]);
|
||||
|
||||
// Make sure that the expired experiment is not reported anymore.
|
||||
let history = yield experiments.getExperiments();
|
||||
Assert.equal(history.length, 1, "Experiments older than 180 days must be removed from the cache.");
|
||||
|
||||
// Test that we don't write expired experiments in the cache.
|
||||
yield setDateAndRestartExperiments(now);
|
||||
validateCache([...experiments._experiments.keys()], [EXPERIMENT2_ID, EXPERIMENT3_ID]);
|
||||
|
||||
// The first experiment should be expired and not in the cache, it ended more than
|
||||
// 180 days ago. We should see the one still running in the cache.
|
||||
history = yield experiments.getExperiments();
|
||||
Assert.equal(history.length, 1, "Expired experiments must not be saved to cache.");
|
||||
checkExperimentListsEqual(experimentListData.slice(0, 1), history);
|
||||
|
||||
// Test that experiments that are cached locally but never ran are removed from cache
|
||||
// when they are removed from the manifest (this is cached data, not really history).
|
||||
gManifestObject["experiments"] = gManifestObject["experiments"].slice(1, 1);
|
||||
yield experiments.updateManifest();
|
||||
validateCache([...experiments._experiments.keys()], [EXPERIMENT2_ID]);
|
||||
|
||||
// Cleanup.
|
||||
yield experiments._toggleExperimentsEnabled(false);
|
||||
yield promiseRestartManager();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
102
browser/experiments/test/xpcshell/test_cacherace.js
Normal file
102
browser/experiments/test/xpcshell/test_cacherace.js
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
const MANIFEST_HANDLER = "manifests/handler";
|
||||
|
||||
const SEC_IN_ONE_DAY = 24 * 60 * 60;
|
||||
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
|
||||
|
||||
var gHttpServer = null;
|
||||
var gHttpRoot = null;
|
||||
var gDataRoot = null;
|
||||
var gPolicy = null;
|
||||
var gManifestObject = null;
|
||||
var gManifestHandlerURI = null;
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_setup() {
|
||||
loadAddonManager();
|
||||
yield removeCacheFile();
|
||||
|
||||
gHttpServer = new HttpServer();
|
||||
gHttpServer.start(-1);
|
||||
let port = gHttpServer.identity.primaryPort;
|
||||
gHttpRoot = "http://localhost:" + port + "/";
|
||||
gDataRoot = gHttpRoot + "data/";
|
||||
gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER;
|
||||
gHttpServer.registerDirectory("/data/", do_get_cwd());
|
||||
gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => {
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
response.write(JSON.stringify(gManifestObject));
|
||||
response.processAsync();
|
||||
response.finish();
|
||||
});
|
||||
do_register_cleanup(() => gHttpServer.stop(() => {}));
|
||||
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
|
||||
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
|
||||
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
|
||||
Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI);
|
||||
Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0);
|
||||
|
||||
let ExperimentsScope = Cu.import("resource:///modules/experiments/Experiments.jsm");
|
||||
let Experiments = ExperimentsScope.Experiments;
|
||||
|
||||
gPolicy = new Experiments.Policy();
|
||||
patchPolicy(gPolicy, {
|
||||
updatechannel: () => "nightly",
|
||||
delayCacheWrite: (promise) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
promise.then(
|
||||
(result) => { setTimeout(() => resolve(result), 500); },
|
||||
(err) => { reject(err); }
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
let now = new Date(2014, 5, 1, 12);
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
let experimentName = "experiment-racybranch.xpi";
|
||||
let experimentPath = getExperimentPath(experimentName);
|
||||
let experimentHash = "sha1:" + sha1File(experimentPath);
|
||||
|
||||
gManifestObject = {
|
||||
version: 1,
|
||||
experiments: [
|
||||
{
|
||||
id: "test-experiment-racybranch@tests.mozilla.org",
|
||||
xpiURL: gDataRoot + "experiment-racybranch.xpi",
|
||||
xpiHash: experimentHash,
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
startTime: dateToSeconds(futureDate(now, -MS_IN_ONE_DAY)),
|
||||
endTime: dateToSeconds(futureDate(now, MS_IN_ONE_DAY)),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
do_print("gManifestObject: " + JSON.stringify(gManifestObject));
|
||||
|
||||
// In order for the addon manager to work properly, we hack
|
||||
// Experiments.instance which is used by the XPIProvider
|
||||
let experiments = new Experiments.Experiments(gPolicy);
|
||||
Assert.strictEqual(ExperimentsScope.gExperiments, null);
|
||||
ExperimentsScope.gExperiments = experiments;
|
||||
|
||||
yield experiments.updateManifest();
|
||||
let active = experiments._getActiveExperiment();
|
||||
Assert.ok(active);
|
||||
Assert.equal(active.branch, "racy-set");
|
||||
Assert.ok(!experiments._dirty);
|
||||
});
|
||||
325
browser/experiments/test/xpcshell/test_conditions.js
Normal file
325
browser/experiments/test/xpcshell/test_conditions.js
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
Cu.import("resource:///modules/experiments/Experiments.jsm");
|
||||
Cu.import("resource://gre/modules/TelemetryController.jsm", this);
|
||||
|
||||
const SEC_IN_ONE_DAY = 24 * 60 * 60;
|
||||
|
||||
var gPolicy = null;
|
||||
|
||||
function ManifestEntry(data) {
|
||||
this.id = EXPERIMENT1_ID;
|
||||
this.xpiURL = "http://localhost:1/dummy.xpi";
|
||||
this.xpiHash = EXPERIMENT1_XPI_SHA1;
|
||||
this.startTime = new Date(2010, 0, 1, 12).getTime() / 1000;
|
||||
this.endTime = new Date(9001, 0, 1, 12).getTime() / 1000;
|
||||
this.maxActiveSeconds = SEC_IN_ONE_DAY;
|
||||
this.appName = ["XPCShell"];
|
||||
this.channel = ["nightly"];
|
||||
|
||||
data = data || {};
|
||||
for (let k of Object.keys(data)) {
|
||||
this[k] = data[k];
|
||||
}
|
||||
|
||||
if (!this.endTime) {
|
||||
this.endTime = this.startTime + 5 * SEC_IN_ONE_DAY;
|
||||
}
|
||||
}
|
||||
|
||||
function applicableFromManifestData(data, policy) {
|
||||
let manifestData = new ManifestEntry(data);
|
||||
let entry = new Experiments.ExperimentEntry(policy);
|
||||
entry.initFromManifestData(manifestData);
|
||||
return entry.isApplicable();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_setup() {
|
||||
createAppInfo();
|
||||
do_get_profile();
|
||||
startAddonManagerOnly();
|
||||
yield TelemetryController.testSetup();
|
||||
gPolicy = new Experiments.Policy();
|
||||
|
||||
patchPolicy(gPolicy, {
|
||||
updatechannel: () => "nightly",
|
||||
locale: () => "en-US",
|
||||
random: () => 0.5,
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
|
||||
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
|
||||
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
|
||||
});
|
||||
|
||||
function arraysEqual(a, b) {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i=0; i<a.length; ++i) {
|
||||
if (a[i] !== b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function exists solely to be .toSource()d
|
||||
const sanityFilter = function filter(c) {
|
||||
if (c.telemetryEnvironment === undefined) {
|
||||
throw Error("No .telemetryEnvironment");
|
||||
}
|
||||
if (c.telemetryEnvironment.build == undefined) {
|
||||
throw Error("No .telemetryEnvironment.build");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Utility function to generate build ID for previous/next date.
|
||||
function addDate(buildId, diff) {
|
||||
let m = /^([0-9]{4})([0-9]{2})([0-9]{2})(.*)$/.exec(buildId);
|
||||
if (!m) {
|
||||
throw Error("Unsupported build ID: " + buildId);
|
||||
}
|
||||
let year = Number.parseInt(m[1], 10);
|
||||
let month = Number.parseInt(m[2], 10);
|
||||
let date = Number.parseInt(m[3], 10);
|
||||
let remainingParts = m[4];
|
||||
|
||||
let d = new Date();
|
||||
d.setUTCFullYear(year, month - 1, date);
|
||||
d.setTime(d.getTime() + diff * 24 * 60 * 60 * 1000);
|
||||
|
||||
let yearStr = String(d.getUTCFullYear());
|
||||
let monthStr = ("0" + String(d.getUTCMonth() + 1)).slice(-2);
|
||||
let dateStr = ("0" + String(d.getUTCDate())).slice(-2);
|
||||
return yearStr + monthStr + dateStr + remainingParts;
|
||||
}
|
||||
function prevDate(buildId) {
|
||||
return addDate(buildId, -1);
|
||||
}
|
||||
function nextDate(buildId) {
|
||||
return addDate(buildId, 1);
|
||||
}
|
||||
|
||||
add_task(function* test_simpleFields() {
|
||||
let testData = [
|
||||
// "expected applicable?", failure reason or null, manifest data
|
||||
|
||||
// misc. environment
|
||||
|
||||
[false, ["appName"], {appName: []}],
|
||||
[false, ["appName"], {appName: ["foo", gAppInfo.name + "-invalid"]}],
|
||||
[true, null, {appName: ["not-an-app-name", gAppInfo.name]}],
|
||||
|
||||
[false, ["os"], {os: []}],
|
||||
[false, ["os"], {os: ["42", "abcdef"]}],
|
||||
[true, null, {os: [gAppInfo.OS, "plan9"]}],
|
||||
|
||||
[false, ["channel"], {channel: []}],
|
||||
[false, ["channel"], {channel: ["foo", gPolicy.updatechannel() + "-invalid"]}],
|
||||
[true, null, {channel: ["not-a-channel", gPolicy.updatechannel()]}],
|
||||
|
||||
[false, ["locale"], {locale: []}],
|
||||
[false, ["locale"], {locale: ["foo", gPolicy.locale + "-invalid"]}],
|
||||
[true, null, {locale: ["not-a-locale", gPolicy.locale()]}],
|
||||
|
||||
// version
|
||||
|
||||
[false, ["version"], {version: []}],
|
||||
[false, ["version"], {version: ["-1", gAppInfo.version + "-invalid", "asdf", "0,4", "99.99", "0.1.1.1"]}],
|
||||
[true, null, {version: ["99999999.999", "-1", gAppInfo.version]}],
|
||||
|
||||
[false, ["minVersion"], {minVersion: "1.0.1"}],
|
||||
[true, null, {minVersion: "1.0b1"}],
|
||||
[true, null, {minVersion: "1.0"}],
|
||||
[true, null, {minVersion: "0.9"}],
|
||||
|
||||
[false, ["maxVersion"], {maxVersion: "0.1"}],
|
||||
[false, ["maxVersion"], {maxVersion: "0.9.9"}],
|
||||
[false, ["maxVersion"], {maxVersion: "1.0b1"}],
|
||||
[true, ["maxVersion"], {maxVersion: "1.0"}],
|
||||
[true, ["maxVersion"], {maxVersion: "1.7pre"}],
|
||||
|
||||
// build id
|
||||
|
||||
[false, ["buildIDs"], {buildIDs: []}],
|
||||
[false, ["buildIDs"], {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID + "-invalid"]}],
|
||||
[true, null, {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID]}],
|
||||
|
||||
[true, null, {minBuildID: prevDate(gAppInfo.platformBuildID)}],
|
||||
[true, null, {minBuildID: gAppInfo.platformBuildID}],
|
||||
[false, ["minBuildID"], {minBuildID: nextDate(gAppInfo.platformBuildID)}],
|
||||
|
||||
[false, ["maxBuildID"], {maxBuildID: prevDate(gAppInfo.platformBuildID)}],
|
||||
[true, null, {maxBuildID: gAppInfo.platformBuildID}],
|
||||
[true, null, {maxBuildID: nextDate(gAppInfo.platformBuildID)}],
|
||||
|
||||
// sample
|
||||
|
||||
[false, ["sample"], {sample: -1 }],
|
||||
[false, ["sample"], {sample: 0.0}],
|
||||
[false, ["sample"], {sample: 0.1}],
|
||||
[true, null, {sample: 0.5}],
|
||||
[true, null, {sample: 0.6}],
|
||||
[true, null, {sample: 1.0}],
|
||||
[true, null, {sample: 0.5}],
|
||||
|
||||
// experiment control
|
||||
|
||||
[false, ["disabled"], {disabled: true}],
|
||||
[true, null, {disabled: false}],
|
||||
|
||||
[false, ["frozen"], {frozen: true}],
|
||||
[true, null, {frozen: false}],
|
||||
|
||||
[false, null, {frozen: true, disabled: true}],
|
||||
[false, null, {frozen: true, disabled: false}],
|
||||
[false, null, {frozen: false, disabled: true}],
|
||||
[true, null, {frozen: false, disabled: false}],
|
||||
|
||||
// jsfilter
|
||||
|
||||
[true, null, {jsfilter: "function filter(c) { return true; }"}],
|
||||
[false, ["jsfilter-false"], {jsfilter: "function filter(c) { return false; }"}],
|
||||
[true, null, {jsfilter: "function filter(c) { return 123; }"}], // truthy
|
||||
[false, ["jsfilter-false"], {jsfilter: "function filter(c) { return ''; }"}], // falsy
|
||||
[false, ["jsfilter-false"], {jsfilter: "function filter(c) { var a = []; }"}], // undefined
|
||||
[false, ["jsfilter-threw", "some error"], {jsfilter: "function filter(c) { throw new Error('some error'); }"}],
|
||||
[false, ["jsfilter-evalfailed"], {jsfilter: "123, this won't work"}],
|
||||
[true, null, {jsfilter: "var filter = " + sanityFilter.toSource()}],
|
||||
];
|
||||
|
||||
for (let i=0; i<testData.length; ++i) {
|
||||
let entry = testData[i];
|
||||
let applicable;
|
||||
let reason = null;
|
||||
|
||||
yield applicableFromManifestData(entry[2], gPolicy).then(
|
||||
value => applicable = value,
|
||||
value => {
|
||||
applicable = false;
|
||||
reason = value;
|
||||
}
|
||||
);
|
||||
|
||||
Assert.equal(applicable, entry[0],
|
||||
"Experiment entry applicability should match for test "
|
||||
+ i + ": " + JSON.stringify(entry[2]));
|
||||
|
||||
let expectedReason = entry[1];
|
||||
if (!applicable && expectedReason) {
|
||||
Assert.ok(arraysEqual(reason, expectedReason),
|
||||
"Experiment rejection reasons should match for test " + i + ". "
|
||||
+ "Got " + JSON.stringify(reason) + ", expected "
|
||||
+ JSON.stringify(expectedReason));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_times() {
|
||||
let now = new Date(2014, 5, 6, 12);
|
||||
let nowSec = now.getTime() / 1000;
|
||||
let testData = [
|
||||
// "expected applicable?", rejection reason or null, fake now date, manifest data
|
||||
|
||||
// start time
|
||||
|
||||
[true, null, now,
|
||||
{startTime: nowSec - 5 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{startTime: nowSec,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[false, "startTime", now,
|
||||
{startTime: nowSec + 5 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
|
||||
// end time
|
||||
|
||||
[false, "endTime", now,
|
||||
{startTime: nowSec - 5 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec - 10 * SEC_IN_ONE_DAY}],
|
||||
[false, "endTime", now,
|
||||
{startTime: nowSec - 5 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec - 5 * SEC_IN_ONE_DAY}],
|
||||
|
||||
// max start time
|
||||
|
||||
[false, "maxStartTime", now,
|
||||
{maxStartTime: nowSec - 15 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[false, "maxStartTime", now,
|
||||
{maxStartTime: nowSec - 1 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[false, "maxStartTime", now,
|
||||
{maxStartTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{maxStartTime: nowSec,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{maxStartTime: nowSec + 1 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
|
||||
// max active seconds
|
||||
|
||||
[true, null, now,
|
||||
{maxActiveSeconds: 5 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{maxActiveSeconds: 15 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
[true, null, now,
|
||||
{maxActiveSeconds: 20 * SEC_IN_ONE_DAY,
|
||||
startTime: nowSec - 10 * SEC_IN_ONE_DAY,
|
||||
endTime: nowSec + 10 * SEC_IN_ONE_DAY}],
|
||||
];
|
||||
|
||||
for (let i=0; i<testData.length; ++i) {
|
||||
let entry = testData[i];
|
||||
let applicable;
|
||||
let reason = null;
|
||||
defineNow(gPolicy, entry[2]);
|
||||
|
||||
yield applicableFromManifestData(entry[3], gPolicy).then(
|
||||
value => applicable = value,
|
||||
value => {
|
||||
applicable = false;
|
||||
reason = value;
|
||||
}
|
||||
);
|
||||
|
||||
Assert.equal(applicable, entry[0],
|
||||
"Experiment entry applicability should match for test "
|
||||
+ i + ": " + JSON.stringify([entry[2], entry[3]]));
|
||||
if (!applicable && entry[1]) {
|
||||
Assert.equal(reason, entry[1], "Experiment rejection reason should match for test " + i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_shutdown() {
|
||||
yield TelemetryController.testShutdown();
|
||||
});
|
||||
180
browser/experiments/test/xpcshell/test_disableExperiments.js
Normal file
180
browser/experiments/test/xpcshell/test_disableExperiments.js
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://testing-common/AddonManagerTesting.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
|
||||
"resource:///modules/experiments/Experiments.jsm");
|
||||
|
||||
const MANIFEST_HANDLER = "manifests/handler";
|
||||
|
||||
const SEC_IN_ONE_DAY = 24 * 60 * 60;
|
||||
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
|
||||
|
||||
var gHttpServer = null;
|
||||
var gHttpRoot = null;
|
||||
var gDataRoot = null;
|
||||
var gPolicy = null;
|
||||
var gManifestObject = null;
|
||||
var gManifestHandlerURI = null;
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_setup() {
|
||||
loadAddonManager();
|
||||
|
||||
gHttpServer = new HttpServer();
|
||||
gHttpServer.start(-1);
|
||||
let port = gHttpServer.identity.primaryPort;
|
||||
gHttpRoot = "http://localhost:" + port + "/";
|
||||
gDataRoot = gHttpRoot + "data/";
|
||||
gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER;
|
||||
gHttpServer.registerDirectory("/data/", do_get_cwd());
|
||||
gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => {
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
response.write(JSON.stringify(gManifestObject));
|
||||
response.processAsync();
|
||||
response.finish();
|
||||
});
|
||||
do_register_cleanup(() => gHttpServer.stop(() => {}));
|
||||
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
|
||||
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
|
||||
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
|
||||
Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI);
|
||||
Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0);
|
||||
|
||||
gPolicy = new Experiments.Policy();
|
||||
patchPolicy(gPolicy, {
|
||||
updatechannel: () => "nightly",
|
||||
oneshotTimer: (callback, timeout, thisObj, name) => {},
|
||||
});
|
||||
});
|
||||
|
||||
// Test disabling the feature stops current and future experiments.
|
||||
|
||||
add_task(function* test_disableExperiments() {
|
||||
const OBSERVER_TOPIC = "experiments-changed";
|
||||
let observerFireCount = 0;
|
||||
let expectedObserverFireCount = 0;
|
||||
let observer = () => ++observerFireCount;
|
||||
Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
|
||||
|
||||
// Dates the following tests are based on.
|
||||
|
||||
let baseDate = new Date(2014, 5, 1, 12);
|
||||
let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY);
|
||||
let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
|
||||
let startDate2 = futureDate(baseDate, 150 * MS_IN_ONE_DAY);
|
||||
let endDate2 = futureDate(baseDate, 200 * MS_IN_ONE_DAY);
|
||||
|
||||
// The manifest data we test with.
|
||||
|
||||
gManifestObject = {
|
||||
"version": 1,
|
||||
experiments: [
|
||||
{
|
||||
id: EXPERIMENT2_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
|
||||
xpiHash: EXPERIMENT2_XPI_SHA1,
|
||||
startTime: dateToSeconds(startDate2),
|
||||
endTime: dateToSeconds(endDate2),
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
{
|
||||
id: EXPERIMENT1_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
|
||||
xpiHash: EXPERIMENT1_XPI_SHA1,
|
||||
startTime: dateToSeconds(startDate1),
|
||||
endTime: dateToSeconds(endDate1),
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let experiments = new Experiments.Experiments(gPolicy);
|
||||
|
||||
// Trigger update, clock set to before any activation.
|
||||
// Use updateManifest() to provide for coverage of that path.
|
||||
|
||||
let now = baseDate;
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield experiments.updateManifest();
|
||||
Assert.equal(observerFireCount, ++expectedObserverFireCount,
|
||||
"Experiments observer should have been called.");
|
||||
let list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 0, "Experiment list should be empty.");
|
||||
let addons = yield getExperimentAddons();
|
||||
Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are installed.");
|
||||
|
||||
// Trigger update, clock set for experiment 1 to start.
|
||||
|
||||
now = futureDate(startDate1, 5 * MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield experiments.updateManifest();
|
||||
Assert.equal(observerFireCount, ++expectedObserverFireCount,
|
||||
"Experiments observer should have been called.");
|
||||
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
|
||||
Assert.equal(list[0].active, true, "Experiment should be active.");
|
||||
addons = yield getExperimentAddons();
|
||||
Assert.equal(addons.length, 1, "An experiment add-on was installed.");
|
||||
|
||||
// Disable the experiments feature. Check that we stop the running experiment.
|
||||
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, false);
|
||||
yield experiments._mainTask;
|
||||
|
||||
Assert.equal(observerFireCount, ++expectedObserverFireCount,
|
||||
"Experiments observer should have been called.");
|
||||
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
|
||||
Assert.equal(list[0].active, false, "Experiment entry should not be active.");
|
||||
addons = yield getExperimentAddons();
|
||||
Assert.equal(addons.length, 0, "The experiment add-on should be uninstalled.");
|
||||
|
||||
// Trigger update, clock set for experiment 2 to start. Verify we don't start it.
|
||||
|
||||
now = startDate2;
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
try {
|
||||
yield experiments.updateManifest();
|
||||
} catch (e) {
|
||||
// This exception is expected, we rethrow everything else
|
||||
if (e.message != "experiments are disabled") {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
experiments.notify();
|
||||
yield experiments._mainTask;
|
||||
|
||||
Assert.equal(observerFireCount, expectedObserverFireCount,
|
||||
"Experiments observer should not have been called.");
|
||||
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "Experiment list should still have 1 entry.");
|
||||
Assert.equal(list[0].active, false, "Experiment entry should not be active.");
|
||||
addons = yield getExperimentAddons();
|
||||
Assert.equal(addons.length, 0, "There should still be no experiment add-on installed.");
|
||||
|
||||
// Cleanup.
|
||||
|
||||
Services.obs.removeObserver(observer, OBSERVER_TOPIC);
|
||||
yield promiseRestartManager();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
68
browser/experiments/test/xpcshell/test_fetch.js
Normal file
68
browser/experiments/test/xpcshell/test_fetch.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource:///modules/experiments/Experiments.jsm");
|
||||
|
||||
var gHttpServer = null;
|
||||
var gHttpRoot = null;
|
||||
var gPolicy = new Experiments.Policy();
|
||||
|
||||
function run_test() {
|
||||
loadAddonManager();
|
||||
|
||||
gHttpServer = new HttpServer();
|
||||
gHttpServer.start(-1);
|
||||
let port = gHttpServer.identity.primaryPort;
|
||||
gHttpRoot = "http://localhost:" + port + "/";
|
||||
gHttpServer.registerDirectory("/", do_get_cwd());
|
||||
do_register_cleanup(() => gHttpServer.stop(() => {}));
|
||||
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
|
||||
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
|
||||
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
|
||||
|
||||
patchPolicy(gPolicy, {
|
||||
updatechannel: () => "nightly",
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_fetchAndCache() {
|
||||
Services.prefs.setCharPref(PREF_MANIFEST_URI, gHttpRoot + "experiments_1.manifest");
|
||||
let ex = new Experiments.Experiments(gPolicy);
|
||||
|
||||
Assert.equal(ex._experiments, null, "There should be no cached experiments yet.");
|
||||
yield ex.updateManifest();
|
||||
Assert.notEqual(ex._experiments.size, 0, "There should be cached experiments now.");
|
||||
|
||||
yield promiseRestartManager();
|
||||
});
|
||||
|
||||
add_task(function* test_checkCache() {
|
||||
let ex = new Experiments.Experiments(gPolicy);
|
||||
yield ex.notify();
|
||||
Assert.notEqual(ex._experiments.size, 0, "There should be cached experiments now.");
|
||||
|
||||
yield promiseRestartManager();
|
||||
});
|
||||
|
||||
add_task(function* test_fetchInvalid() {
|
||||
yield removeCacheFile();
|
||||
|
||||
Services.prefs.setCharPref(PREF_MANIFEST_URI, gHttpRoot + "experiments_1.manifest");
|
||||
let ex = new Experiments.Experiments(gPolicy);
|
||||
yield ex.updateManifest();
|
||||
Assert.notEqual(ex._experiments.size, 0, "There should be experiments");
|
||||
|
||||
Services.prefs.setCharPref(PREF_MANIFEST_URI, gHttpRoot + "invalid.manifest");
|
||||
yield ex.updateManifest()
|
||||
Assert.notEqual(ex._experiments.size, 0, "There should still be experiments: fetch failure shouldn't remove them.");
|
||||
|
||||
yield promiseRestartManager();
|
||||
});
|
||||
47
browser/experiments/test/xpcshell/test_nethang_bug1012924.js
Normal file
47
browser/experiments/test/xpcshell/test_nethang_bug1012924.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource:///modules/experiments/Experiments.jsm");
|
||||
|
||||
const MANIFEST_HANDLER = "manifests/handler";
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_setup() {
|
||||
loadAddonManager();
|
||||
do_get_profile();
|
||||
|
||||
let httpServer = new HttpServer();
|
||||
httpServer.start(-1);
|
||||
let port = httpServer.identity.primaryPort;
|
||||
let httpRoot = "http://localhost:" + port + "/";
|
||||
let handlerURI = httpRoot + MANIFEST_HANDLER;
|
||||
httpServer.registerPathHandler("/" + MANIFEST_HANDLER,
|
||||
(request, response) => {
|
||||
response.processAsync();
|
||||
response.setStatus(null, 200, "OK");
|
||||
response.write("["); // never finish!
|
||||
});
|
||||
|
||||
do_register_cleanup(() => httpServer.stop(() => {}));
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
|
||||
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
|
||||
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
|
||||
Services.prefs.setCharPref(PREF_MANIFEST_URI, handlerURI);
|
||||
Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0);
|
||||
|
||||
let experiments = Experiments.instance();
|
||||
experiments.updateManifest().then(
|
||||
() => {
|
||||
Assert.ok(true, "updateManifest finished successfully");
|
||||
},
|
||||
(e) => {
|
||||
do_throw("updateManifest should not have failed: got error " + e);
|
||||
});
|
||||
yield experiments.uninit();
|
||||
});
|
||||
179
browser/experiments/test/xpcshell/test_previous_provider.js
Normal file
179
browser/experiments/test/xpcshell/test_previous_provider.js
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource:///modules/experiments/Experiments.jsm");
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
|
||||
var gDataRoot;
|
||||
var gHttpServer;
|
||||
var gManifestObject;
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function test_setup() {
|
||||
loadAddonManager();
|
||||
do_get_profile();
|
||||
|
||||
gHttpServer = new HttpServer();
|
||||
gHttpServer.start(-1);
|
||||
let httpRoot = "http://localhost:" + gHttpServer.identity.primaryPort + "/";
|
||||
gDataRoot = httpRoot + "data/";
|
||||
gHttpServer.registerDirectory("/data/", do_get_cwd());
|
||||
gHttpServer.registerPathHandler("/manifests/handler", (req, res) => {
|
||||
res.setStatusLine(null, 200, "OK");
|
||||
res.write(JSON.stringify(gManifestObject));
|
||||
res.processAsync();
|
||||
res.finish();
|
||||
});
|
||||
do_register_cleanup(() => gHttpServer.stop(() => {}));
|
||||
|
||||
Services.prefs.setBoolPref("experiments.enabled", true);
|
||||
Services.prefs.setCharPref("experiments.manifest.uri",
|
||||
httpRoot + "manifests/handler");
|
||||
Services.prefs.setBoolPref("experiments.logging.dump", true);
|
||||
Services.prefs.setCharPref("experiments.logging.level", "Trace");
|
||||
});
|
||||
|
||||
add_task(function* test_provider_basic() {
|
||||
let e = Experiments.instance();
|
||||
|
||||
let provider = new Experiments.PreviousExperimentProvider(e);
|
||||
e._setPreviousExperimentsProvider(provider);
|
||||
|
||||
let deferred = Promise.defer();
|
||||
provider.getAddonsByTypes(["experiment"], (addons) => {
|
||||
deferred.resolve(addons);
|
||||
});
|
||||
let experimentAddons = yield deferred.promise;
|
||||
Assert.ok(Array.isArray(experimentAddons), "getAddonsByTypes returns an Array.");
|
||||
Assert.equal(experimentAddons.length, 0, "No previous add-ons returned.");
|
||||
|
||||
gManifestObject = {
|
||||
version: 1,
|
||||
experiments: [
|
||||
{
|
||||
id: EXPERIMENT1_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
|
||||
xpiHash: EXPERIMENT1_XPI_SHA1,
|
||||
startTime: Date.now() / 1000 - 60,
|
||||
endTime: Date.now() / 1000 + 60,
|
||||
maxActiveSeconds: 60,
|
||||
appName: ["XPCShell"],
|
||||
channel: [e._policy.updatechannel()],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
yield e.updateManifest();
|
||||
|
||||
deferred = Promise.defer();
|
||||
provider.getAddonsByTypes(["experiment"], (addons) => {
|
||||
deferred.resolve(addons);
|
||||
});
|
||||
experimentAddons = yield deferred.promise;
|
||||
Assert.equal(experimentAddons.length, 0, "Still no previous experiment.");
|
||||
|
||||
let experiments = yield e.getExperiments();
|
||||
Assert.equal(experiments.length, 1, "1 experiment present.");
|
||||
Assert.ok(experiments[0].active, "It is active.");
|
||||
|
||||
// Deactivate it.
|
||||
defineNow(e._policy, new Date(gManifestObject.experiments[0].endTime * 1000 + 1000));
|
||||
yield e.updateManifest();
|
||||
|
||||
experiments = yield e.getExperiments();
|
||||
Assert.equal(experiments.length, 1, "1 experiment present.");
|
||||
Assert.equal(experiments[0].active, false, "It isn't active.");
|
||||
|
||||
deferred = Promise.defer();
|
||||
provider.getAddonsByTypes(["experiment"], (addons) => {
|
||||
deferred.resolve(addons);
|
||||
});
|
||||
experimentAddons = yield deferred.promise;
|
||||
Assert.equal(experimentAddons.length, 1, "1 previous add-on known.");
|
||||
Assert.equal(experimentAddons[0].id, EXPERIMENT1_ID, "ID matches expected.");
|
||||
|
||||
deferred = Promise.defer();
|
||||
provider.getAddonByID(EXPERIMENT1_ID, (addon) => {
|
||||
deferred.resolve(addon);
|
||||
});
|
||||
let addon = yield deferred.promise;
|
||||
Assert.ok(addon, "We got an add-on from its ID.");
|
||||
Assert.equal(addon.id, EXPERIMENT1_ID, "ID matches expected.");
|
||||
Assert.ok(addon.appDisabled, "Add-on is a previous experiment.");
|
||||
Assert.ok(addon.userDisabled, "Add-on is disabled.");
|
||||
Assert.equal(addon.type, "experiment", "Add-on is an experiment.");
|
||||
Assert.equal(addon.isActive, false, "Add-on is not active.");
|
||||
Assert.equal(addon.permissions, 0, "Add-on has no permissions.");
|
||||
|
||||
deferred = Promise.defer();
|
||||
AddonManager.getAddonsByTypes(["experiment"], (addons) => {
|
||||
deferred.resolve(addons);
|
||||
});
|
||||
experimentAddons = yield deferred.promise;
|
||||
Assert.equal(experimentAddons.length, 1, "Got 1 experiment from add-on manager.");
|
||||
Assert.equal(experimentAddons[0].id, EXPERIMENT1_ID, "ID matches expected.");
|
||||
Assert.ok(experimentAddons[0].appDisabled, "It is a previous experiment add-on.");
|
||||
});
|
||||
|
||||
add_task(function* test_active_and_previous() {
|
||||
// Building on the previous test, activate experiment 2.
|
||||
let e = Experiments.instance();
|
||||
let provider = new Experiments.PreviousExperimentProvider(e);
|
||||
e._setPreviousExperimentsProvider(provider);
|
||||
|
||||
gManifestObject = {
|
||||
version: 1,
|
||||
experiments: [
|
||||
{
|
||||
id: EXPERIMENT2_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
|
||||
xpiHash: EXPERIMENT2_XPI_SHA1,
|
||||
startTime: Date.now() / 1000 - 60,
|
||||
endTime: Date.now() / 1000 + 60,
|
||||
maxActiveSeconds: 60,
|
||||
appName: ["XPCShell"],
|
||||
channel: [e._policy.updatechannel()],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
defineNow(e._policy, new Date());
|
||||
yield e.updateManifest();
|
||||
|
||||
let experiments = yield e.getExperiments();
|
||||
Assert.equal(experiments.length, 2, "2 experiments known.");
|
||||
|
||||
let deferred = Promise.defer();
|
||||
provider.getAddonsByTypes(["experiment"], (addons) => {
|
||||
deferred.resolve(addons);
|
||||
});
|
||||
let experimentAddons = yield deferred.promise;
|
||||
Assert.equal(experimentAddons.length, 1, "1 previous experiment.");
|
||||
|
||||
deferred = Promise.defer();
|
||||
AddonManager.getAddonsByTypes(["experiment"], (addons) => {
|
||||
deferred.resolve(addons);
|
||||
});
|
||||
experimentAddons = yield deferred.promise;
|
||||
Assert.equal(experimentAddons.length, 2, "2 experiment add-ons known.");
|
||||
|
||||
for (let addon of experimentAddons) {
|
||||
if (addon.id == EXPERIMENT1_ID) {
|
||||
Assert.equal(addon.isActive, false, "Add-on is not active.");
|
||||
Assert.ok(addon.appDisabled, "Should be a previous experiment.");
|
||||
}
|
||||
else if (addon.id == EXPERIMENT2_ID) {
|
||||
Assert.ok(addon.isActive, "Add-on is active.");
|
||||
Assert.ok(!addon.appDisabled, "Should not be a previous experiment.");
|
||||
}
|
||||
else {
|
||||
throw new Error("Unexpected add-on ID: " + addon.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
294
browser/experiments/test/xpcshell/test_telemetry.js
Normal file
294
browser/experiments/test/xpcshell/test_telemetry.js
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/TelemetryLog.jsm");
|
||||
var bsp = Cu.import("resource:///modules/experiments/Experiments.jsm");
|
||||
|
||||
|
||||
const MANIFEST_HANDLER = "manifests/handler";
|
||||
|
||||
const SEC_IN_ONE_DAY = 24 * 60 * 60;
|
||||
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
|
||||
|
||||
|
||||
var gHttpServer = null;
|
||||
var gHttpRoot = null;
|
||||
var gDataRoot = null;
|
||||
var gPolicy = null;
|
||||
var gManifestObject = null;
|
||||
var gManifestHandlerURI = null;
|
||||
|
||||
const TLOG = bsp.TELEMETRY_LOG;
|
||||
|
||||
function checkEvent(event, id, data)
|
||||
{
|
||||
do_print("Checking message " + id);
|
||||
Assert.equal(event[0], id, "id should match");
|
||||
Assert.ok(event[1] > 0, "timestamp should be greater than 0");
|
||||
|
||||
if (data === undefined) {
|
||||
Assert.equal(event.length, 2, "event array should have 2 entries");
|
||||
} else {
|
||||
Assert.equal(event.length, data.length + 2, "event entry count should match expected count");
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
Assert.equal(typeof(event[i + 2]), "string", "event entry should be a string");
|
||||
Assert.equal(event[i + 2], data[i], "event entry should match expected entry");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_setup() {
|
||||
loadAddonManager();
|
||||
|
||||
gHttpServer = new HttpServer();
|
||||
gHttpServer.start(-1);
|
||||
let port = gHttpServer.identity.primaryPort;
|
||||
gHttpRoot = "http://localhost:" + port + "/";
|
||||
gDataRoot = gHttpRoot + "data/";
|
||||
gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER;
|
||||
gHttpServer.registerDirectory("/data/", do_get_cwd());
|
||||
gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => {
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
response.write(JSON.stringify(gManifestObject));
|
||||
response.processAsync();
|
||||
response.finish();
|
||||
});
|
||||
do_register_cleanup(() => gHttpServer.stop(() => {}));
|
||||
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
|
||||
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
|
||||
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
|
||||
Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI);
|
||||
Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0);
|
||||
|
||||
gPolicy = new Experiments.Policy();
|
||||
let dummyTimer = { cancel: () => {}, clear: () => {} };
|
||||
patchPolicy(gPolicy, {
|
||||
updatechannel: () => "nightly",
|
||||
oneshotTimer: (callback, timeout, thisObj, name) => dummyTimer,
|
||||
});
|
||||
|
||||
yield removeCacheFile();
|
||||
});
|
||||
|
||||
// Test basic starting and stopping of experiments.
|
||||
|
||||
add_task(function* test_telemetryBasics() {
|
||||
// Check TelemetryLog instead of TelemetrySession.getPayload().log because
|
||||
// TelemetrySession gets Experiments.instance() and side-effects log entries.
|
||||
|
||||
let expectedLogLength = 0;
|
||||
|
||||
// Dates the following tests are based on.
|
||||
|
||||
let baseDate = new Date(2014, 5, 1, 12);
|
||||
let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY);
|
||||
let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
|
||||
let startDate2 = futureDate(baseDate, 150 * MS_IN_ONE_DAY);
|
||||
let endDate2 = futureDate(baseDate, 200 * MS_IN_ONE_DAY);
|
||||
|
||||
// The manifest data we test with.
|
||||
|
||||
gManifestObject = {
|
||||
"version": 1,
|
||||
experiments: [
|
||||
{
|
||||
id: EXPERIMENT1_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
|
||||
xpiHash: EXPERIMENT1_XPI_SHA1,
|
||||
startTime: dateToSeconds(startDate1),
|
||||
endTime: dateToSeconds(endDate1),
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
{
|
||||
id: EXPERIMENT2_ID,
|
||||
xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
|
||||
xpiHash: EXPERIMENT2_XPI_SHA1,
|
||||
startTime: dateToSeconds(startDate2),
|
||||
endTime: dateToSeconds(endDate2),
|
||||
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
|
||||
appName: ["XPCShell"],
|
||||
channel: ["nightly"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let experiments = new Experiments.Experiments(gPolicy);
|
||||
|
||||
// Trigger update, clock set to before any activation.
|
||||
// Use updateManifest() to provide for coverage of that path.
|
||||
|
||||
let now = baseDate;
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield experiments.updateManifest();
|
||||
let list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 0, "Experiment list should be empty.");
|
||||
|
||||
expectedLogLength += 2;
|
||||
let log = TelemetryLog.entries();
|
||||
do_print("Telemetry log: " + JSON.stringify(log));
|
||||
Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries.");
|
||||
checkEvent(log[log.length-2], TLOG.ACTIVATION_KEY,
|
||||
[TLOG.ACTIVATION.REJECTED, EXPERIMENT1_ID, "startTime"]);
|
||||
checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY,
|
||||
[TLOG.ACTIVATION.REJECTED, EXPERIMENT2_ID, "startTime"]);
|
||||
|
||||
// Trigger update, clock set for experiment 1 to start.
|
||||
|
||||
now = futureDate(startDate1, 5 * MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield experiments.updateManifest();
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
|
||||
|
||||
expectedLogLength += 1;
|
||||
log = TelemetryLog.entries();
|
||||
Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries. Got " + log.toSource());
|
||||
checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY,
|
||||
[TLOG.ACTIVATION.ACTIVATED, EXPERIMENT1_ID]);
|
||||
|
||||
// Trigger update, clock set for experiment 1 to stop.
|
||||
|
||||
now = futureDate(endDate1, 1000);
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield experiments.updateManifest();
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
|
||||
|
||||
expectedLogLength += 2;
|
||||
log = TelemetryLog.entries();
|
||||
Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries.");
|
||||
checkEvent(log[log.length-2], TLOG.TERMINATION_KEY,
|
||||
[TLOG.TERMINATION.EXPIRED, EXPERIMENT1_ID]);
|
||||
checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY,
|
||||
[TLOG.ACTIVATION.REJECTED, EXPERIMENT2_ID, "startTime"]);
|
||||
|
||||
// Trigger update, clock set for experiment 2 to start with invalid hash.
|
||||
|
||||
now = startDate2;
|
||||
defineNow(gPolicy, now);
|
||||
gManifestObject.experiments[1].xpiHash = "sha1:0000000000000000000000000000000000000000";
|
||||
|
||||
yield experiments.updateManifest();
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 1, "Experiment list should have 1 entries.");
|
||||
|
||||
expectedLogLength += 1;
|
||||
log = TelemetryLog.entries();
|
||||
Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries.");
|
||||
checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY,
|
||||
[TLOG.ACTIVATION.INSTALL_FAILURE, EXPERIMENT2_ID]);
|
||||
|
||||
// Trigger update, clock set for experiment 2 to properly start now.
|
||||
|
||||
now = futureDate(now, MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
gManifestObject.experiments[1].xpiHash = EXPERIMENT2_XPI_SHA1;
|
||||
|
||||
yield experiments.updateManifest();
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 2, "Experiment list should have 2 entries.");
|
||||
|
||||
expectedLogLength += 1;
|
||||
log = TelemetryLog.entries();
|
||||
Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries.");
|
||||
checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY,
|
||||
[TLOG.ACTIVATION.ACTIVATED, EXPERIMENT2_ID]);
|
||||
|
||||
// Fake user uninstall of experiment via add-on manager.
|
||||
|
||||
now = futureDate(now, MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield experiments.disableExperiment(TLOG.TERMINATION.ADDON_UNINSTALLED);
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 2, "Experiment list should have 2 entries.");
|
||||
|
||||
expectedLogLength += 1;
|
||||
log = TelemetryLog.entries();
|
||||
Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries.");
|
||||
checkEvent(log[log.length-1], TLOG.TERMINATION_KEY,
|
||||
[TLOG.TERMINATION.ADDON_UNINSTALLED, EXPERIMENT2_ID]);
|
||||
|
||||
// Trigger update with experiment 1a ready to start.
|
||||
|
||||
now = futureDate(now, MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
gManifestObject.experiments[0].id = EXPERIMENT3_ID;
|
||||
gManifestObject.experiments[0].endTime = dateToSeconds(futureDate(now, 50 * MS_IN_ONE_DAY));
|
||||
|
||||
yield experiments.updateManifest();
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 3, "Experiment list should have 3 entries.");
|
||||
|
||||
expectedLogLength += 1;
|
||||
log = TelemetryLog.entries();
|
||||
Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries.");
|
||||
checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY,
|
||||
[TLOG.ACTIVATION.ACTIVATED, EXPERIMENT3_ID]);
|
||||
|
||||
// Trigger disable of an experiment via the API.
|
||||
|
||||
now = futureDate(now, MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
|
||||
yield experiments.disableExperiment(TLOG.TERMINATION.FROM_API);
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 3, "Experiment list should have 3 entries.");
|
||||
|
||||
expectedLogLength += 1;
|
||||
log = TelemetryLog.entries();
|
||||
Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries.");
|
||||
checkEvent(log[log.length-1], TLOG.TERMINATION_KEY,
|
||||
[TLOG.TERMINATION.FROM_API, EXPERIMENT3_ID]);
|
||||
|
||||
// Trigger update with experiment 1a ready to start.
|
||||
|
||||
now = futureDate(now, MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
gManifestObject.experiments[0].id = EXPERIMENT4_ID;
|
||||
gManifestObject.experiments[0].endTime = dateToSeconds(futureDate(now, 50 * MS_IN_ONE_DAY));
|
||||
|
||||
yield experiments.updateManifest();
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 4, "Experiment list should have 4 entries.");
|
||||
|
||||
expectedLogLength += 1;
|
||||
log = TelemetryLog.entries();
|
||||
Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries.");
|
||||
checkEvent(log[log.length-1], TLOG.ACTIVATION_KEY,
|
||||
[TLOG.ACTIVATION.ACTIVATED, EXPERIMENT4_ID]);
|
||||
|
||||
// Trigger experiment termination by something other than expiry via the manifest.
|
||||
|
||||
now = futureDate(now, MS_IN_ONE_DAY);
|
||||
defineNow(gPolicy, now);
|
||||
gManifestObject.experiments[0].os = "Plan9";
|
||||
|
||||
yield experiments.updateManifest();
|
||||
list = yield experiments.getExperiments();
|
||||
Assert.equal(list.length, 4, "Experiment list should have 4 entries.");
|
||||
|
||||
expectedLogLength += 1;
|
||||
log = TelemetryLog.entries();
|
||||
Assert.equal(log.length, expectedLogLength, "Telemetry log should have " + expectedLogLength + " entries.");
|
||||
checkEvent(log[log.length-1], TLOG.TERMINATION_KEY,
|
||||
[TLOG.TERMINATION.RECHECK, EXPERIMENT4_ID, "os"]);
|
||||
|
||||
// Cleanup.
|
||||
|
||||
yield promiseRestartManager();
|
||||
yield removeCacheFile();
|
||||
});
|
||||
21
browser/experiments/test/xpcshell/test_telemetry_disabled.js
Normal file
21
browser/experiments/test/xpcshell/test_telemetry_disabled.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource:///modules/experiments/Experiments.jsm");
|
||||
|
||||
add_test(function test_experiments_activation() {
|
||||
do_get_profile();
|
||||
loadAddonManager();
|
||||
|
||||
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
|
||||
Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, false);
|
||||
|
||||
let experiments = Experiments.instance();
|
||||
Assert.ok(!experiments.enabled, "Experiments must be disabled if Telemetry is disabled.");
|
||||
|
||||
// TODO: Test that Experiments are turned back on when bug 1232648 lands.
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
52
browser/experiments/test/xpcshell/test_upgrade.js
Normal file
52
browser/experiments/test/xpcshell/test_upgrade.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
Cu.import("resource:///modules/experiments/Experiments.jsm");
|
||||
|
||||
var cacheData = {
|
||||
_enabled: true,
|
||||
_manifestData: {
|
||||
id: "foobartestid",
|
||||
xpiURL: "http://example.com/foo.xpi",
|
||||
xpiHash: "sha256:abcde",
|
||||
startTime: 0,
|
||||
endTime: 2000000000,
|
||||
maxActiveSeconds: 40000000,
|
||||
appName: "TestApp",
|
||||
channel: "test-foo",
|
||||
},
|
||||
_needsUpdate: false,
|
||||
_randomValue: 0.5,
|
||||
_failedStart: false,
|
||||
_name: "Foo",
|
||||
_description: "Foobar",
|
||||
_homepageURL: "",
|
||||
_addonId: "foo@test",
|
||||
_startDate: 0,
|
||||
_endDate: 2000000000,
|
||||
_branch: null
|
||||
};
|
||||
|
||||
add_task(function* test_valid() {
|
||||
let e = new Experiments.ExperimentEntry();
|
||||
Assert.ok(e.initFromCacheData(cacheData));
|
||||
Assert.ok(e.enabled);
|
||||
});
|
||||
|
||||
add_task(function* test_upgrade() {
|
||||
let e = new Experiments.ExperimentEntry();
|
||||
delete cacheData._branch;
|
||||
Assert.ok(e.initFromCacheData(cacheData));
|
||||
Assert.ok(e.enabled);
|
||||
});
|
||||
|
||||
add_task(function* test_missing() {
|
||||
let e = new Experiments.ExperimentEntry();
|
||||
delete cacheData._name;
|
||||
Assert.ok(!e.initFromCacheData(cacheData));
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
31
browser/experiments/test/xpcshell/xpcshell.ini
Normal file
31
browser/experiments/test/xpcshell/xpcshell.ini
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
[DEFAULT]
|
||||
head = head.js
|
||||
tail =
|
||||
tags = addons
|
||||
firefox-appdir = browser
|
||||
skip-if = toolkit == 'android'
|
||||
support-files =
|
||||
experiments_1.manifest
|
||||
experiment-1.xpi
|
||||
experiment-1a.xpi
|
||||
experiment-2.xpi
|
||||
experiment-racybranch.xpi
|
||||
!/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
|
||||
generated-files =
|
||||
experiment-1.xpi
|
||||
experiment-1a.xpi
|
||||
experiment-2.xpi
|
||||
experiment-racybranch.xpi
|
||||
|
||||
[test_activate.js]
|
||||
[test_api.js]
|
||||
[test_cache.js]
|
||||
[test_cacherace.js]
|
||||
[test_conditions.js]
|
||||
[test_disableExperiments.js]
|
||||
[test_fetch.js]
|
||||
[test_telemetry.js]
|
||||
[test_telemetry_disabled.js]
|
||||
[test_previous_provider.js]
|
||||
[test_upgrade.js]
|
||||
[test_nethang_bug1012924.js]
|
||||
Loading…
Add table
Add a link
Reference in a new issue