Bug 1234526 - Remove services/healthreport. r=gfritzsche

This commit is contained in:
Alessio Placitelli 2016-01-06 09:07:00 +01:00
parent aa10ab3291
commit d3777d94c4
29 changed files with 7 additions and 5461 deletions

View File

@ -631,10 +631,6 @@
#endif
@RESPATH@/components/servicesComponents.manifest
@RESPATH@/components/cryptoComponents.manifest
#ifdef MOZ_SERVICES_HEALTHREPORT
@RESPATH@/components/HealthReportComponents.manifest
@RESPATH@/components/HealthReportService.js
#endif
@RESPATH@/components/CaptivePortalDetectComponents.manifest
@RESPATH@/components/captivedetect.js
@RESPATH@/components/TelemetryStartup.js

View File

@ -502,7 +502,6 @@
@RESPATH@/components/nsPrompter.manifest
@RESPATH@/components/nsPrompter.js
#ifdef MOZ_SERVICES_HEALTHREPORT
@RESPATH@/components/HealthReportComponents.manifest
@RESPATH@/browser/components/SelfSupportService.manifest
@RESPATH@/browser/components/SelfSupportService.js
#endif

View File

@ -432,11 +432,6 @@
@BINPATH@/components/PeerConnection.manifest
#endif
#ifdef MOZ_SERVICES_HEALTHREPORT
@BINPATH@/components/HealthReportComponents.manifest
@BINPATH@/components/HealthReportService.js
#endif
@BINPATH@/components/CaptivePortalDetectComponents.manifest
@BINPATH@/components/captivedetect.js

View File

@ -7,6 +7,6 @@
#if MOZ_WIDGET_TOOLKIT == android
#include ../../mobile/android/chrome/content/healthreport-prefs.js
#else
#include ../../services/healthreport/healthreport-prefs.js
#include ../../toolkit/components/telemetry/healthreport-prefs.js
#endif
#endif

View File

@ -1,43 +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 = [
"HealthReporter",
"AddonsProvider",
"AppInfoProvider",
"CrashesProvider",
"HealthReportProvider",
"HotfixProvider",
"Metrics",
"PlacesProvider",
"ProfileMetadataProvider",
"SearchesProvider",
"SessionsProvider",
"SysInfoProvider",
];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
// We concatenate the JSMs together to eliminate compartment overhead.
// This is a giant hack until compartment overhead is no longer an
// issue.
#define MERGED_COMPARTMENT
#include ../common/async.js
;
#include ../common/bagheeraclient.js
;
#include ../metrics/Metrics.jsm
;
#include healthreporter.jsm
;
#include profile.jsm
;
#include providers.jsm
;

View File

@ -1,16 +0,0 @@
# Register Firefox Health Report providers.
category healthreport-js-provider-default AddonsProvider resource://gre/modules/HealthReport.jsm
category healthreport-js-provider-default AppInfoProvider resource://gre/modules/HealthReport.jsm
#ifdef MOZ_CRASHREPORTER
category healthreport-js-provider-default CrashesProvider resource://gre/modules/HealthReport.jsm
#endif
category healthreport-js-provider-default HealthReportProvider resource://gre/modules/HealthReport.jsm
category healthreport-js-provider-default HotfixProvider resource://gre/modules/HealthReport.jsm
category healthreport-js-provider-default PlacesProvider resource://gre/modules/HealthReport.jsm
category healthreport-js-provider-default ProfileMetadataProvider resource://gre/modules/HealthReport.jsm
category healthreport-js-provider-default SearchesProvider resource://gre/modules/HealthReport.jsm
category healthreport-js-provider-default SessionsProvider resource://gre/modules/HealthReport.jsm
category healthreport-js-provider-default SysInfoProvider resource://gre/modules/HealthReport.jsm
# No Aurora or Beta providers yet; use the categories
# "healthreport-js-provider-aurora", "healthreport-js-provider-beta".

File diff suppressed because it is too large Load Diff

View File

@ -1,198 +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 = [
"getAppInfo",
"updateAppInfo",
"createFakeCrash",
"InspectedHealthReporter",
"getHealthReporter",
];
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/services-common/utils.js");
Cu.import("resource://gre/modules/services/healthreport/healthreporter.jsm");
Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
var APP_INFO = {
vendor: "Mozilla",
name: "xpcshell",
ID: "xpcshell@tests.mozilla.org",
version: "1",
appBuildID: "20121107",
platformVersion: "p-ver",
platformBuildID: "20121106",
inSafeMode: false,
logConsoleErrors: true,
OS: "XPCShell",
XPCOMABI: "noarch-spidermonkey",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo, Ci.nsIXULRuntime]),
invalidateCachesOnRestart: function() {},
};
/**
* Obtain a reference to the current object used to define XULAppInfo.
*/
this.getAppInfo = function () { return APP_INFO; }
/**
* Update the current application info.
*
* If the argument is defined, it will be the object used. Else, APP_INFO is
* used.
*
* To change the current XULAppInfo, simply call this function. If there was
* a previously registered app info object, it will be unloaded and replaced.
*/
this.updateAppInfo = function (obj) {
obj = obj || APP_INFO;
APP_INFO = obj;
let id = Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}");
let cid = "@mozilla.org/xre/app-info;1";
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
// Unregister an existing factory if one exists.
try {
let existing = Components.manager.getClassObjectByContractID(cid, Ci.nsIFactory);
registrar.unregisterFactory(id, existing);
} catch (ex) {}
let factory = {
createInstance: function (outer, iid) {
if (outer != null) {
throw Cr.NS_ERROR_NO_AGGREGATION;
}
return obj.QueryInterface(iid);
},
};
registrar.registerFactory(id, "XULAppInfo", cid, factory);
};
/**
* Creates a fake crash in the Crash Reports directory.
*
* Currently, we just create a dummy file. A more robust implementation would
* create something that actually resembles a crash report file.
*
* This is very similar to code in crashreporter/tests/browser/head.js.
*
* FUTURE consolidate code in a shared JSM.
*/
this.createFakeCrash = function (submitted=false, date=new Date()) {
let id = CommonUtils.generateUUID();
let filename;
let paths = ["Crash Reports"];
let mode;
if (submitted) {
paths.push("submitted");
filename = "bp-" + id + ".txt";
mode = OS.Constants.libc.S_IRUSR | OS.Constants.libc.S_IWUSR |
OS.Constants.libc.S_IRGRP | OS.Constants.libc.S_IROTH;
} else {
paths.push("pending");
filename = id + ".dmp";
mode = OS.Constants.libc.S_IRUSR | OS.Constants.libc.S_IWUSR;
}
paths.push(filename);
let file = FileUtils.getFile("UAppData", paths, true);
file.create(file.NORMAL_FILE_TYPE, mode);
file.lastModifiedTime = date.getTime();
dump("Created fake crash: " + id + "\n");
return id;
};
/**
* A HealthReporter that is probed with various callbacks and counters.
*
* The purpose of this type is to aid testing of startup and shutdown.
*/
this.InspectedHealthReporter = function (branch, policy, stateLeaf) {
HealthReporter.call(this, branch, policy, stateLeaf);
this.onStorageCreated = null;
this.onProviderManagerInitialized = null;
this.providerManagerShutdownCount = 0;
this.storageCloseCount = 0;
}
InspectedHealthReporter.prototype = {
__proto__: HealthReporter.prototype,
_onStorageCreated: function (storage) {
if (this.onStorageCreated) {
this.onStorageCreated(storage);
}
return HealthReporter.prototype._onStorageCreated.call(this, storage);
},
_initializeProviderManager: Task.async(function* () {
yield HealthReporter.prototype._initializeProviderManager.call(this);
if (this.onInitializeProviderManagerFinished) {
this.onInitializeProviderManagerFinished();
}
}),
_onProviderManagerInitialized: function () {
if (this.onProviderManagerInitialized) {
this.onProviderManagerInitialized();
}
return HealthReporter.prototype._onProviderManagerInitialized.call(this);
},
_onProviderManagerShutdown: function () {
this.providerManagerShutdownCount++;
return HealthReporter.prototype._onProviderManagerShutdown.call(this);
},
_onStorageClose: function () {
this.storageCloseCount++;
return HealthReporter.prototype._onStorageClose.call(this);
},
};
const DUMMY_URI="http://localhost:62013/";
this.getHealthReporter = function (name, uri=DUMMY_URI, inspected=false) {
let branch = "healthreport.testing." + name + ".";
let prefs = new Preferences(branch + "healthreport.");
prefs.set("documentServerURI", uri);
prefs.set("dbName", name);
let reporter;
let policyPrefs = new Preferences(branch + "policy.");
let policy = {};
let type = inspected ? InspectedHealthReporter : HealthReporter;
reporter = new type(branch + "healthreport.", policy,
"state-" + name + ".json");
return reporter;
};

View File

@ -1,27 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
SPHINX_TREES['healthreport'] = 'docs'
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
EXTRA_PP_COMPONENTS += [
'HealthReportComponents.manifest',
]
EXTRA_PP_JS_MODULES += [
'HealthReport.jsm',
]
EXTRA_PP_JS_MODULES.services.healthreport += [
'healthreporter.jsm',
'profile.jsm',
'providers.jsm',
]
TESTING_JS_MODULES.services.healthreport += [
'modules-testing/utils.jsm',
]

View File

@ -1,124 +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/. */
#ifndef MERGED_COMPARTMENT
"use strict";
this.EXPORTED_SYMBOLS = ["ProfileMetadataProvider"];
const {utils: Cu, classes: Cc, interfaces: Ci} = Components;
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
Cu.import("resource://gre/modules/Metrics.jsm");
#endif
const DEFAULT_PROFILE_MEASUREMENT_NAME = "age";
const DEFAULT_PROFILE_MEASUREMENT_VERSION = 2;
const REQUIRED_UINT32_TYPE = {type: "TYPE_UINT32"};
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/osfile.jsm")
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/ProfileAge.jsm");
/**
* Measurements pertaining to the user's profile.
*/
// This is "version 1" of the metadata measurement - it must remain, but
// it's currently unused - see bug 1063714 comment 12 for why.
function ProfileMetadataMeasurement() {
Metrics.Measurement.call(this);
}
ProfileMetadataMeasurement.prototype = {
__proto__: Metrics.Measurement.prototype,
name: DEFAULT_PROFILE_MEASUREMENT_NAME,
version: 1,
fields: {
// Profile creation date. Number of days since Unix epoch.
profileCreation: {type: Metrics.Storage.FIELD_LAST_NUMERIC},
},
};
// This is the current measurement - it adds the profileReset value.
function ProfileMetadataMeasurement2() {
Metrics.Measurement.call(this);
}
ProfileMetadataMeasurement2.prototype = {
__proto__: Metrics.Measurement.prototype,
name: DEFAULT_PROFILE_MEASUREMENT_NAME,
version: DEFAULT_PROFILE_MEASUREMENT_VERSION,
fields: {
// Profile creation date. Number of days since Unix epoch.
profileCreation: {type: Metrics.Storage.FIELD_LAST_NUMERIC},
// Profile reset date. Number of days since Unix epoch.
profileReset: {type: Metrics.Storage.FIELD_LAST_NUMERIC},
},
};
/**
* Turn a millisecond timestamp into a day timestamp.
*
* @param msec a number of milliseconds since epoch.
* @return the number of whole days denoted by the input.
*/
function truncate(msec) {
return Math.floor(msec / MILLISECONDS_PER_DAY);
}
/**
* A Metrics.Provider for profile metadata, such as profile creation and
* reset time.
*/
this.ProfileMetadataProvider = function() {
Metrics.Provider.call(this);
}
this.ProfileMetadataProvider.prototype = {
__proto__: Metrics.Provider.prototype,
name: "org.mozilla.profile",
measurementTypes: [ProfileMetadataMeasurement2],
pullOnly: true,
getProfileDays: Task.async(function* () {
let result = {};
let accessor = new ProfileAge(null, this._log);
let created = yield accessor.created;
result["profileCreation"] = truncate(created);
let reset = yield accessor.reset;
if (reset) {
result["profileReset"] = truncate(reset);
}
return result;
}),
collectConstantData: function () {
let m = this.getMeasurement(DEFAULT_PROFILE_MEASUREMENT_NAME,
DEFAULT_PROFILE_MEASUREMENT_VERSION);
return Task.spawn(function* collectConstants() {
let days = yield this.getProfileDays();
yield this.enqueueStorageOperation(function storeDays() {
return Task.spawn(function* () {
yield m.setLastNumeric("profileCreation", days["profileCreation"]);
if (days["profileReset"]) {
yield m.setLastNumeric("profileReset", days["profileReset"]);
}
});
});
}.bind(this));
},
};

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// We need to initialize the profile or OS.File may not work. See bug 810543.
do_get_profile();
(function initMetricsTestingInfrastructure() {
let ns = {};
Components.utils.import("resource://testing-common/services/common/logging.js",
ns);
ns.initTestLogging();
}).call(this);
(function createAppInfo() {
let ns = {};
Components.utils.import("resource://testing-common/services/healthreport/utils.jsm", ns);
ns.updateAppInfo();
}).call(this);

View File

@ -1,20 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const modules = [
"healthreporter.jsm",
"profile.jsm",
"providers.jsm",
];
function run_test() {
for (let m of modules) {
let resource = "resource://gre/modules/services/healthreport/" + m;
Components.utils.import(resource, {});
}
Components.utils.import("resource://gre/modules/HealthReport.jsm", {});
}

View File

@ -1,258 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var {utils: Cu} = Components;
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
// Create profile directory before use.
// It can be no older than a day ago….
var profile_creation_lower = Date.now() - MILLISECONDS_PER_DAY;
do_get_profile();
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Metrics.jsm");
Cu.import("resource://gre/modules/services/healthreport/profile.jsm");
Cu.import("resource://gre/modules/ProfileAge.jsm");
Cu.import("resource://gre/modules/Task.jsm");
function MockProfileMetadataProvider(name="MockProfileMetadataProvider") {
this.name = name;
ProfileMetadataProvider.call(this);
}
MockProfileMetadataProvider.prototype = {
__proto__: ProfileMetadataProvider.prototype,
includeProfileReset: false,
getProfileDays: function getProfileDays() {
let result = {profileCreation: 1234};
if (this.includeProfileReset) {
result.profileReset = 5678;
}
return Promise.resolve(result);
},
};
function run_test() {
run_next_test();
}
/**
* Ensure that OS.File works in our environment.
* This test can go once there are xpcshell tests for OS.File.
*/
add_test(function use_os_file() {
Cu.import("resource://gre/modules/osfile.jsm")
// Ensure that we get constants, too.
do_check_neq(OS.Constants.Path.profileDir, null);
let iterator = new OS.File.DirectoryIterator(".");
iterator.forEach(function onEntry(entry) {
print("Got " + entry.path);
}).then(function onSuccess() {
iterator.close();
print("Done.");
run_next_test();
}, function onFail() {
iterator.close();
do_throw("Iterating over current directory failed.");
});
});
function getAccessor() {
let acc = new ProfileAge();
print("Profile is " + acc.profilePath);
return acc;
}
add_test(function test_time_accessor_no_file() {
let acc = getAccessor();
// There should be no file yet.
acc.readTimes()
.then(function onSuccess(json) {
do_throw("File existed!");
},
function onFailure() {
run_next_test();
});
});
add_task(function test_time_accessor_named_file() {
let acc = getAccessor();
// There should be no file yet.
yield acc.writeTimes({created: 12345}, "test.json");
let json = yield acc.readTimes("test.json")
print("Read: " + JSON.stringify(json));
do_check_eq(12345, json.created);
});
add_task(function test_time_accessor_creates_file() {
let lower = profile_creation_lower;
// Ensure that provided contents are merged, and existing
// files can be overwritten. These two things occur if we
// read and then decide that we have to write.
let acc = getAccessor();
let existing = {abc: "123", easy: "abc"};
let expected;
let created = yield acc.computeAndPersistCreated(existing, "test2.json")
let upper = Date.now() + 1000;
print(lower + " < " + created + " <= " + upper);
do_check_true(lower < created);
do_check_true(upper >= created);
expected = created;
let json = yield acc.readTimes("test2.json")
print("Read: " + JSON.stringify(json));
do_check_eq("123", json.abc);
do_check_eq("abc", json.easy);
do_check_eq(expected, json.created);
});
add_task(function test_time_accessor_all() {
let lower = profile_creation_lower;
let acc = getAccessor();
let expected;
let created = yield acc.created
let upper = Date.now() + 1000;
do_check_true(lower < created);
do_check_true(upper >= created);
expected = created;
let again = yield acc.created
do_check_eq(expected, again);
});
add_task(function* test_time_reset() {
let lower = profile_creation_lower;
let acc = getAccessor();
let testTime = 100000;
yield acc.recordProfileReset(testTime);
let reset = yield acc.reset;
Assert.equal(reset, testTime);
});
add_test(function test_constructor() {
let provider = new ProfileMetadataProvider("named");
run_next_test();
});
add_test(function test_profile_files() {
let provider = new ProfileMetadataProvider();
function onSuccess(answer) {
let now = Date.now() / MILLISECONDS_PER_DAY;
print("Got " + answer.profileCreation + ", versus now = " + now);
Assert.ok(answer.profileCreation < now);
run_next_test();
}
function onFailure(ex) {
do_throw("Directory iteration failed: " + ex);
}
provider.getProfileDays().then(onSuccess, onFailure);
});
// A generic test helper. We use this with both real
// and mock providers in these tests.
function test_collect_constant(provider, expectReset) {
return Task.spawn(function* () {
yield provider.collectConstantData();
let m = provider.getMeasurement("age", 2);
Assert.notEqual(m, null);
let values = yield m.getValues();
Assert.ok(values.singular.has("profileCreation"));
let createValue = values.singular.get("profileCreation")[1];
let resetValue;
if (expectReset) {
Assert.equal(values.singular.size, 2);
Assert.ok(values.singular.has("profileReset"));
resetValue = values.singular.get("profileReset")[1];
} else {
Assert.equal(values.singular.size, 1);
Assert.ok(!values.singular.has("profileReset"));
}
return [createValue, resetValue];
});
}
add_task(function* test_collect_constant_mock_no_reset() {
let storage = yield Metrics.Storage("collect_constant_mock");
let provider = new MockProfileMetadataProvider();
yield provider.init(storage);
let v = yield test_collect_constant(provider, false);
Assert.equal(v.length, 2);
Assert.equal(v[0], 1234);
Assert.equal(v[1], undefined);
yield storage.close();
});
add_task(function* test_collect_constant_mock_with_reset() {
let storage = yield Metrics.Storage("collect_constant_mock");
let provider = new MockProfileMetadataProvider();
provider.includeProfileReset = true;
yield provider.init(storage);
let v = yield test_collect_constant(provider, true);
Assert.equal(v.length, 2);
Assert.equal(v[0], 1234);
Assert.equal(v[1], 5678);
yield storage.close();
});
add_task(function* test_collect_constant_real_no_reset() {
let provider = new ProfileMetadataProvider();
let storage = yield Metrics.Storage("collect_constant_real");
yield provider.init(storage);
let vals = yield test_collect_constant(provider, false);
let created = vals[0];
let reset = vals[1];
Assert.equal(reset, undefined);
let ms = created * MILLISECONDS_PER_DAY;
let lower = profile_creation_lower;
let upper = Date.now() + 1000;
print("Day: " + created);
print("msec: " + ms);
print("Lower: " + lower);
print("Upper: " + upper);
Assert.ok(lower <= ms);
Assert.ok(upper >= ms);
yield storage.close();
});
add_task(function* test_collect_constant_real_with_reset() {
let now = Date.now();
let acc = getAccessor();
yield acc.writeTimes({created: now-MILLISECONDS_PER_DAY, // yesterday
reset: Date.now()}); // today
let provider = new ProfileMetadataProvider();
let storage = yield Metrics.Storage("collect_constant_real");
yield provider.init(storage);
let [created, reset] = yield test_collect_constant(provider, true);
// we've already tested truncate() works as expected, so here just check
// we got values.
Assert.ok(created);
Assert.ok(reset);
Assert.ok(created <= reset);
yield storage.close();
});

View File

@ -1,339 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var {utils: Cu, classes: Cc, interfaces: Ci} = Components;
Cu.import("resource://gre/modules/Metrics.jsm");
Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
// The hack, it burns. This could go away if extensions code exposed its
// test environment setup functions as a testing-only JSM. See similar
// code in Sync's head_helpers.js.
var gGlobalScope = this;
function loadAddonManager() {
let ns = {};
Cu.import("resource://gre/modules/Services.jsm", ns);
let head = "../../../../toolkit/mozapps/extensions/test/xpcshell/head_addons.js";
let file = do_get_file(head);
let uri = ns.Services.io.newFileURI(file);
ns.Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
startupManager();
}
function run_test() {
loadAddonManager();
run_next_test();
}
add_test(function test_constructor() {
let provider = new AddonsProvider();
run_next_test();
});
add_task(function test_init() {
let storage = yield Metrics.Storage("init");
let provider = new AddonsProvider();
yield provider.init(storage);
yield provider.shutdown();
yield storage.close();
});
function monkeypatchAddons(provider, addons) {
if (!Array.isArray(addons)) {
throw new Error("Must define array of addon objects.");
}
Object.defineProperty(provider, "_createDataStructure", {
value: function _createDataStructure() {
return AddonsProvider.prototype._createDataStructure.call(provider, addons);
},
});
}
add_task(function test_collect() {
let storage = yield Metrics.Storage("collect");
let provider = new AddonsProvider();
yield provider.init(storage);
let now = new Date();
// FUTURE install add-on via AddonManager and don't use monkeypatching.
let testAddons = [
{
id: "addon0",
userDisabled: false,
appDisabled: false,
version: "1",
type: "extension",
scope: 1,
foreignInstall: false,
hasBinaryComponents: false,
installDate: now,
updateDate: now,
},
// This plugin entry should get ignored.
{
id: "addon1",
userDisabled: false,
appDisabled: false,
version: "2",
type: "plugin",
scope: 1,
foreignInstall: false,
hasBinaryComponents: false,
installDate: now,
updateDate: now,
},
// Is counted but full details are omitted because it is a theme.
{
id: "addon2",
userDisabled: false,
appDisabled: false,
version: "3",
type: "theme",
scope: 1,
foreignInstall: false,
hasBinaryComponents: false,
installDate: now,
updateDate: now,
},
{
id: "addon3",
userDisabled: false,
appDisabled: false,
version: "4",
type: "service",
scope: 1,
foreignInstall: false,
hasBinaryComponents: false,
installDate: now,
updateDate: now,
description: "addon3 description"
},
{
// Should be excluded from the report completely
id: "pluginfake",
type: "plugin",
userDisabled: false,
appDisabled: false,
},
{
// Should be in gm-plugins
id: "gmp-testgmp",
type: "plugin",
userDisabled: false,
version: "7.2",
isGMPlugin: true,
},
];
monkeypatchAddons(provider, testAddons);
let testPlugins = {
"Test Plug-in":
{
"version": "1.0.0.0",
"description": "Plug-in for testing purposes.™ (हिन्दी 中文 العربية)",
"blocklisted": false,
"disabled": false,
"clicktoplay": false,
"mimeTypes":[
"application/x-test"
],
},
"Second Test Plug-in":
{
"version": "1.0.0.0",
"description": "Second plug-in for testing purposes.",
"blocklisted": false,
"disabled": false,
"clicktoplay": false,
"mimeTypes":[
"application/x-second-test"
],
},
"Java Test Plug-in":
{
"version": "1.0.0.0",
"description": "Dummy Java plug-in for testing purposes.",
"blocklisted": false,
"disabled": false,
"clicktoplay": false,
"mimeTypes":[
"application/x-java-test"
],
},
"Third Test Plug-in":
{
"version": "1.0.0.0",
"description": "Third plug-in for testing purposes.",
"blocklisted": false,
"disabled": false,
"clicktoplay": false,
"mimeTypes":[
"application/x-third-test"
],
},
"Flash Test Plug-in":
{
"version": "1.0.0.0",
"description": "Flash plug-in for testing purposes.",
"blocklisted": false,
"disabled": false,
"clicktoplay": false,
"mimeTypes":[
"application/x-shockwave-flash-test"
],
},
"Silverlight Test Plug-in":
{
"version": "1.0.0.0",
"description": "Silverlight plug-in for testing purposes.",
"blocklisted": false,
"disabled": false,
"clicktoplay": false,
"mimeTypes":[
"application/x-silverlight-test"
],
},
};
let pluginTags = Cc["@mozilla.org/plugin/host;1"]
.getService(Ci.nsIPluginHost)
.getPluginTags({});
for (let tag of pluginTags) {
if (tag.name in testPlugins) {
let p = testPlugins[tag.name];
p.id = tag.filename+":"+tag.name+":"+p.version+":"+p.description;
}
}
yield provider.collectConstantData();
// Test addons measurement.
let addons = provider.getMeasurement("addons", 2);
let data = yield addons.getValues();
do_check_eq(data.days.size, 0);
do_check_eq(data.singular.size, 1);
do_check_true(data.singular.has("addons"));
let json = data.singular.get("addons")[1];
let value = JSON.parse(json);
do_check_eq(typeof(value), "object");
do_check_eq(Object.keys(value).length, 2);
do_check_true("addon0" in value);
do_check_true(!("addon1" in value));
do_check_true(!("addon2" in value));
do_check_true("addon3" in value);
do_check_true(!("pluginfake" in value));
do_check_true(!("gmp-testgmp" in value));
let serializer = addons.serializer(addons.SERIALIZE_JSON);
let serialized = serializer.singular(data.singular);
do_check_eq(typeof(serialized), "object");
do_check_eq(Object.keys(serialized).length, 3); // Our entries, plus _v.
do_check_true("addon0" in serialized);
do_check_true("addon3" in serialized);
do_check_eq(serialized._v, 2);
// Test plugins measurement.
let plugins = provider.getMeasurement("plugins", 1);
data = yield plugins.getValues();
do_check_eq(data.days.size, 0);
do_check_eq(data.singular.size, 1);
do_check_true(data.singular.has("plugins"));
json = data.singular.get("plugins")[1];
value = JSON.parse(json);
do_check_eq(typeof(value), "object");
do_check_eq(Object.keys(value).length, pluginTags.length);
do_check_true(testPlugins["Test Plug-in"].id in value);
do_check_true(testPlugins["Second Test Plug-in"].id in value);
do_check_true(testPlugins["Java Test Plug-in"].id in value);
for (let id in value) {
let item = value[id];
let testData = testPlugins[item.name];
for (let prop in testData) {
if (prop == "mimeTypes" || prop == "id") {
continue;
}
do_check_eq(testData[prop], item[prop]);
}
for (let mime of testData.mimeTypes) {
do_check_true(item.mimeTypes.indexOf(mime) != -1);
}
}
serializer = plugins.serializer(plugins.SERIALIZE_JSON);
serialized = serializer.singular(data.singular);
do_check_eq(typeof(serialized), "object");
do_check_eq(Object.keys(serialized).length, pluginTags.length+1); // Our entries, plus _v.
for (let name in testPlugins) {
// Special case for bug 1165981. There is a test plugin that
// exists to make sure we don't load it on certain platforms.
// We skip the check for that plugin here, as it will work on some
// platforms but not others.
if (name == "Third Test Plug-in") {
continue;
}
do_check_true(testPlugins[name].id in serialized);
}
do_check_eq(serialized._v, 1);
// Test GMP plugins measurement.
let gmPlugins = provider.getMeasurement("gm-plugins", 1);
data = yield gmPlugins.getValues();
do_check_eq(data.days.size, 0);
do_check_eq(data.singular.size, 1);
do_check_true(data.singular.has("gm-plugins"));
json = data.singular.get("gm-plugins")[1];
value = JSON.parse(json);
do_print("value: " + json);
do_check_eq(typeof(value), "object");
do_check_eq(Object.keys(value).length, 1);
do_check_eq(value["gmp-testgmp"].version, "7.2");
do_check_eq(value["gmp-testgmp"].userDisabled, false);
serializer = gmPlugins.serializer(plugins.SERIALIZE_JSON);
serialized = serializer.singular(data.singular);
do_check_eq(typeof(serialized), "object");
do_check_eq(serialized["gmp-testgmp"].version, "7.2");
do_check_eq(serialized._v, 1);
// Test counts measurement.
let counts = provider.getMeasurement("counts", 2);
data = yield counts.getValues();
do_check_eq(data.days.size, 1);
do_check_eq(data.singular.size, 0);
do_check_true(data.days.hasDay(now));
value = data.days.getDay(now);
do_check_eq(value.size, 4);
do_check_eq(value.get("extension"), 1);
do_check_eq(value.get("plugin"), pluginTags.length);
do_check_eq(value.get("theme"), 1);
do_check_eq(value.get("service"), 1);
yield provider.shutdown();
yield storage.close();
});

View File

@ -1,270 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var {interfaces: Ci, results: Cr, utils: Cu, classes: Cc} = Components;
Cu.import("resource://gre/modules/Metrics.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
Cu.import("resource://testing-common/services/healthreport/utils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function run_test() {
do_get_profile();
run_next_test();
}
add_test(function test_constructor() {
let provider = new AppInfoProvider();
run_next_test();
});
add_task(function test_collect_smoketest() {
let storage = yield Metrics.Storage("collect_smoketest");
let provider = new AppInfoProvider();
yield provider.init(storage);
let now = new Date();
yield provider.collectConstantData();
let m = provider.getMeasurement("appinfo", 2);
let data = yield storage.getMeasurementValues(m.id);
let serializer = m.serializer(m.SERIALIZE_JSON);
let d = serializer.singular(data.singular);
do_check_eq(d._v, 2);
do_check_eq(d.vendor, "Mozilla");
do_check_eq(d.name, "xpcshell");
do_check_eq(d.id, "xpcshell@tests.mozilla.org");
do_check_eq(d.version, "1");
do_check_eq(d.appBuildID, "20121107");
do_check_eq(d.platformVersion, "p-ver");
do_check_eq(d.platformBuildID, "20121106");
do_check_eq(d.os, "XPCShell");
do_check_eq(d.xpcomabi, "noarch-spidermonkey");
do_check_eq(data.days.size, 1);
do_check_true(data.days.hasDay(now));
let day = data.days.getDay(now);
do_check_eq(day.size, 3);
do_check_true(day.has("isDefaultBrowser"));
do_check_true(day.has("isTelemetryEnabled"));
do_check_true(day.has("isBlocklistEnabled"));
// TODO Bug 827189 Actually test this properly. On some local builds, this
// is always -1 (the service throws). On buildbot, it seems to always be 0.
do_check_neq(day.get("isDefaultBrowser"), 1);
yield provider.shutdown();
yield storage.close();
});
add_task(function test_record_version() {
let storage = yield Metrics.Storage("record_version");
let provider = new AppInfoProvider();
let now = new Date();
yield provider.init(storage);
// The provider records information on startup.
let m = provider.getMeasurement("versions", 2);
let data = yield m.getValues();
do_check_true(data.days.hasDay(now));
let day = data.days.getDay(now);
do_check_eq(day.size, 4);
do_check_true(day.has("appVersion"));
do_check_true(day.has("platformVersion"));
do_check_true(day.has("appBuildID"));
do_check_true(day.has("platformBuildID"));
let value = day.get("appVersion");
do_check_true(Array.isArray(value));
do_check_eq(value.length, 1);
let ai = getAppInfo();
do_check_eq(value[0], ai.version);
value = day.get("platformVersion");
do_check_true(Array.isArray(value));
do_check_eq(value.length, 1);
do_check_eq(value[0], ai.platformVersion);
value = day.get("appBuildID");
do_check_true(Array.isArray(value));
do_check_eq(value.length, 1);
do_check_eq(value[0], ai.appBuildID);
value = day.get("platformBuildID");
do_check_true(Array.isArray(value));
do_check_eq(value.length, 1);
do_check_eq(value[0], ai.platformBuildID);
yield provider.shutdown();
yield storage.close();
});
add_task(function test_record_version_change() {
let storage = yield Metrics.Storage("record_version_change");
let provider = new AppInfoProvider();
let now = new Date();
yield provider.init(storage);
yield provider.shutdown();
let ai = getAppInfo();
ai.version = "new app version";
ai.platformVersion = "new platform version";
ai.appBuildID = "new app id";
ai.platformBuildID = "new platform id";
updateAppInfo(ai);
provider = new AppInfoProvider();
yield provider.init(storage);
// There should be 2 records in the versions history.
let m = provider.getMeasurement("versions", 2);
let data = yield m.getValues();
do_check_true(data.days.hasDay(now));
let day = data.days.getDay(now);
let value = day.get("appVersion");
do_check_true(Array.isArray(value));
do_check_eq(value.length, 2);
do_check_eq(value[1], "new app version");
value = day.get("platformVersion");
do_check_true(Array.isArray(value));
do_check_eq(value.length, 2);
do_check_eq(value[1], "new platform version");
// There should be 2 records in the buildID history.
value = day.get("appBuildID");
do_check_true(Array.isArray(value));
do_check_eq(value.length, 2);
do_check_eq(value[1], "new app id");
value = day.get("platformBuildID");
do_check_true(Array.isArray(value));
do_check_eq(value.length, 2);
do_check_eq(value[1], "new platform id");
yield provider.shutdown();
yield storage.close();
});
add_task(function test_record_telemetry() {
let storage = yield Metrics.Storage("record_telemetry");
let provider;
let now = new Date();
Services.prefs.setBoolPref("toolkit.telemetry.enabled", true);
provider = new AppInfoProvider();
yield provider.init(storage);
yield provider.collectConstantData();
let m = provider.getMeasurement("appinfo", 2);
let data = yield m.getValues();
let d = yield m.serializer(m.SERIALIZE_JSON).daily(data.days.getDay(now));
do_check_eq(1, d.isTelemetryEnabled);
yield provider.shutdown();
Services.prefs.setBoolPref("toolkit.telemetry.enabled", false);
provider = new AppInfoProvider();
yield provider.init(storage);
yield provider.collectConstantData();
m = provider.getMeasurement("appinfo", 2);
data = yield m.getValues();
d = yield m.serializer(m.SERIALIZE_JSON).daily(data.days.getDay(now));
do_check_eq(0, d.isTelemetryEnabled);
yield provider.shutdown();
yield storage.close();
});
add_task(function test_record_blocklist() {
let storage = yield Metrics.Storage("record_blocklist");
let now = new Date();
Services.prefs.setBoolPref("extensions.blocklist.enabled", true);
let provider = new AppInfoProvider();
yield provider.init(storage);
yield provider.collectConstantData();
let m = provider.getMeasurement("appinfo", 2);
let data = yield m.getValues();
let d = yield m.serializer(m.SERIALIZE_JSON).daily(data.days.getDay(now));
do_check_eq(d.isBlocklistEnabled, 1);
yield provider.shutdown();
Services.prefs.setBoolPref("extensions.blocklist.enabled", false);
provider = new AppInfoProvider();
yield provider.init(storage);
yield provider.collectConstantData();
m = provider.getMeasurement("appinfo", 2);
data = yield m.getValues();
d = yield m.serializer(m.SERIALIZE_JSON).daily(data.days.getDay(now));
do_check_eq(d.isBlocklistEnabled, 0);
yield provider.shutdown();
yield storage.close();
});
add_task(function test_record_app_update () {
let storage = yield Metrics.Storage("record_update");
Services.prefs.setBoolPref("app.update.enabled", true);
Services.prefs.setBoolPref("app.update.auto", true);
let provider = new AppInfoProvider();
yield provider.init(storage);
let now = new Date();
yield provider.collectDailyData();
let m = provider.getMeasurement("update", 1);
let data = yield m.getValues();
let d = yield m.serializer(m.SERIALIZE_JSON).daily(data.days.getDay(now));
do_check_eq(d.enabled, 1);
do_check_eq(d.autoDownload, 1);
Services.prefs.setBoolPref("app.update.enabled", false);
Services.prefs.setBoolPref("app.update.auto", false);
yield provider.collectDailyData();
data = yield m.getValues();
d = yield m.serializer(m.SERIALIZE_JSON).daily(data.days.getDay(now));
do_check_eq(d.enabled, 0);
do_check_eq(d.autoDownload, 0);
yield provider.shutdown();
yield storage.close();
});
add_task(function test_healthreporter_integration () {
let reporter = getHealthReporter("healthreporter_integration");
yield reporter.init();
try {
yield reporter._providerManager.registerProviderFromType(AppInfoProvider);
yield reporter.collectMeasurements();
let payload = yield reporter.getJSONPayload(true);
let days = payload['data']['days'];
for (let [day, measurements] in Iterator(days)) {
do_check_eq(Object.keys(measurements).length, 3);
do_check_true("org.mozilla.appInfo.appinfo" in measurements);
do_check_true("org.mozilla.appInfo.update" in measurements);
do_check_true("org.mozilla.appInfo.versions" in measurements);
}
} finally {
yield reporter._shutdown();
}
});

View File

@ -1,137 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var {utils: Cu} = Components;
Cu.import("resource://gre/modules/Metrics.jsm");
Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
Cu.import("resource://testing-common/AppData.jsm");
Cu.import("resource://testing-common/services/healthreport/utils.jsm");
Cu.import("resource://testing-common/CrashManagerTest.jsm");
function run_test() {
run_next_test();
}
add_task(function* init() {
do_get_profile();
yield makeFakeAppDir();
});
add_task(function test_constructor() {
let provider = new CrashesProvider();
});
add_task(function* test_init() {
let storage = yield Metrics.Storage("init");
let provider = new CrashesProvider();
yield provider.init(storage);
yield provider.shutdown();
yield storage.close();
});
add_task(function* test_collect() {
let storage = yield Metrics.Storage("collect");
let provider = new CrashesProvider();
yield provider.init(storage);
// Install custom manager so we don't interfere with other tests.
let manager = yield getManager();
provider._manager = manager;
let day1 = new Date(2014, 0, 1, 0, 0, 0);
let day2 = new Date(2014, 0, 3, 0, 0, 0);
yield manager.addCrash(manager.PROCESS_TYPE_MAIN,
manager.CRASH_TYPE_CRASH,
"mc1", day1, { OOMAllocationSize: 1073741824 });
yield manager.addCrash(manager.PROCESS_TYPE_MAIN,
manager.CRASH_TYPE_CRASH,
"mc2", day1);
yield manager.addCrash(manager.PROCESS_TYPE_CONTENT,
manager.CRASH_TYPE_HANG,
"ch", day1);
yield manager.addCrash(manager.PROCESS_TYPE_PLUGIN,
manager.CRASH_TYPE_CRASH,
"pc", day1);
yield manager.addSubmissionAttempt("mc1", "sub1", day1);
yield manager.addSubmissionResult("mc1", "sub1", day1,
manager.SUBMISSION_RESULT_OK);
yield manager.addSubmissionAttempt("ch", "sub1", day1);
yield manager.addSubmissionResult("ch", "sub1", day1,
manager.SUBMISSION_RESULT_FAILED);
yield manager.addSubmissionAttempt("ch", "sub2", day1);
yield manager.addSubmissionResult("ch", "sub2", day1,
manager.SUBMISSION_RESULT_FAILED);
yield manager.addSubmissionAttempt("ch", "sub3", day1);
yield manager.addSubmissionResult("ch", "sub3", day1,
manager.SUBMISSION_RESULT_OK);
yield manager.addCrash(manager.PROCESS_TYPE_MAIN,
manager.CRASH_TYPE_HANG,
"mh", day2);
yield manager.addCrash(manager.PROCESS_TYPE_CONTENT,
manager.CRASH_TYPE_CRASH,
"cc", day2);
yield manager.addCrash(manager.PROCESS_TYPE_PLUGIN,
manager.CRASH_TYPE_HANG,
"ph", day2);
yield manager.addCrash(manager.PROCESS_TYPE_GMPLUGIN,
manager.CRASH_TYPE_CRASH,
"gmpc", day2);
yield provider.collectDailyData();
let m = provider.getMeasurement("crashes", 6);
let values = yield m.getValues();
do_check_eq(values.days.size, 2);
do_check_true(values.days.hasDay(day1));
do_check_true(values.days.hasDay(day2));
let value = values.days.getDay(day1);
do_check_true(value.has("main-crash"));
do_check_eq(value.get("main-crash"), 2);
do_check_true(value.has("main-crash-oom"));
do_check_eq(value.get("main-crash-oom"), 1);
do_check_true(value.has("content-hang"));
do_check_eq(value.get("content-hang"), 1);
do_check_true(value.has("plugin-crash"));
do_check_eq(value.get("plugin-crash"), 1);
do_check_true(value.has("main-crash-submission-succeeded"));
do_check_eq(value.get("main-crash-submission-succeeded"), 1);
do_check_true(value.has("content-hang-submission-failed"));
do_check_eq(value.get("content-hang-submission-failed"), 2);
do_check_true(value.has("content-hang-submission-succeeded"));
do_check_eq(value.get("content-hang-submission-succeeded"), 1);
value = values.days.getDay(day2);
do_check_true(value.has("main-hang"));
do_check_eq(value.get("main-hang"), 1);
do_check_true(value.has("content-crash"));
do_check_eq(value.get("content-crash"), 1);
do_check_true(value.has("plugin-hang"));
do_check_eq(value.get("plugin-hang"), 1);
do_check_true(value.has("gmplugin-crash"));
do_check_eq(value.get("gmplugin-crash"), 1);
// Check that adding a new crash increments counter on next collect.
yield manager.addCrash(manager.PROCESS_TYPE_MAIN,
manager.CRASH_TYPE_HANG,
"mc3", day2);
yield provider.collectDailyData();
values = yield m.getValues();
value = values.days.getDay(day2);
do_check_eq(value.get("main-hang"), 2);
yield provider.shutdown();
yield storage.close();
});

View File

@ -1,179 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var {utils: Cu} = Components;
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/Metrics.jsm");
Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
const EXAMPLE_2014052701 = {
"upgradedFrom":"13.0.1",
"uninstallReason":"SUCCESSFUL_UPGRADE",
"_entityID":null,
"forensicsID":"29525548-b653-49db-bfb8-a160cdfbeb4a",
"_installInProgress":false,
"_everCompatible":true,
"reportedWindowsVersion":[6,1,1],
"actualWindowsVersion":[6,1,1],
"firstNotifyDay":0,
"lastNotifyDay":0,
"downloadAttempts":1,
"downloadFailures":0,
"installAttempts":1,
"installSuccesses":1,
"installLauncherFailures":0,
"installFailures":0,
"notificationsShown":0,
"notificationsClicked":0,
"notificationsDismissed":0,
"notificationsRemoved":0,
"launcherExitCodes":{"0":1}
};
function run_test() {
run_next_test();
}
add_task(function* init() {
do_get_profile();
});
add_task(function test_constructor() {
new HotfixProvider();
});
add_task(function* test_init() {
let storage = yield Metrics.Storage("init");
let provider = new HotfixProvider();
yield provider.init(storage);
yield provider.shutdown();
yield storage.close();
});
add_task(function* test_collect_empty() {
let storage = yield Metrics.Storage("collect_empty");
let provider = new HotfixProvider();
yield provider.init(storage);
yield provider.collectDailyData();
let m = provider.getMeasurement("update", 1);
let data = yield m.getValues();
Assert.equal(data.singular.size, 0);
Assert.equal(data.days.size, 0);
yield storage.close();
});
add_task(function* test_collect_20140527() {
let storage = yield Metrics.Storage("collect_20140527");
let provider = new HotfixProvider();
yield provider.init(storage);
let path = OS.Path.join(OS.Constants.Path.profileDir,
"hotfix.v20140527.01.json");
let encoder = new TextEncoder();
yield OS.File.writeAtomic(path,
encoder.encode(JSON.stringify(EXAMPLE_2014052701)));
yield provider.collectDailyData();
let m = provider.getMeasurement("update", 1);
let data = yield m.getValues();
let s = data.singular;
Assert.equal(s.size, 7);
Assert.equal(s.get("v20140527.upgradedFrom")[1], "13.0.1");
Assert.equal(s.get("v20140527.uninstallReason")[1], "SUCCESSFUL_UPGRADE");
Assert.equal(s.get("v20140527.downloadAttempts")[1], 1);
Assert.equal(s.get("v20140527.downloadFailures")[1], 0);
Assert.equal(s.get("v20140527.installAttempts")[1], 1);
Assert.equal(s.get("v20140527.installFailures")[1], 0);
Assert.equal(s.get("v20140527.notificationsShown")[1], 0);
// Ensure the dynamic fields get serialized.
let serializer = m.serializer(m.SERIALIZE_JSON);
let d = serializer.singular(s);
Assert.deepEqual(d, {
"_v": 1,
"v20140527.upgradedFrom": "13.0.1",
"v20140527.uninstallReason": "SUCCESSFUL_UPGRADE",
"v20140527.downloadAttempts": 1,
"v20140527.downloadFailures": 0,
"v20140527.installAttempts": 1,
"v20140527.installFailures": 0,
"v20140527.notificationsShown": 0,
});
// Don't interfere with next test.
yield OS.File.remove(path);
yield storage.close();
});
add_task(function* test_collect_multiple_versions() {
let storage = yield Metrics.Storage("collect_multiple_versions");
let provider = new HotfixProvider();
yield provider.init(storage);
let p1 = {
upgradedFrom: "12.0",
uninstallReason: "SUCCESSFUL_UPGRADE",
downloadAttempts: 3,
downloadFailures: 1,
installAttempts: 1,
installFailures: 1,
notificationsShown: 2,
};
let p2 = {
downloadAttempts: 5,
downloadFailures: 3,
installAttempts: 2,
installFailures: 2,
uninstallReason: null,
notificationsShown: 1,
};
let path1 = OS.Path.join(OS.Constants.Path.profileDir, "updateHotfix.v20140601.json");
let path2 = OS.Path.join(OS.Constants.Path.profileDir, "updateHotfix.v20140701.json");
let encoder = new TextEncoder();
yield OS.File.writeAtomic(path1, encoder.encode(JSON.stringify(p1)));
yield OS.File.writeAtomic(path2, encoder.encode(JSON.stringify(p2)));
yield provider.collectDailyData();
let m = provider.getMeasurement("update", 1);
let data = yield m.getValues();
let serializer = m.serializer(m.SERIALIZE_JSON);
let d = serializer.singular(data.singular);
Assert.deepEqual(d, {
"_v": 1,
"v20140601.upgradedFrom": "12.0",
"v20140601.uninstallReason": "SUCCESSFUL_UPGRADE",
"v20140601.downloadAttempts": 3,
"v20140601.downloadFailures": 1,
"v20140601.installAttempts": 1,
"v20140601.installFailures": 1,
"v20140601.notificationsShown": 2,
"v20140701.uninstallReason": "STILL_INSTALLED",
"v20140701.downloadAttempts": 5,
"v20140701.downloadFailures": 3,
"v20140701.installAttempts": 2,
"v20140701.installFailures": 2,
"v20140701.notificationsShown": 1,
});
// Don't interfere with next test.
yield OS.File.remove(path1);
yield OS.File.remove(path2);
yield storage.close();
});

View File

@ -1,46 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var {utils: Cu} = Components;
Cu.import("resource://gre/modules/Metrics.jsm");
Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
function run_test() {
run_next_test();
}
add_test(function test_constructor() {
let provider = new PlacesProvider();
run_next_test();
});
add_task(function test_collect_smoketest() {
let storage = yield Metrics.Storage("collect_smoketest");
let provider = new PlacesProvider();
yield provider.init(storage);
let now = new Date();
yield provider.collectDailyData();
let m = provider.getMeasurement("places", 1);
let data = yield storage.getMeasurementValues(m.id);
do_check_eq(data.days.size, 1);
do_check_true(data.days.hasDay(now));
let serializer = m.serializer(m.SERIALIZE_JSON);
let day = serializer.daily(data.days.getDay(now));
do_check_eq(day._v, 1);
do_check_eq(Object.keys(day).length, 3);
do_check_eq(day.pages, 0);
do_check_eq(day.bookmarks, 0);
yield storage.close();
});

View File

@ -1,187 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var {utils: Cu} = Components;
Cu.import("resource://gre/modules/Metrics.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var bsp = Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
const DEFAULT_ENGINES = [
{name: "Amazon.com", identifier: "amazondotcom"},
{name: "Bing", identifier: "bing"},
{name: "Google", identifier: "google"},
{name: "Yahoo", identifier: "yahoo"},
{name: "Foobar Search", identifier: "foobar"},
];
function MockSearchCountMeasurement() {
bsp.SearchCountMeasurement3.call(this);
}
MockSearchCountMeasurement.prototype = {
__proto__: bsp.SearchCountMeasurement3.prototype,
};
function MockSearchesProvider() {
SearchesProvider.call(this);
}
MockSearchesProvider.prototype = {
__proto__: SearchesProvider.prototype,
measurementTypes: [MockSearchCountMeasurement],
};
function run_test() {
// Tell the search service we are running in the US. This also has the
// desired side-effect of preventing our geoip lookup.
Services.prefs.setBoolPref("browser.search.isUS", true);
Services.prefs.setCharPref("browser.search.countryCode", "US");
run_next_test();
}
add_test(function test_constructor() {
let provider = new SearchesProvider();
run_next_test();
});
add_task(function* test_record() {
let storage = yield Metrics.Storage("record");
let provider = new MockSearchesProvider();
yield provider.init(storage);
let now = new Date();
// Record searches for all but one of our defaults, and one engine that's
// not a default.
for (let engine of DEFAULT_ENGINES.concat([{name: "Not Default", identifier: "notdef"}])) {
if (engine.identifier == "yahoo") {
continue;
}
yield provider.recordSearch(engine, "abouthome");
yield provider.recordSearch(engine, "contextmenu");
yield provider.recordSearch(engine, "newtab");
yield provider.recordSearch(engine, "searchbar");
yield provider.recordSearch(engine, "urlbar");
}
// Invalid sources should throw.
let errored = false;
try {
yield provider.recordSearch(DEFAULT_ENGINES[0], "bad source");
} catch (ex) {
errored = true;
} finally {
do_check_true(errored);
}
let m = provider.getMeasurement("counts", 3);
let data = yield m.getValues();
do_check_eq(data.days.size, 1);
do_check_true(data.days.hasDay(now));
let day = data.days.getDay(now);
for (let engine of DEFAULT_ENGINES) {
let identifier = engine.identifier;
let expected = identifier != "yahoo";
for (let source of ["abouthome", "contextmenu", "searchbar", "urlbar"]) {
let field = identifier + "." + source;
if (expected) {
do_check_true(day.has(field));
do_check_eq(day.get(field), 1);
} else {
do_check_false(day.has(field));
}
}
}
// Also, check that our non-default engine contributed, with a computed
// identifier.
let identifier = "notdef";
for (let source of ["abouthome", "contextmenu", "searchbar", "urlbar"]) {
let field = identifier + "." + source;
do_check_true(day.has(field));
}
yield storage.close();
});
add_task(function* test_includes_other_fields() {
let storage = yield Metrics.Storage("includes_other_fields");
let provider = new MockSearchesProvider();
yield provider.init(storage);
let m = provider.getMeasurement("counts", 3);
// Register a search against a provider that isn't live in this session.
let id = yield m.storage.registerField(m.id, "test.searchbar",
Metrics.Storage.FIELD_DAILY_COUNTER);
let testField = "test.searchbar";
let now = new Date();
yield m.storage.incrementDailyCounterFromFieldID(id, now);
// Make sure we don't know about it.
do_check_false(testField in m.fields);
// But we want to include it in payloads.
do_check_true(m.shouldIncludeField(testField));
// And we do so.
let data = yield provider.storage.getMeasurementValues(m.id);
let serializer = m.serializer(m.SERIALIZE_JSON);
let formatted = serializer.daily(data.days.getDay(now));
do_check_true(testField in formatted);
do_check_eq(formatted[testField], 1);
yield storage.close();
});
add_task(function* test_default_search_engine() {
let storage = yield Metrics.Storage("default_search_engine");
let provider = new SearchesProvider();
yield provider.init(storage);
let m = provider.getMeasurement("engines", 2);
let now = new Date();
yield provider.collectDailyData();
let data = yield m.getValues();
Assert.ok(data.days.hasDay(now));
let day = data.days.getDay(now);
Assert.equal(day.size, 1);
Assert.ok(day.has("default"));
// test environment doesn't have a default engine.
Assert.equal(day.get("default"), "NONE");
Services.search.addEngineWithDetails("testdefault",
"http://localhost/icon.png",
null,
"test description",
"GET",
"http://localhost/search/%s");
let engine1 = Services.search.getEngineByName("testdefault");
Assert.ok(engine1);
Services.search.defaultEngine = engine1;
yield provider.collectDailyData();
data = yield m.getValues();
Assert.equal(data.days.getDay(now).get("default"), "other-testdefault");
// If no cohort identifier is set, we shouldn't report a cohort.
Assert.equal(data.days.getDay(now).get("cohort"), undefined);
// Set a cohort identifier and verify we record it.
Services.prefs.setCharPref("browser.search.cohort", "testcohort");
yield provider.collectDailyData();
data = yield m.getValues();
Assert.equal(data.days.getDay(now).get("cohort"), "testcohort");
yield storage.close();
});

View File

@ -1,217 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var {utils: Cu} = Components;
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Metrics.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/services-common/utils.js");
Cu.import("resource://gre/modules/SessionRecorder.jsm");
Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
function run_test() {
run_next_test();
}
add_test(function test_constructor() {
let provider = new SessionsProvider();
run_next_test();
});
add_task(function test_init() {
let storage = yield Metrics.Storage("init");
let provider = new SessionsProvider();
yield provider.init(storage);
yield provider.shutdown();
yield storage.close();
});
function monkeypatchStartupInfo(recorder, start=new Date(), offset=500) {
Object.defineProperty(recorder, "_getStartupInfo", {
value: function _getStartupInfo() {
return {
process: start,
main: new Date(start.getTime() + offset),
firstPaint: new Date(start.getTime() + 2 * offset),
sessionRestored: new Date(start.getTime() + 3 * offset),
};
}
});
}
function sleep(wait) {
let deferred = Promise.defer();
let timer = CommonUtils.namedTimer(function onTimer() {
deferred.resolve();
}, wait, deferred.promise, "_sleepTimer");
return deferred.promise;
}
function getProvider(name, now=new Date(), init=true) {
return Task.spawn(function () {
let storage = yield Metrics.Storage(name);
let provider = new SessionsProvider();
let recorder = new SessionRecorder("testing." + name + ".sessions.");
monkeypatchStartupInfo(recorder, now);
provider.healthReporter = {sessionRecorder: recorder};
recorder.onStartup();
if (init) {
yield provider.init(storage);
}
throw new Task.Result([provider, storage, recorder]);
});
}
add_task(function test_current_session() {
let now = new Date();
let [provider, storage, recorder] = yield getProvider("current_session", now);
yield sleep(25);
recorder.onActivity(true);
let current = provider.getMeasurement("current", 3);
let values = yield current.getValues();
let fields = values.singular;
for (let field of ["startDay", "activeTicks", "totalTime", "main", "firstPaint", "sessionRestored"]) {
do_check_true(fields.has(field));
}
do_check_eq(fields.get("startDay")[1], Metrics.dateToDays(now));
do_check_eq(fields.get("totalTime")[1], recorder.totalTime);
do_check_eq(fields.get("activeTicks")[1], 1);
do_check_eq(fields.get("main")[1], 500);
do_check_eq(fields.get("firstPaint")[1], 1000);
do_check_eq(fields.get("sessionRestored")[1], 1500);
yield provider.shutdown();
yield storage.close();
});
add_task(function test_collect() {
let now = new Date();
let [provider, storage, recorder] = yield getProvider("collect");
recorder.onShutdown();
yield sleep(25);
for (let i = 0; i < 5; i++) {
let recorder2 = new SessionRecorder("testing.collect.sessions.");
recorder2.onStartup();
yield sleep(25);
recorder2.onShutdown();
yield sleep(25);
}
recorder = new SessionRecorder("testing.collect.sessions.");
recorder.onStartup();
// Collecting the provider should prune all previous sessions.
let sessions = recorder.getPreviousSessions();
do_check_eq(Object.keys(sessions).length, 6);
yield provider.collectConstantData();
sessions = recorder.getPreviousSessions();
do_check_eq(Object.keys(sessions).length, 0);
// And those previous sessions should make it to storage.
let daily = provider.getMeasurement("previous", 3);
let values = yield daily.getValues();
do_check_true(values.days.hasDay(now));
do_check_eq(values.days.size, 1);
let day = values.days.getDay(now);
do_check_eq(day.size, 5);
let previousStorageCount = day.get("main").length;
for (let field of ["cleanActiveTicks", "cleanTotalTime", "main", "firstPaint", "sessionRestored"]) {
do_check_true(day.has(field));
do_check_true(Array.isArray(day.get(field)));
do_check_eq(day.get(field).length, 6);
}
let lastIndex = yield provider.getState("lastSession");
do_check_eq(lastIndex, "" + (previousStorageCount - 1)); // 0-indexed
// Fake an aborted session. If we create a 2nd recorder against the same
// prefs branch as a running one, this simulates what would happen if the
// first recorder didn't shut down.
let recorder2 = new SessionRecorder("testing.collect.sessions.");
recorder2.onStartup();
do_check_eq(Object.keys(recorder.getPreviousSessions()).length, 1);
yield provider.collectConstantData();
do_check_eq(Object.keys(recorder.getPreviousSessions()).length, 0);
values = yield daily.getValues();
day = values.days.getDay(now);
do_check_eq(day.size, previousStorageCount + 1);
previousStorageCount = day.get("main").length;
for (let field of ["abortedActiveTicks", "abortedTotalTime"]) {
do_check_true(day.has(field));
do_check_true(Array.isArray(day.get(field)));
do_check_eq(day.get(field).length, 1);
}
lastIndex = yield provider.getState("lastSession");
do_check_eq(lastIndex, "" + (previousStorageCount - 1));
recorder.onShutdown();
recorder2.onShutdown();
// If we try to insert a already-inserted session, it will be ignored.
recorder = new SessionRecorder("testing.collect.sessions.");
recorder._currentIndex = recorder._currentIndex - 1;
recorder._prunedIndex = recorder._currentIndex;
recorder.onStartup();
// Session is left over from recorder2.
sessions = recorder.getPreviousSessions();
do_check_eq(Object.keys(sessions).length, 1);
do_check_true(previousStorageCount - 1 in sessions);
yield provider.collectConstantData();
lastIndex = yield provider.getState("lastSession");
do_check_eq(lastIndex, "" + (previousStorageCount - 1));
values = yield daily.getValues();
day = values.days.getDay(now);
// We should not get additional entry.
do_check_eq(day.get("main").length, previousStorageCount);
recorder.onShutdown();
yield provider.shutdown();
yield storage.close();
});
add_task(function test_serialization() {
let [provider, storage, recorder] = yield getProvider("serialization");
yield sleep(1025);
recorder.onActivity(true);
let current = provider.getMeasurement("current", 3);
let data = yield current.getValues();
do_check_true("singular" in data);
let serializer = current.serializer(current.SERIALIZE_JSON);
let fields = serializer.singular(data.singular);
do_check_eq(fields._v, 3);
do_check_eq(fields.activeTicks, 1);
do_check_eq(fields.startDay, Metrics.dateToDays(recorder.startDate));
do_check_eq(fields.main, 500);
do_check_eq(fields.firstPaint, 1000);
do_check_eq(fields.sessionRestored, 1500);
do_check_true(fields.totalTime > 0);
yield provider.shutdown();
yield storage.close();
});

View File

@ -1,41 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var {interfaces: Ci, results: Cr, utils: Cu} = Components;
Cu.import("resource://gre/modules/Metrics.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
function run_test() {
run_next_test();
}
add_test(function test_constructor() {
let provider = new SysInfoProvider();
run_next_test();
});
add_task(function test_collect_smoketest() {
let storage = yield Metrics.Storage("collect_smoketest");
let provider = new SysInfoProvider();
yield provider.init(storage);
yield provider.collectConstantData();
let m = provider.getMeasurement("sysinfo", 2);
let data = yield storage.getMeasurementValues(m.id);
let serializer = m.serializer(m.SERIALIZE_JSON);
let d = serializer.singular(data.singular);
do_check_eq(d._v, 2);
do_check_true(d.cpuCount > 0);
do_check_neq(d.name, null);
yield storage.close();
});

View File

@ -1,19 +0,0 @@
[DEFAULT]
head = head.js
tail =
skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_load_modules.js]
[test_profile.js]
[test_provider_addons.js]
skip-if = buildapp == 'mulet'
tags = addons
[test_provider_appinfo.js]
[test_provider_crashes.js]
skip-if = !crashreporter
[test_provider_hotfix.js]
[test_provider_places.js]
[test_provider_searches.js]
[test_provider_sysinfo.js]
[test_provider_sessions.js]

View File

@ -12,12 +12,6 @@ DIRS += [
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android' or CONFIG['MOZ_B2GDROID']:
DIRS += ['fxaccounts']
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
# MOZ_SERVICES_HEALTHREPORT and therefore MOZ_DATA_REPORTING are
# defined on Android, but these features are implemented using Java.
if CONFIG['MOZ_SERVICES_HEALTHREPORT']:
DIRS += ['healthreport']
if CONFIG['MOZ_SERVICES_METRICS']:
DIRS += ['metrics']

View File

@ -1,11 +1,11 @@
.. _healthreport:
=====================
Firefox Health Report
=====================
================================
Firefox Health Report (Obsolete)
================================
``/services/healthreport`` contains the implementation of the
``Firefox Health Report`` (FHR).
**Firefox Health Report (FHR) is obsolete and no longer ships with Firefox.
This documentation will live here for a few more cycles.**
Firefox Health Report is a background service that collects application
metrics and periodically submits them to a central server. The core

View File

@ -81,3 +81,4 @@ LOCAL_INCLUDES += [
]
SPHINX_TREES['telemetry'] = 'docs'
SPHINX_TREES['healthreport'] = 'docs/fhr'