mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changeset bafe9571f3e8 (bug 839794) for xpcshell failures.
This commit is contained in:
parent
a9e24185ca
commit
db3da3f56c
@ -1,8 +1,3 @@
|
||||
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
|
||||
/* 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 = ["TelemetryFile"];
|
||||
@ -12,13 +7,20 @@ const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/Deprecated.jsm", this);
|
||||
Cu.import("resource://gre/modules/osfile.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", this);
|
||||
let imports = {};
|
||||
Cu.import("resource://gre/modules/Services.jsm", imports);
|
||||
Cu.import("resource://gre/modules/Deprecated.jsm", imports);
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm", imports);
|
||||
|
||||
const Telemetry = Services.telemetry;
|
||||
let {Services, Deprecated, NetUtil} = imports;
|
||||
|
||||
// Constants from prio.h for nsIFileOutputStream.init
|
||||
const PR_WRONLY = 0x2;
|
||||
const PR_CREATE_FILE = 0x8;
|
||||
const PR_TRUNCATE = 0x20;
|
||||
const PR_EXCL = 0x80;
|
||||
const RW_OWNER = parseInt("0600", 8);
|
||||
const RWX_OWNER = parseInt("0700", 8);
|
||||
|
||||
// Files that have been lying around for longer than MAX_PING_FILE_AGE are
|
||||
// deleted without being loaded.
|
||||
@ -32,6 +34,9 @@ const OVERDUE_PING_FILE_AGE = 7 * 24 * 60 * 60 * 1000; // 1 week
|
||||
// requests for.
|
||||
let pingsLoaded = 0;
|
||||
|
||||
// The number of those requests that have actually completed.
|
||||
let pingLoadsCompleted = 0;
|
||||
|
||||
// The number of pings that we have destroyed due to being older
|
||||
// than MAX_PING_FILE_AGE.
|
||||
let pingsDiscarded = 0;
|
||||
@ -40,11 +45,13 @@ let pingsDiscarded = 0;
|
||||
// but younger than MAX_PING_FILE_AGE.
|
||||
let pingsOverdue = 0;
|
||||
|
||||
// If |true|, send notifications "telemetry-test-save-complete"
|
||||
// and "telemetry-test-load-complete" once save/load is complete.
|
||||
let shouldNotifyUponSave = false;
|
||||
|
||||
// Data that has neither been saved nor sent by ping
|
||||
let pendingPings = [];
|
||||
|
||||
let isPingDirectoryCreated = false;
|
||||
|
||||
this.TelemetryFile = {
|
||||
|
||||
get MAX_PING_FILE_AGE() {
|
||||
@ -55,64 +62,94 @@ this.TelemetryFile = {
|
||||
return OVERDUE_PING_FILE_AGE;
|
||||
},
|
||||
|
||||
get pingDirectoryPath() {
|
||||
return OS.Path.join(OS.Constants.Path.profileDir, "saved-telemetry-pings");
|
||||
},
|
||||
|
||||
/**
|
||||
* Save a single ping to a file.
|
||||
*
|
||||
* @param {object} ping The content of the ping to save.
|
||||
* @param {string} file The destination file.
|
||||
* @param {nsIFile} file The destination file.
|
||||
* @param {bool} sync If |true|, write synchronously. Deprecated.
|
||||
* This argument should be |false|.
|
||||
* @param {bool} overwrite If |true|, the file will be overwritten
|
||||
* if it exists.
|
||||
* @returns {promise}
|
||||
*/
|
||||
savePingToFile: function(ping, file, overwrite) {
|
||||
savePingToFile: function(ping, file, sync, overwrite) {
|
||||
let pingString = JSON.stringify(ping);
|
||||
return OS.File.writeAtomic(file, pingString, {tmpPath: file + ".tmp",
|
||||
noOverwrite: !overwrite});
|
||||
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
|
||||
let ostream = Cc["@mozilla.org/network/file-output-stream;1"]
|
||||
.createInstance(Ci.nsIFileOutputStream);
|
||||
let initFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
|
||||
if (!overwrite) {
|
||||
initFlags |= PR_EXCL;
|
||||
}
|
||||
try {
|
||||
ostream.init(file, initFlags, RW_OWNER, 0);
|
||||
} catch (e) {
|
||||
// Probably due to PR_EXCL.
|
||||
return;
|
||||
}
|
||||
|
||||
if (sync) {
|
||||
let utf8String = converter.ConvertFromUnicode(pingString);
|
||||
utf8String += converter.Finish();
|
||||
let success = false;
|
||||
try {
|
||||
let amount = ostream.write(utf8String, utf8String.length);
|
||||
success = amount == utf8String.length;
|
||||
} catch (e) {
|
||||
}
|
||||
finishTelemetrySave(success, ostream);
|
||||
} else {
|
||||
let istream = converter.convertToInputStream(pingString);
|
||||
let self = this;
|
||||
NetUtil.asyncCopy(istream, ostream,
|
||||
function(result) {
|
||||
finishTelemetrySave(Components.isSuccessCode(result),
|
||||
ostream);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Save a ping to its file.
|
||||
* Save a ping to its file, synchronously.
|
||||
*
|
||||
* @param {object} ping The content of the ping to save.
|
||||
* @param {bool} overwrite If |true|, the file will be overwritten
|
||||
* if it exists.
|
||||
* @returns {promise}
|
||||
*/
|
||||
savePing: function(ping, overwrite) {
|
||||
return Task.spawn(function*() {
|
||||
yield getPingDirectory();
|
||||
let file = pingFilePath(ping);
|
||||
return this.savePingToFile(ping, file, overwrite);
|
||||
}.bind(this));
|
||||
this.savePingToFile(ping,
|
||||
getSaveFileForPing(ping), true, overwrite);
|
||||
},
|
||||
|
||||
/**
|
||||
* Save all pending pings.
|
||||
* Save all pending pings, synchronously.
|
||||
*
|
||||
* @param {object} sessionPing The additional session ping.
|
||||
* @returns {promise}
|
||||
*/
|
||||
savePendingPings: function(sessionPing) {
|
||||
let p = pendingPings.reduce((p, ping) => {
|
||||
p.push(this.savePing(ping, false));
|
||||
return p;}, [this.savePing(sessionPing, true)]);
|
||||
|
||||
this.savePing(sessionPing, true);
|
||||
pendingPings.forEach(function sppcb(e, i, a) {
|
||||
this.savePing(e, false);
|
||||
}, this);
|
||||
pendingPings = [];
|
||||
return Promise.all(p);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the file for a ping
|
||||
*
|
||||
* @param {object} ping The ping.
|
||||
* @returns {promise}
|
||||
*/
|
||||
cleanupPingFile: function(ping) {
|
||||
return OS.File.remove(pingFilePath(ping));
|
||||
// FIXME: We shouldn't create the directory just to remove the file.
|
||||
let file = getSaveFileForPing(ping);
|
||||
try {
|
||||
file.remove(true); // FIXME: Should be |false|, isn't it?
|
||||
} catch(e) {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -121,26 +158,24 @@ this.TelemetryFile = {
|
||||
* Once loaded, the saved pings can be accessed (destructively only)
|
||||
* through |popPendingPings|.
|
||||
*
|
||||
* @returns {promise}
|
||||
* @param {bool} sync If |true|, loading takes place synchronously.
|
||||
* @param {function*} onLoad A function called upon loading of each
|
||||
* ping. It is passed |true| in case of success, |false| in case of
|
||||
* format error.
|
||||
*/
|
||||
loadSavedPings: function() {
|
||||
return Task.spawn(function*() {
|
||||
let directory = TelemetryFile.pingDirectoryPath;
|
||||
let iter = new OS.File.DirectoryIterator(directory);
|
||||
let exists = yield iter.exists();
|
||||
|
||||
if (exists) {
|
||||
let entries = yield iter.nextBatch();
|
||||
yield iter.close();
|
||||
|
||||
let p = [e for (e of entries) if (!e.isDir)].
|
||||
map((e) => this.loadHistograms(e.path));
|
||||
|
||||
yield Promise.all(p);
|
||||
loadSavedPings: function(sync, onLoad = null, onDone = null) {
|
||||
let directory = ensurePingDirectory();
|
||||
let entries = directory.directoryEntries
|
||||
.QueryInterface(Ci.nsIDirectoryEnumerator);
|
||||
pingsLoaded = 0;
|
||||
pingLoadsCompleted = 0;
|
||||
try {
|
||||
while (entries.hasMoreElements()) {
|
||||
this.loadHistograms(entries.nextFile, sync, onLoad, onDone);
|
||||
}
|
||||
|
||||
yield iter.close();
|
||||
}.bind(this));
|
||||
} finally {
|
||||
entries.close();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -149,26 +184,43 @@ this.TelemetryFile = {
|
||||
* Once loaded, the saved pings can be accessed (destructively only)
|
||||
* through |popPendingPings|.
|
||||
*
|
||||
* @param {string} file The file to load.
|
||||
* @returns {promise}
|
||||
* @param {nsIFile} file The file to load.
|
||||
* @param {bool} sync If |true|, loading takes place synchronously.
|
||||
* @param {function*} onLoad A function called upon loading of the
|
||||
* ping. It is passed |true| in case of success, |false| in case of
|
||||
* format error.
|
||||
*/
|
||||
loadHistograms: function loadHistograms(file) {
|
||||
return OS.File.stat(file).then(function(info){
|
||||
let now = Date.now();
|
||||
if (now - info.lastModificationDate > MAX_PING_FILE_AGE) {
|
||||
// We haven't had much luck in sending this file; delete it.
|
||||
pingsDiscarded++;
|
||||
return OS.File.remove(file);
|
||||
}
|
||||
loadHistograms: function loadHistograms(file, sync, onLoad = null, onDone = null) {
|
||||
let now = Date.now();
|
||||
if (now - file.lastModifiedTime > MAX_PING_FILE_AGE) {
|
||||
// We haven't had much luck in sending this file; delete it.
|
||||
file.remove(true);
|
||||
pingsDiscarded++;
|
||||
return;
|
||||
}
|
||||
|
||||
// This file is a bit stale, and overdue for sending.
|
||||
if (now - info.lastModificationDate > OVERDUE_PING_FILE_AGE) {
|
||||
pingsOverdue++;
|
||||
}
|
||||
// This file is a bit stale, and overdue for sending.
|
||||
if (now - file.lastModifiedTime > OVERDUE_PING_FILE_AGE) {
|
||||
pingsOverdue++;
|
||||
}
|
||||
|
||||
pingsLoaded++;
|
||||
return addToPendingPings(file);
|
||||
});
|
||||
pingsLoaded++;
|
||||
if (sync) {
|
||||
let stream = Cc["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
stream.init(file, -1, -1, 0);
|
||||
addToPendingPings(file, stream, onLoad, onDone);
|
||||
} else {
|
||||
let channel = NetUtil.newChannel(file);
|
||||
channel.contentType = "application/json";
|
||||
|
||||
NetUtil.asyncFetch(channel, (function(stream, result) {
|
||||
if (!Components.isSuccessCode(result)) {
|
||||
return;
|
||||
}
|
||||
addToPendingPings(file, stream, onLoad, onDone);
|
||||
}).bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -199,7 +251,7 @@ this.TelemetryFile = {
|
||||
*
|
||||
* @return {iterator}
|
||||
*/
|
||||
popPendingPings: function*(reason) {
|
||||
popPendingPings: function(reason) {
|
||||
while (pendingPings.length > 0) {
|
||||
let data = pendingPings.pop();
|
||||
// Send persisted pings to the test URL too.
|
||||
@ -210,53 +262,74 @@ this.TelemetryFile = {
|
||||
}
|
||||
},
|
||||
|
||||
testLoadHistograms: function(file) {
|
||||
set shouldNotifyUponSave(value) {
|
||||
shouldNotifyUponSave = value;
|
||||
},
|
||||
|
||||
testLoadHistograms: function(file, sync, onLoad) {
|
||||
pingsLoaded = 0;
|
||||
return this.loadHistograms(file.path);
|
||||
pingLoadsCompleted = 0;
|
||||
this.loadHistograms(file, sync, onLoad);
|
||||
}
|
||||
};
|
||||
|
||||
///// Utility functions
|
||||
function pingFilePath(ping) {
|
||||
return OS.Path.join(TelemetryFile.pingDirectoryPath, ping.slug);
|
||||
}
|
||||
|
||||
function getPingDirectory() {
|
||||
return Task.spawn(function*() {
|
||||
let directory = TelemetryFile.pingDirectoryPath;
|
||||
function getSaveFileForPing(ping) {
|
||||
let file = ensurePingDirectory();
|
||||
file.append(ping.slug);
|
||||
return file;
|
||||
};
|
||||
|
||||
if (!isPingDirectoryCreated) {
|
||||
yield OS.File.makeDir(directory, { unixMode: OS.Constants.S_IRWXU });
|
||||
isPingDirectoryCreated = true;
|
||||
function ensurePingDirectory() {
|
||||
let directory = Services.dirsvc.get("ProfD", Ci.nsILocalFile).clone();
|
||||
directory.append("saved-telemetry-pings");
|
||||
try {
|
||||
directory.create(Ci.nsIFile.DIRECTORY_TYPE, RWX_OWNER);
|
||||
} catch (e) {
|
||||
// Already exists, just ignore this.
|
||||
}
|
||||
return directory;
|
||||
};
|
||||
|
||||
function addToPendingPings(file, stream, onLoad, onDone) {
|
||||
let success = false;
|
||||
|
||||
try {
|
||||
let string = NetUtil.readInputStreamToString(stream, stream.available(),
|
||||
{ charset: "UTF-8" });
|
||||
stream.close();
|
||||
let ping = JSON.parse(string);
|
||||
// The ping's payload used to be stringified JSON. Deal with that.
|
||||
if (typeof(ping.payload) == "string") {
|
||||
ping.payload = JSON.parse(ping.payload);
|
||||
}
|
||||
|
||||
return directory;
|
||||
});
|
||||
}
|
||||
|
||||
function addToPendingPings(file) {
|
||||
function onLoad(success) {
|
||||
let success_histogram = Telemetry.getHistogramById("READ_SAVED_PING_SUCCESS");
|
||||
success_histogram.add(success);
|
||||
pingLoadsCompleted++;
|
||||
pendingPings.push(ping);
|
||||
success = true;
|
||||
} catch (e) {
|
||||
// An error reading the file, or an error parsing the contents.
|
||||
stream.close(); // close is idempotent.
|
||||
file.remove(true); // FIXME: Should be false, isn't it?
|
||||
}
|
||||
|
||||
return Task.spawn(function*() {
|
||||
try {
|
||||
let array = yield OS.File.read(file);
|
||||
let decoder = new TextDecoder();
|
||||
let string = decoder.decode(array);
|
||||
if (onLoad) {
|
||||
onLoad(success);
|
||||
}
|
||||
|
||||
let ping = JSON.parse(string);
|
||||
// The ping's payload used to be stringified JSON. Deal with that.
|
||||
if (typeof(ping.payload) == "string") {
|
||||
ping.payload = JSON.parse(ping.payload);
|
||||
}
|
||||
|
||||
pendingPings.push(ping);
|
||||
onLoad(true);
|
||||
} catch (e) {
|
||||
onLoad(false);
|
||||
yield OS.File.remove(file);
|
||||
if (pingLoadsCompleted == pingsLoaded) {
|
||||
if (onDone) {
|
||||
onDone();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (shouldNotifyUponSave) {
|
||||
Services.obs.notifyObservers(null, "telemetry-test-load-complete", null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function finishTelemetrySave(ok, stream) {
|
||||
stream.close();
|
||||
if (shouldNotifyUponSave && ok) {
|
||||
Services.obs.notifyObservers(null, "telemetry-test-save-complete", null);
|
||||
}
|
||||
};
|
||||
|
@ -10,15 +10,13 @@ const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/debug.js", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
Cu.import("resource://gre/modules/debug.js");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
Cu.import("resource://gre/modules/LightweightThemeManager.jsm", this);
|
||||
Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
|
||||
#endif
|
||||
Cu.import("resource://gre/modules/ThirdPartyCookieProbe.jsm", this);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
Cu.import("resource://gre/modules/ThirdPartyCookieProbe.jsm");
|
||||
|
||||
// When modifying the payload in incompatible ways, please bump this version number
|
||||
const PAYLOAD_VERSION = 1;
|
||||
@ -129,57 +127,30 @@ let processInfo = {
|
||||
this.EXPORTED_SYMBOLS = ["TelemetryPing"];
|
||||
|
||||
this.TelemetryPing = Object.freeze({
|
||||
/**
|
||||
* Returns the current telemetry payload.
|
||||
* @returns Object
|
||||
*/
|
||||
getPayload: function() {
|
||||
return Impl.getPayload();
|
||||
},
|
||||
/**
|
||||
* Save histograms to a file.
|
||||
* Used only for testing purposes.
|
||||
*
|
||||
* @param {nsIFile} aFile The file to load from.
|
||||
*/
|
||||
testSaveHistograms: function(aFile) {
|
||||
return Impl.testSaveHistograms(aFile);
|
||||
saveHistograms: function(aFile, aSync) {
|
||||
return Impl.saveHistograms(aFile, aSync);
|
||||
},
|
||||
/**
|
||||
* Collect and store information about startup.
|
||||
*/
|
||||
gatherStartup: function() {
|
||||
return Impl.gatherStartup();
|
||||
},
|
||||
/**
|
||||
* Inform the ping which AddOns are installed.
|
||||
*
|
||||
* @param aAddOns - The AddOns.
|
||||
*/
|
||||
enableLoadSaveNotifications: function() {
|
||||
return Impl.enableLoadSaveNotifications();
|
||||
},
|
||||
cacheProfileDirectory: function() {
|
||||
return Impl.cacheProfileDirectory();
|
||||
},
|
||||
setAddOns: function(aAddOns) {
|
||||
return Impl.setAddOns(aAddOns);
|
||||
},
|
||||
/**
|
||||
* Send a ping to a test server. Used only for testing.
|
||||
*
|
||||
* @param aServer - The server.
|
||||
*/
|
||||
testPing: function(aServer) {
|
||||
return Impl.testPing(aServer);
|
||||
},
|
||||
/**
|
||||
* Load histograms from a file.
|
||||
* Used only for testing purposes.
|
||||
*
|
||||
* @param aFile - File to load from.
|
||||
*/
|
||||
testLoadHistograms: function(aFile) {
|
||||
return Impl.testLoadHistograms(aFile);
|
||||
testLoadHistograms: function(aFile, aSync) {
|
||||
return Impl.testLoadHistograms(aFile, aSync);
|
||||
},
|
||||
/**
|
||||
* Returns the path component of the current submission URL.
|
||||
* @returns String
|
||||
*/
|
||||
submissionPath: function() {
|
||||
return Impl.submissionPath();
|
||||
},
|
||||
@ -192,22 +163,24 @@ this.TelemetryPing = Object.freeze({
|
||||
* Used only for testing purposes.
|
||||
*/
|
||||
reset: function() {
|
||||
return Task.spawn(function*(){
|
||||
yield this.uninstall();
|
||||
yield this.setup();
|
||||
}.bind(this));
|
||||
this.uninstall();
|
||||
this.setup();
|
||||
},
|
||||
/**
|
||||
* Used only for testing purposes.
|
||||
*/
|
||||
setup: function() {
|
||||
return Impl.setup(true);
|
||||
Impl.setup(true);
|
||||
},
|
||||
/**
|
||||
* Used only for testing purposes.
|
||||
*/
|
||||
uninstall: function() {
|
||||
return Impl.uninstall();
|
||||
try {
|
||||
Impl.uninstall();
|
||||
} catch (ex) {
|
||||
// Ignore errors
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Descriptive metadata
|
||||
@ -724,15 +697,46 @@ let Impl = {
|
||||
send: function send(reason, server) {
|
||||
// populate histograms one last time
|
||||
this.gatherMemory();
|
||||
return this.sendPingsFromIterator(server, reason,
|
||||
this.sendPingsFromIterator(server, reason,
|
||||
Iterator(this.popPayloads(reason)));
|
||||
},
|
||||
|
||||
/**
|
||||
* What we want to do is the following:
|
||||
*
|
||||
* for data in getPayloads(reason):
|
||||
* if sending ping data to server failed:
|
||||
* break;
|
||||
*
|
||||
* but we can't do that, since XMLHttpRequest is async. What we do
|
||||
* instead is let this function control the essential looping logic
|
||||
* and provide callbacks for XMLHttpRequest when a request has
|
||||
* finished.
|
||||
*/
|
||||
sendPingsFromIterator: function sendPingsFromIterator(server, reason, i) {
|
||||
let p = [data for (data in i)].map((data) =>
|
||||
this.doPing(server, data).then(null, () => TelemetryFile.savePing(data, true)));
|
||||
function finishPings(reason) {
|
||||
if (reason == "test-ping") {
|
||||
Services.obs.notifyObservers(null, "telemetry-test-xhr-complete", null);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(p);
|
||||
let data = null;
|
||||
try {
|
||||
data = i.next();
|
||||
} catch (e if e instanceof StopIteration) {
|
||||
finishPings(reason);
|
||||
return;
|
||||
}
|
||||
function onSuccess() {
|
||||
this.sendPingsFromIterator(server, reason, i);
|
||||
}
|
||||
function onError() {
|
||||
TelemetryFile.savePing(data, true);
|
||||
// Notify that testing is complete, even if we didn't send everything.
|
||||
finishPings(reason);
|
||||
}
|
||||
this.doPing(server, data,
|
||||
onSuccess.bind(this), onError.bind(this));
|
||||
},
|
||||
|
||||
finishPingRequest: function finishPingRequest(success, startTime, ping) {
|
||||
@ -743,9 +747,7 @@ let Impl = {
|
||||
hping.add(new Date() - startTime);
|
||||
|
||||
if (success) {
|
||||
return TelemetryFile.cleanupPingFile(ping);
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
TelemetryFile.cleanupPingFile(ping);
|
||||
}
|
||||
},
|
||||
|
||||
@ -763,8 +765,7 @@ let Impl = {
|
||||
return "/submit/telemetry/" + slug;
|
||||
},
|
||||
|
||||
doPing: function doPing(server, ping) {
|
||||
let deferred = Promise.defer();
|
||||
doPing: function doPing(server, ping, onSuccess, onError) {
|
||||
let url = server + this.submissionPath(ping);
|
||||
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
@ -775,19 +776,14 @@ let Impl = {
|
||||
|
||||
let startTime = new Date();
|
||||
|
||||
function handler(success) {
|
||||
function handler(success, callback) {
|
||||
return function(event) {
|
||||
this.finishPingRequest(success, startTime, ping);
|
||||
|
||||
if (success) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject(event);
|
||||
}
|
||||
callback();
|
||||
};
|
||||
}
|
||||
request.addEventListener("error", handler(false).bind(this), false);
|
||||
request.addEventListener("load", handler(true).bind(this), false);
|
||||
request.addEventListener("error", handler(false, onError).bind(this), false);
|
||||
request.addEventListener("load", handler(true, onSuccess).bind(this), false);
|
||||
|
||||
request.setRequestHeader("Content-Encoding", "gzip");
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
@ -799,7 +795,6 @@ let Impl = {
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
payloadStream.data = this.gzipCompressString(utf8Payload);
|
||||
request.send(payloadStream);
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
gzipCompressString: function gzipCompressString(string) {
|
||||
@ -904,39 +899,41 @@ let Impl = {
|
||||
// run various late initializers. Otherwise our gathered memory
|
||||
// footprint and other numbers would be too optimistic.
|
||||
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
let deferred = Promise.defer();
|
||||
|
||||
function timerCallback() {
|
||||
Task.spawn(function*(){
|
||||
this._initialized = true;
|
||||
this._initialized = true;
|
||||
TelemetryFile.loadSavedPings(false, (success =>
|
||||
{
|
||||
let success_histogram = Telemetry.getHistogramById("READ_SAVED_PING_SUCCESS");
|
||||
success_histogram.add(success);
|
||||
}), () =>
|
||||
{
|
||||
// If we have any TelemetryPings lying around, we'll be aggressive
|
||||
// and try to send them all off ASAP.
|
||||
if (TelemetryFile.pingsOverdue > 0) {
|
||||
// It doesn't really matter what we pass to this.send as a reason,
|
||||
// since it's never sent to the server. All that this.send does with
|
||||
// the reason is check to make sure it's not a test-ping.
|
||||
this.send("overdue-flush", this._server);
|
||||
}
|
||||
});
|
||||
this.attachObservers();
|
||||
this.gatherMemory();
|
||||
|
||||
yield TelemetryFile.loadSavedPings();
|
||||
// If we have any TelemetryPings lying around, we'll be aggressive
|
||||
// and try to send them all off ASAP.
|
||||
if (TelemetryFile.pingsOverdue > 0) {
|
||||
// It doesn't really matter what we pass to this.send as a reason,
|
||||
// since it's never sent to the server. All that this.send does with
|
||||
// the reason is check to make sure it's not a test-ping.
|
||||
yield this.send("overdue-flush", this._server);
|
||||
}
|
||||
|
||||
this.attachObservers();
|
||||
this.gatherMemory();
|
||||
|
||||
Telemetry.asyncFetchTelemetryData(function () {});
|
||||
delete this._timer;
|
||||
deferred.resolve();
|
||||
}.bind(this));
|
||||
Telemetry.asyncFetchTelemetryData(function () {
|
||||
});
|
||||
delete this._timer;
|
||||
}
|
||||
|
||||
this._timer.initWithCallback(timerCallback.bind(this),
|
||||
aTesting ? TELEMETRY_TEST_DELAY : TELEMETRY_DELAY,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
testLoadHistograms: function testLoadHistograms(file) {
|
||||
return TelemetryFile.testLoadHistograms(file);
|
||||
testLoadHistograms: function testLoadHistograms(file, sync) {
|
||||
TelemetryFile.testLoadHistograms(file, sync, (success =>
|
||||
{
|
||||
let success_histogram = Telemetry.getHistogramById("READ_SAVED_PING_SUCCESS");
|
||||
success_histogram.add(success);
|
||||
}));
|
||||
},
|
||||
|
||||
getFlashVersion: function getFlashVersion() {
|
||||
@ -953,12 +950,13 @@ let Impl = {
|
||||
|
||||
savePendingPings: function savePendingPings() {
|
||||
let sessionPing = this.getSessionPayloadAndSlug("saved-session");
|
||||
return TelemetryFile.savePendingPings(sessionPing);
|
||||
TelemetryFile.savePendingPings(sessionPing);
|
||||
},
|
||||
|
||||
testSaveHistograms: function testSaveHistograms(file) {
|
||||
return TelemetryFile.savePingToFile(this.getSessionPayloadAndSlug("saved-session"),
|
||||
file.path, true);
|
||||
saveHistograms: function saveHistograms(file, sync) {
|
||||
TelemetryFile.savePingToFile(
|
||||
this.getSessionPayloadAndSlug("saved-session"),
|
||||
file, sync, true);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -979,11 +977,6 @@ let Impl = {
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
Services.obs.removeObserver(this, "application-background", false);
|
||||
#endif
|
||||
if (Telemetry.canSend) {
|
||||
return this.savePendingPings();
|
||||
} else {
|
||||
Promise.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
getPayload: function getPayload() {
|
||||
@ -1007,6 +1000,10 @@ let Impl = {
|
||||
this._slowSQLStartup = Telemetry.slowSQL;
|
||||
},
|
||||
|
||||
enableLoadSaveNotifications: function enableLoadSaveNotifications() {
|
||||
TelemetryFile.shouldNotifyUponSave = true;
|
||||
},
|
||||
|
||||
setAddOns: function setAddOns(aAddOns) {
|
||||
this._addons = aAddOns;
|
||||
},
|
||||
@ -1017,14 +1014,19 @@ let Impl = {
|
||||
this._isIdleObserver = false;
|
||||
}
|
||||
if (aTest) {
|
||||
return this.send("test-ping", aServer);
|
||||
this.send("test-ping", aServer);
|
||||
} else if (Telemetry.canSend) {
|
||||
return this.send("idle-daily", aServer);
|
||||
this.send("idle-daily", aServer);
|
||||
}
|
||||
},
|
||||
|
||||
testPing: function testPing(server) {
|
||||
return this.sendIdlePing(true, server);
|
||||
this.sendIdlePing(true, server);
|
||||
},
|
||||
|
||||
cacheProfileDirectory: function cacheProfileDirectory() {
|
||||
// This method doesn't do anything anymore
|
||||
return;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1076,6 +1078,9 @@ let Impl = {
|
||||
break;
|
||||
case "profile-before-change2":
|
||||
this.uninstall();
|
||||
if (Telemetry.canSend) {
|
||||
this.savePendingPings();
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
@ -1102,5 +1107,5 @@ let Impl = {
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -13,13 +13,11 @@ const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js", this);
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/LightweightThemeManager.jsm", this);
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryPing.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", this);
|
||||
Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/TelemetryPing.jsm");
|
||||
|
||||
const IGNORE_HISTOGRAM = "test::ignore_me";
|
||||
const IGNORE_HISTOGRAM_TO_CLONE = "MEMORY_HEAP_ALLOCATED";
|
||||
@ -38,27 +36,45 @@ const PR_TRUNCATE = 0x20;
|
||||
const RW_OWNER = 0600;
|
||||
|
||||
const NUMBER_OF_THREADS_TO_LAUNCH = 30;
|
||||
let gNumberOfThreadsLaunched = 0;
|
||||
var gNumberOfThreadsLaunched = 0;
|
||||
|
||||
const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
|
||||
let gHttpServer = new HttpServer();
|
||||
let gServerStarted = false;
|
||||
let gRequestIterator = null;
|
||||
var httpserver = new HttpServer();
|
||||
var serverStarted = false;
|
||||
var gFinished = false;
|
||||
|
||||
function sendPing () {
|
||||
function test_expired_histogram() {
|
||||
var histogram_id = "FOOBAR";
|
||||
var dummy = Telemetry.newHistogram(histogram_id, "30", 1, 2, 3, Telemetry.HISTOGRAM_EXPONENTIAL);
|
||||
|
||||
dummy.add(1);
|
||||
|
||||
do_check_eq(TelemetryPing.getPayload()["histograms"][histogram_id], undefined);
|
||||
do_check_eq(TelemetryPing.getPayload()["histograms"]["TELEMETRY_TEST_EXPIRED"], undefined);
|
||||
}
|
||||
|
||||
function telemetry_ping () {
|
||||
TelemetryPing.gatherStartup();
|
||||
if (gServerStarted) {
|
||||
return TelemetryPing.testPing("http://localhost:" + gHttpServer.identity.primaryPort);
|
||||
TelemetryPing.enableLoadSaveNotifications();
|
||||
TelemetryPing.cacheProfileDirectory();
|
||||
if (serverStarted) {
|
||||
TelemetryPing.testPing("http://localhost:" + httpserver.identity.primaryPort);
|
||||
} else {
|
||||
return TelemetryPing.testPing("http://doesnotexist");
|
||||
TelemetryPing.testPing("http://doesnotexist");
|
||||
}
|
||||
}
|
||||
|
||||
// Mostly useful so that you can dump payloads from decodeRequestPayload.
|
||||
function dummyHandler(request, response) {
|
||||
let p = decodeRequestPayload(request);
|
||||
return p;
|
||||
}
|
||||
|
||||
function wrapWithExceptionHandler(f) {
|
||||
function wrapper(...args) {
|
||||
function wrapper() {
|
||||
try {
|
||||
f(...args);
|
||||
f.apply(null, arguments);
|
||||
} catch (ex if typeof(ex) == 'object') {
|
||||
dump("Caught exception: " + ex.message + "\n");
|
||||
dump(ex.stack);
|
||||
@ -68,11 +84,29 @@ function wrapWithExceptionHandler(f) {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function addWrappedObserver(f, topic) {
|
||||
let wrappedObserver = wrapWithExceptionHandler(f);
|
||||
Services.obs.addObserver(function g(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(g, aTopic);
|
||||
wrappedObserver(aSubject, aTopic, aData);
|
||||
}, topic, false);
|
||||
}
|
||||
|
||||
function registerPingHandler(handler) {
|
||||
gHttpServer.registerPrefixHandler("/submit/telemetry/",
|
||||
httpserver.registerPrefixHandler("/submit/telemetry/",
|
||||
wrapWithExceptionHandler(handler));
|
||||
}
|
||||
|
||||
function nonexistentServerObserver(aSubject, aTopic, aData) {
|
||||
httpserver.start(-1);
|
||||
serverStarted = true;
|
||||
|
||||
// Provide a dummy function so it returns 200 instead of 404 to telemetry.
|
||||
registerPingHandler(dummyHandler);
|
||||
addWrappedObserver(telemetryObserver, "telemetry-test-xhr-complete");
|
||||
telemetry_ping();
|
||||
}
|
||||
|
||||
function setupTestData() {
|
||||
Telemetry.newHistogram(IGNORE_HISTOGRAM, "never", 1, 2, 3, Telemetry.HISTOGRAM_BOOLEAN);
|
||||
Telemetry.histogramFrom(IGNORE_CLONED_HISTOGRAM, IGNORE_HISTOGRAM_TO_CLONE);
|
||||
@ -99,6 +133,16 @@ function getSavedHistogramsFile(basename) {
|
||||
return histogramsFile;
|
||||
}
|
||||
|
||||
function telemetryObserver(aSubject, aTopic, aData) {
|
||||
registerPingHandler(checkHistogramsSync);
|
||||
let histogramsFile = getSavedHistogramsFile("saved-histograms.dat");
|
||||
setupTestData();
|
||||
|
||||
TelemetryPing.saveHistograms(histogramsFile, true);
|
||||
TelemetryPing.testLoadHistograms(histogramsFile, true);
|
||||
telemetry_ping();
|
||||
}
|
||||
|
||||
function decodeRequestPayload(request) {
|
||||
let s = request.bodyInputStream;
|
||||
let payload = null;
|
||||
@ -160,9 +204,9 @@ function checkPayloadInfo(payload, reason) {
|
||||
try {
|
||||
// If we've not got nsIGfxInfoDebug, then this will throw and stop us doing
|
||||
// this test.
|
||||
let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
|
||||
let isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
|
||||
let isOSX = ("nsILocalFileMac" in Components.interfaces);
|
||||
var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
|
||||
var isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
|
||||
var isOSX = ("nsILocalFileMac" in Components.interfaces);
|
||||
|
||||
if (isWindows || isOSX) {
|
||||
do_check_true("adapterVendorID" in payload.info);
|
||||
@ -196,7 +240,7 @@ function checkPayload(request, reason, successfulPings) {
|
||||
do_check_true(!failedProfileLocksFile.exists());
|
||||
|
||||
|
||||
let isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
|
||||
var isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
|
||||
if (isWindows) {
|
||||
do_check_true(payload.simpleMeasurements.startupSessionRestoreReadBytes > 0);
|
||||
do_check_true(payload.simpleMeasurements.startupSessionRestoreWriteBytes > 0);
|
||||
@ -268,6 +312,72 @@ function checkPayload(request, reason, successfulPings) {
|
||||
("otherThreads" in payload.slowSQL));
|
||||
}
|
||||
|
||||
function checkPersistedHistogramsSync(request, response) {
|
||||
// Even though we have had two successful pings when this handler is
|
||||
// run, we only had one successful ping when the histograms were
|
||||
// saved.
|
||||
checkPayload(request, "saved-session", 1);
|
||||
|
||||
addWrappedObserver(runAsyncTestObserver, "telemetry-test-xhr-complete");
|
||||
}
|
||||
|
||||
function checkHistogramsSync(request, response) {
|
||||
registerPingHandler(checkPersistedHistogramsSync);
|
||||
checkPayload(request, "test-ping", 1);
|
||||
}
|
||||
|
||||
function runAsyncTestObserver(aSubject, aTopic, aData) {
|
||||
registerPingHandler(checkHistogramsAsync);
|
||||
let histogramsFile = getSavedHistogramsFile("saved-histograms2.dat");
|
||||
|
||||
addWrappedObserver(function(aSubject, aTopic, aData) {
|
||||
addWrappedObserver(function(aSubject, aTopic, aData) {
|
||||
telemetry_ping();
|
||||
}, "telemetry-test-load-complete");
|
||||
|
||||
TelemetryPing.testLoadHistograms(histogramsFile, false);
|
||||
}, "telemetry-test-save-complete");
|
||||
TelemetryPing.saveHistograms(histogramsFile, false);
|
||||
}
|
||||
|
||||
function checkPersistedHistogramsAsync(request, response) {
|
||||
// do not need the http server anymore
|
||||
httpserver.stop(do_test_finished);
|
||||
// Even though we have had four successful pings when this handler is
|
||||
// run, we only had three successful pings when the histograms were
|
||||
// saved.
|
||||
checkPayload(request, "saved-session", 3);
|
||||
|
||||
runOldPingFileTest();
|
||||
|
||||
gFinished = true;
|
||||
}
|
||||
|
||||
function checkHistogramsAsync(request, response) {
|
||||
registerPingHandler(checkPersistedHistogramsAsync);
|
||||
checkPayload(request, "test-ping", 3);
|
||||
}
|
||||
|
||||
function runInvalidJSONTest() {
|
||||
let histogramsFile = getSavedHistogramsFile("invalid-histograms.dat");
|
||||
writeStringToFile(histogramsFile, "this.is.invalid.JSON");
|
||||
do_check_true(histogramsFile.exists());
|
||||
|
||||
TelemetryPing.testLoadHistograms(histogramsFile, true);
|
||||
do_check_false(histogramsFile.exists());
|
||||
}
|
||||
|
||||
function runOldPingFileTest() {
|
||||
let histogramsFile = getSavedHistogramsFile("old-histograms.dat");
|
||||
TelemetryPing.saveHistograms(histogramsFile, true);
|
||||
do_check_true(histogramsFile.exists());
|
||||
|
||||
let mtime = histogramsFile.lastModifiedTime;
|
||||
histogramsFile.lastModifiedTime = mtime - (14 * 24 * 60 * 60 * 1000 + 60000); // 14 days, 1m
|
||||
TelemetryPing.testLoadHistograms(histogramsFile, true);
|
||||
do_check_false(histogramsFile.exists());
|
||||
}
|
||||
|
||||
function dummyTheme(id) {
|
||||
return {
|
||||
id: id,
|
||||
@ -280,7 +390,7 @@ function dummyTheme(id) {
|
||||
}
|
||||
|
||||
// A fake plugin host for testing flash version telemetry
|
||||
let PluginHost = {
|
||||
var PluginHost = {
|
||||
getPluginTags: function(countRef) {
|
||||
let plugins = [{name: "Shockwave Flash", version: FLASH_VERSION}];
|
||||
countRef.value = plugins.length;
|
||||
@ -296,7 +406,7 @@ let PluginHost = {
|
||||
}
|
||||
}
|
||||
|
||||
let PluginHostFactory = {
|
||||
var PluginHostFactory = {
|
||||
createInstance: function (outer, iid) {
|
||||
if (outer != null)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
@ -308,7 +418,7 @@ const PLUGINHOST_CONTRACTID = "@mozilla.org/plugin/host;1";
|
||||
const PLUGINHOST_CID = Components.ID("{2329e6ea-1f15-4cbe-9ded-6e98e842de0e}");
|
||||
|
||||
function registerFakePluginHost() {
|
||||
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.registerFactory(PLUGINHOST_CID, "Fake Plugin Host",
|
||||
PLUGINHOST_CONTRACTID, PluginHostFactory);
|
||||
}
|
||||
@ -342,7 +452,7 @@ function write_fake_failedprofilelocks_file() {
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
try {
|
||||
let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
|
||||
var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
|
||||
gfxInfo.spoofVendorID("0xabcd");
|
||||
gfxInfo.spoofDeviceID("0x1234");
|
||||
} catch (x) {
|
||||
@ -385,6 +495,8 @@ function run_test() {
|
||||
}
|
||||
|
||||
function actualTest() {
|
||||
// ensure that test runs to completion
|
||||
do_register_cleanup(function () do_check_true(gFinished));
|
||||
// try to make LightweightThemeManager do stuff
|
||||
let gInternalManager = Cc["@mozilla.org/addons/integration;1"]
|
||||
.getService(Ci.nsIObserver)
|
||||
@ -396,99 +508,12 @@ function actualTest() {
|
||||
// fake plugin host for consistent flash version data
|
||||
registerFakePluginHost();
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Ensures that expired histograms are not part of the payload.
|
||||
add_task(function* test_expiredHistogram() {
|
||||
let histogram_id = "FOOBAR";
|
||||
let dummy = Telemetry.newHistogram(histogram_id, "30", 1, 2, 3, Telemetry.HISTOGRAM_EXPONENTIAL);
|
||||
|
||||
dummy.add(1);
|
||||
|
||||
do_check_eq(TelemetryPing.getPayload()["histograms"][histogram_id], undefined);
|
||||
do_check_eq(TelemetryPing.getPayload()["histograms"]["TELEMETRY_TEST_EXPIRED"], undefined);
|
||||
});
|
||||
|
||||
// Checks that an invalid histogram file is deleted if TelemetryFile fails to parse it.
|
||||
add_task(function* test_runInvalidJSON() {
|
||||
let histogramsFile = getSavedHistogramsFile("invalid-histograms.dat");
|
||||
|
||||
writeStringToFile(histogramsFile, "this.is.invalid.JSON");
|
||||
do_check_true(histogramsFile.exists());
|
||||
|
||||
yield TelemetryPing.testLoadHistograms(histogramsFile);
|
||||
do_check_false(histogramsFile.exists());
|
||||
});
|
||||
|
||||
// Sends a ping to a non existing server.
|
||||
add_task(function* test_noServerPing() {
|
||||
yield sendPing();
|
||||
});
|
||||
|
||||
// Checks that a sent ping is correctly received by a dummy http server.
|
||||
add_task(function* test_simplePing() {
|
||||
gHttpServer.start(-1);
|
||||
gServerStarted = true;
|
||||
gRequestIterator = Iterator(new Request());
|
||||
|
||||
yield sendPing();
|
||||
decodeRequestPayload(yield gRequestIterator.next());
|
||||
});
|
||||
|
||||
// Saves the current session histograms, reloads them, perfoms a ping
|
||||
// and checks that the dummy http server received both the previously
|
||||
// saved histograms and the new ones.
|
||||
add_task(function* test_saveLoadPing() {
|
||||
let histogramsFile = getSavedHistogramsFile("saved-histograms.dat");
|
||||
|
||||
setupTestData();
|
||||
yield TelemetryPing.testSaveHistograms(histogramsFile);
|
||||
yield TelemetryPing.testLoadHistograms(histogramsFile);
|
||||
yield sendPing();
|
||||
checkPayload((yield gRequestIterator.next()), "test-ping", 1);
|
||||
checkPayload((yield gRequestIterator.next()), "saved-session", 1);
|
||||
});
|
||||
|
||||
// Checks that an expired histogram file is deleted when loaded.
|
||||
add_task(function* test_runOldPingFile() {
|
||||
let histogramsFile = getSavedHistogramsFile("old-histograms.dat");
|
||||
|
||||
yield TelemetryPing.testSaveHistograms(histogramsFile);
|
||||
do_check_true(histogramsFile.exists());
|
||||
let mtime = histogramsFile.lastModifiedTime;
|
||||
histogramsFile.lastModifiedTime = mtime - (14 * 24 * 60 * 60 * 1000 + 60000); // 14 days, 1m
|
||||
|
||||
yield TelemetryPing.testLoadHistograms(histogramsFile);
|
||||
do_check_false(histogramsFile.exists());
|
||||
});
|
||||
|
||||
add_task(function* stopServer(){
|
||||
gHttpServer.stop(do_test_finished);
|
||||
});
|
||||
|
||||
// An iterable sequence of http requests
|
||||
function Request() {
|
||||
let defers = [];
|
||||
let current = 0;
|
||||
|
||||
function RequestIterator() {}
|
||||
|
||||
// Returns a promise that resolves to the next http request
|
||||
RequestIterator.prototype.next = function() {
|
||||
let deferred = defers[current++];
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
this.__iterator__ = function(){
|
||||
return new RequestIterator();
|
||||
}
|
||||
|
||||
registerPingHandler((request, response) => {
|
||||
let deferred = defers[defers.length - 1];
|
||||
defers.push(Promise.defer());
|
||||
deferred.resolve(request);
|
||||
});
|
||||
|
||||
defers.push(Promise.defer());
|
||||
runInvalidJSONTest();
|
||||
test_expired_histogram();
|
||||
|
||||
addWrappedObserver(nonexistentServerObserver, "telemetry-test-xhr-complete");
|
||||
telemetry_ping();
|
||||
// spin the event loop
|
||||
do_test_pending();
|
||||
do_test_finished();
|
||||
}
|
||||
|
@ -13,58 +13,57 @@
|
||||
* -> previousBuildID in telemetry, new value set in prefs.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryPing.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/TelemetryPing.jsm");
|
||||
|
||||
// Force the Telemetry enabled preference so that TelemetryPing.reset() doesn't exit early.
|
||||
Services.prefs.setBoolPref(TelemetryPing.Constants.PREF_ENABLED, true);
|
||||
|
||||
// Set up our dummy AppInfo object so we can control the appBuildID.
|
||||
Cu.import("resource://testing-common/AppInfo.jsm", this);
|
||||
Cu.import("resource://testing-common/AppInfo.jsm");
|
||||
updateAppInfo();
|
||||
|
||||
// Check that when run with no previous build ID stored, we update the pref but do not
|
||||
// put anything into the metadata.
|
||||
add_task(function* test_firstRun() {
|
||||
yield TelemetryPing.setup()
|
||||
yield TelemetryPing.reset();
|
||||
function testFirstRun() {
|
||||
TelemetryPing.reset();
|
||||
let metadata = TelemetryPing.getMetadata();
|
||||
do_check_false("previousBuildID" in metadata);
|
||||
let appBuildID = getAppInfo().appBuildID;
|
||||
let buildIDPref = Services.prefs.getCharPref(TelemetryPing.Constants.PREF_PREVIOUS_BUILDID);
|
||||
do_check_eq(appBuildID, buildIDPref);
|
||||
});
|
||||
}
|
||||
|
||||
// Check that a subsequent run with the same build ID does not put prev build ID in
|
||||
// metadata. Assumes testFirstRun() has already been called to set the previousBuildID pref.
|
||||
add_task(function* test_secondRun() {
|
||||
yield TelemetryPing.reset();
|
||||
function testSecondRun() {
|
||||
TelemetryPing.reset();
|
||||
let metadata = TelemetryPing.getMetadata();
|
||||
do_check_false("previousBuildID" in metadata);
|
||||
});
|
||||
}
|
||||
|
||||
// Set up telemetry with a different app build ID and check that the old build ID
|
||||
// is returned in the metadata and the pref is updated to the new build ID.
|
||||
// Assumes testFirstRun() has been called to set the previousBuildID pref.
|
||||
const NEW_BUILD_ID = "20130314";
|
||||
add_task(function* test_newBuild() {
|
||||
function testNewBuild() {
|
||||
let info = getAppInfo();
|
||||
let oldBuildID = info.appBuildID;
|
||||
info.appBuildID = NEW_BUILD_ID;
|
||||
yield TelemetryPing.reset();
|
||||
TelemetryPing.reset();
|
||||
let metadata = TelemetryPing.getMetadata();
|
||||
do_check_eq(metadata.previousBuildID, oldBuildID);
|
||||
let buildIDPref = Services.prefs.getCharPref(TelemetryPing.Constants.PREF_PREVIOUS_BUILDID);
|
||||
do_check_eq(NEW_BUILD_ID, buildIDPref);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function run_test() {
|
||||
// Make sure we have a profile directory.
|
||||
do_get_profile();
|
||||
run_next_test();
|
||||
testFirstRun();
|
||||
testSecondRun();
|
||||
testNewBuild();
|
||||
}
|
||||
|
@ -10,20 +10,16 @@
|
||||
* overdue and recent pings.
|
||||
*/
|
||||
|
||||
"use strict"
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://testing-common/httpd.js", this);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryFile.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryPing.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
Cu.import("resource://gre/modules/osfile.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/TelemetryFile.jsm");
|
||||
Cu.import("resource://gre/modules/TelemetryPing.jsm");
|
||||
|
||||
// We increment TelemetryFile's MAX_PING_FILE_AGE and
|
||||
// OVERDUE_PING_FILE_AGE by 1ms so that our test pings exceed
|
||||
@ -55,30 +51,25 @@ let gSeenPings = 0;
|
||||
* @returns an Array with the created pings.
|
||||
*/
|
||||
function createSavedPings(aNum, aAge) {
|
||||
return Task.spawn(function*(){
|
||||
// Create a TelemetryPing service that we can generate payloads from.
|
||||
// Luckily, the TelemetryPing constructor does nothing that we need to
|
||||
// clean up.
|
||||
let pings = [];
|
||||
let age = Date.now() - aAge;
|
||||
|
||||
for (let i = 0; i < aNum; ++i) {
|
||||
let payload = TelemetryPing.getPayload();
|
||||
let ping = { slug: "test-ping-" + gCreatedPings, reason: "test", payload: payload };
|
||||
|
||||
yield TelemetryFile.savePing(ping);
|
||||
|
||||
if (aAge) {
|
||||
// savePing writes to the file synchronously, so we're good to
|
||||
// modify the lastModifedTime now.
|
||||
let file = getSaveFileForPing(ping);
|
||||
file.lastModifiedTime = age;
|
||||
}
|
||||
gCreatedPings++;
|
||||
pings.push(ping);
|
||||
// Create a TelemetryPing service that we can generate payloads from.
|
||||
// Luckily, the TelemetryPing constructor does nothing that we need to
|
||||
// clean up.
|
||||
let pings = [];
|
||||
let age = Date.now() - aAge;
|
||||
for (let i = 0; i < aNum; ++i) {
|
||||
let payload = TelemetryPing.getPayload();
|
||||
let ping = { slug: "test-ping-" + gCreatedPings, reason: "test", payload: payload };
|
||||
TelemetryFile.savePing(ping);
|
||||
if (aAge) {
|
||||
// savePing writes to the file synchronously, so we're good to
|
||||
// modify the lastModifedTime now.
|
||||
let file = getSaveFileForPing(ping);
|
||||
file.lastModifiedTime = age;
|
||||
}
|
||||
return pings;
|
||||
});
|
||||
gCreatedPings++;
|
||||
pings.push(ping);
|
||||
}
|
||||
return pings;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,13 +101,45 @@ function getSaveFileForPing(aPing) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the number of TelemetryPings received by the
|
||||
* HttpServer is not equal to aExpectedNum.
|
||||
* Wait for PING_TIMEOUT_LENGTH ms, and make sure we didn't receive
|
||||
* TelemetryPings in that time.
|
||||
*
|
||||
* @returns Promise
|
||||
*/
|
||||
function assertReceivedNoPings() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
do_timeout(PING_TIMEOUT_LENGTH, function() {
|
||||
if (gSeenPings > 0) {
|
||||
deferred.reject();
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Promise that rejects if the number of TelemetryPings
|
||||
* received by the HttpServer is not equal to aExpectedNum.
|
||||
*
|
||||
* @param aExpectedNum the number of pings we expect to receive.
|
||||
* @returns Promise
|
||||
*/
|
||||
function assertReceivedPings(aExpectedNum) {
|
||||
do_check_eq(gSeenPings, aExpectedNum);
|
||||
let deferred = Promise.defer();
|
||||
|
||||
do_timeout(PING_TIMEOUT_LENGTH, function() {
|
||||
if (gSeenPings == aExpectedNum) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject("Saw " + gSeenPings + " TelemetryPings, " +
|
||||
"but expected " + aExpectedNum);
|
||||
}
|
||||
})
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,13 +190,11 @@ function stopHttpServer() {
|
||||
* pings to put as back in the starting state.
|
||||
*/
|
||||
function resetTelemetry() {
|
||||
return Task.spawn(function*(){
|
||||
yield TelemetryPing.uninstall();
|
||||
// Quick and dirty way to clear TelemetryFile's pendingPings
|
||||
// collection, and put it back in its initial state.
|
||||
let gen = TelemetryFile.popPendingPings();
|
||||
for (let item of gen) {};
|
||||
});
|
||||
TelemetryPing.uninstall();
|
||||
// Quick and dirty way to clear TelemetryFile's pendingPings
|
||||
// collection, and put it back in its initial state.
|
||||
let gen = TelemetryFile.popPendingPings();
|
||||
for (let item of gen) {};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,7 +202,7 @@ function resetTelemetry() {
|
||||
* mode.
|
||||
*/
|
||||
function startTelemetry() {
|
||||
return TelemetryPing.setup();
|
||||
TelemetryPing.setup();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
@ -199,21 +220,21 @@ function run_test() {
|
||||
* immediately and never sent.
|
||||
*/
|
||||
add_task(function test_expired_pings_are_deleted() {
|
||||
let expiredPings = yield createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE);
|
||||
yield startTelemetry();
|
||||
assertReceivedPings(0);
|
||||
let expiredPings = createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE);
|
||||
startTelemetry();
|
||||
yield assertReceivedNoPings();
|
||||
assertNotSaved(expiredPings);
|
||||
yield resetTelemetry();
|
||||
resetTelemetry();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that really recent pings are not sent on Telemetry initialization.
|
||||
*/
|
||||
add_task(function test_recent_pings_not_sent() {
|
||||
let recentPings = yield createSavedPings(RECENT_PINGS);
|
||||
yield startTelemetry();
|
||||
assertReceivedPings(0);
|
||||
yield resetTelemetry();
|
||||
let recentPings = createSavedPings(RECENT_PINGS);
|
||||
startTelemetry();
|
||||
yield assertReceivedNoPings();
|
||||
resetTelemetry();
|
||||
clearPings(recentPings);
|
||||
});
|
||||
|
||||
@ -223,17 +244,17 @@ add_task(function test_recent_pings_not_sent() {
|
||||
* should just be deleted.
|
||||
*/
|
||||
add_task(function test_overdue_pings_trigger_send() {
|
||||
let recentPings = yield createSavedPings(RECENT_PINGS);
|
||||
let expiredPings = yield createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE);
|
||||
let overduePings = yield createSavedPings(OVERDUE_PINGS, OVERDUE_PING_FILE_AGE);
|
||||
let recentPings = createSavedPings(RECENT_PINGS);
|
||||
let expiredPings = createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE);
|
||||
let overduePings = createSavedPings(OVERDUE_PINGS, OVERDUE_PING_FILE_AGE);
|
||||
|
||||
yield startTelemetry();
|
||||
assertReceivedPings(TOTAL_EXPECTED_PINGS);
|
||||
startTelemetry();
|
||||
yield assertReceivedPings(TOTAL_EXPECTED_PINGS);
|
||||
|
||||
assertNotSaved(recentPings);
|
||||
assertNotSaved(expiredPings);
|
||||
assertNotSaved(overduePings);
|
||||
yield resetTelemetry();
|
||||
resetTelemetry();
|
||||
});
|
||||
|
||||
add_task(function teardown() {
|
||||
|
Loading…
Reference in New Issue
Block a user