1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/services/healthreport/modules-testing/utils.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,211 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +this.EXPORTED_SYMBOLS = [ 1.11 + "getAppInfo", 1.12 + "updateAppInfo", 1.13 + "createFakeCrash", 1.14 + "InspectedHealthReporter", 1.15 + "getHealthReporter", 1.16 +]; 1.17 + 1.18 + 1.19 +const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components; 1.20 + 1.21 +Cu.import("resource://gre/modules/Preferences.jsm"); 1.22 +Cu.import("resource://gre/modules/Promise.jsm"); 1.23 +Cu.import("resource://gre/modules/FileUtils.jsm"); 1.24 +Cu.import("resource://gre/modules/osfile.jsm"); 1.25 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.26 +Cu.import("resource://gre/modules/services-common/utils.js"); 1.27 +Cu.import("resource://gre/modules/services/datareporting/policy.jsm"); 1.28 +Cu.import("resource://gre/modules/services/healthreport/healthreporter.jsm"); 1.29 +Cu.import("resource://gre/modules/services/healthreport/providers.jsm"); 1.30 + 1.31 + 1.32 +let APP_INFO = { 1.33 + vendor: "Mozilla", 1.34 + name: "xpcshell", 1.35 + ID: "xpcshell@tests.mozilla.org", 1.36 + version: "1", 1.37 + appBuildID: "20121107", 1.38 + platformVersion: "p-ver", 1.39 + platformBuildID: "20121106", 1.40 + inSafeMode: false, 1.41 + logConsoleErrors: true, 1.42 + OS: "XPCShell", 1.43 + XPCOMABI: "noarch-spidermonkey", 1.44 + QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo, Ci.nsIXULRuntime]), 1.45 + invalidateCachesOnRestart: function() {}, 1.46 +}; 1.47 + 1.48 + 1.49 +/** 1.50 + * Obtain a reference to the current object used to define XULAppInfo. 1.51 + */ 1.52 +this.getAppInfo = function () { return APP_INFO; } 1.53 + 1.54 +/** 1.55 + * Update the current application info. 1.56 + * 1.57 + * If the argument is defined, it will be the object used. Else, APP_INFO is 1.58 + * used. 1.59 + * 1.60 + * To change the current XULAppInfo, simply call this function. If there was 1.61 + * a previously registered app info object, it will be unloaded and replaced. 1.62 + */ 1.63 +this.updateAppInfo = function (obj) { 1.64 + obj = obj || APP_INFO; 1.65 + APP_INFO = obj; 1.66 + 1.67 + let id = Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"); 1.68 + let cid = "@mozilla.org/xre/app-info;1"; 1.69 + let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); 1.70 + 1.71 + // Unregister an existing factory if one exists. 1.72 + try { 1.73 + let existing = Components.manager.getClassObjectByContractID(cid, Ci.nsIFactory); 1.74 + registrar.unregisterFactory(id, existing); 1.75 + } catch (ex) {} 1.76 + 1.77 + let factory = { 1.78 + createInstance: function (outer, iid) { 1.79 + if (outer != null) { 1.80 + throw Cr.NS_ERROR_NO_AGGREGATION; 1.81 + } 1.82 + 1.83 + return obj.QueryInterface(iid); 1.84 + }, 1.85 + }; 1.86 + 1.87 + registrar.registerFactory(id, "XULAppInfo", cid, factory); 1.88 +}; 1.89 + 1.90 +/** 1.91 + * Creates a fake crash in the Crash Reports directory. 1.92 + * 1.93 + * Currently, we just create a dummy file. A more robust implementation would 1.94 + * create something that actually resembles a crash report file. 1.95 + * 1.96 + * This is very similar to code in crashreporter/tests/browser/head.js. 1.97 + * 1.98 + * FUTURE consolidate code in a shared JSM. 1.99 + */ 1.100 +this.createFakeCrash = function (submitted=false, date=new Date()) { 1.101 + let id = CommonUtils.generateUUID(); 1.102 + let filename; 1.103 + 1.104 + let paths = ["Crash Reports"]; 1.105 + let mode; 1.106 + 1.107 + if (submitted) { 1.108 + paths.push("submitted"); 1.109 + filename = "bp-" + id + ".txt"; 1.110 + mode = OS.Constants.libc.S_IRUSR | OS.Constants.libc.S_IWUSR | 1.111 + OS.Constants.libc.S_IRGRP | OS.Constants.libc.S_IROTH; 1.112 + } else { 1.113 + paths.push("pending"); 1.114 + filename = id + ".dmp"; 1.115 + mode = OS.Constants.libc.S_IRUSR | OS.Constants.libc.S_IWUSR; 1.116 + } 1.117 + 1.118 + paths.push(filename); 1.119 + 1.120 + let file = FileUtils.getFile("UAppData", paths, true); 1.121 + file.create(file.NORMAL_FILE_TYPE, mode); 1.122 + file.lastModifiedTime = date.getTime(); 1.123 + dump("Created fake crash: " + id + "\n"); 1.124 + 1.125 + return id; 1.126 +}; 1.127 + 1.128 + 1.129 +/** 1.130 + * A HealthReporter that is probed with various callbacks and counters. 1.131 + * 1.132 + * The purpose of this type is to aid testing of startup and shutdown. 1.133 + */ 1.134 +this.InspectedHealthReporter = function (branch, policy, recorder, stateLeaf) { 1.135 + HealthReporter.call(this, branch, policy, recorder, stateLeaf); 1.136 + 1.137 + this.onStorageCreated = null; 1.138 + this.onProviderManagerInitialized = null; 1.139 + this.providerManagerShutdownCount = 0; 1.140 + this.storageCloseCount = 0; 1.141 +} 1.142 + 1.143 +InspectedHealthReporter.prototype = { 1.144 + __proto__: HealthReporter.prototype, 1.145 + 1.146 + _onStorageCreated: function (storage) { 1.147 + if (this.onStorageCreated) { 1.148 + this.onStorageCreated(storage); 1.149 + } 1.150 + 1.151 + return HealthReporter.prototype._onStorageCreated.call(this, storage); 1.152 + }, 1.153 + 1.154 + _initializeProviderManager: function () { 1.155 + for (let result of HealthReporter.prototype._initializeProviderManager.call(this)) { 1.156 + yield result; 1.157 + } 1.158 + 1.159 + if (this.onInitializeProviderManagerFinished) { 1.160 + this.onInitializeProviderManagerFinished(); 1.161 + } 1.162 + }, 1.163 + 1.164 + _onProviderManagerInitialized: function () { 1.165 + if (this.onProviderManagerInitialized) { 1.166 + this.onProviderManagerInitialized(); 1.167 + } 1.168 + 1.169 + return HealthReporter.prototype._onProviderManagerInitialized.call(this); 1.170 + }, 1.171 + 1.172 + _onProviderManagerShutdown: function () { 1.173 + this.providerManagerShutdownCount++; 1.174 + 1.175 + return HealthReporter.prototype._onProviderManagerShutdown.call(this); 1.176 + }, 1.177 + 1.178 + _onStorageClose: function () { 1.179 + this.storageCloseCount++; 1.180 + 1.181 + return HealthReporter.prototype._onStorageClose.call(this); 1.182 + }, 1.183 +}; 1.184 + 1.185 +const DUMMY_URI="http://localhost:62013/"; 1.186 + 1.187 +this.getHealthReporter = function (name, uri=DUMMY_URI, inspected=false) { 1.188 + let branch = "healthreport.testing." + name + "."; 1.189 + 1.190 + let prefs = new Preferences(branch + "healthreport."); 1.191 + prefs.set("documentServerURI", uri); 1.192 + prefs.set("dbName", name); 1.193 + 1.194 + let reporter; 1.195 + 1.196 + let policyPrefs = new Preferences(branch + "policy."); 1.197 + let policy = new DataReportingPolicy(policyPrefs, prefs, { 1.198 + onRequestDataUpload: function (request) { 1.199 + reporter.requestDataUpload(request); 1.200 + }, 1.201 + 1.202 + onNotifyDataPolicy: function (request) { }, 1.203 + 1.204 + onRequestRemoteDelete: function (request) { 1.205 + reporter.deleteRemoteData(request); 1.206 + }, 1.207 + }); 1.208 + 1.209 + let type = inspected ? InspectedHealthReporter : HealthReporter; 1.210 + reporter = new type(branch + "healthreport.", policy, null, 1.211 + "state-" + name + ".json"); 1.212 + 1.213 + return reporter; 1.214 +};