michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * This file provides common and shared functionality to facilitate michael@0: * testing of the Crashes component (CrashManager.jsm). michael@0: */ michael@0: michael@0: "use strict"; michael@0: michael@0: const {classes: Cc, interfaces: Ci, utils: Cu} = Components; michael@0: michael@0: this.EXPORTED_SYMBOLS = [ michael@0: "configureLogging", michael@0: "getManager", michael@0: "sleep", michael@0: "TestingCrashManager", michael@0: ]; michael@0: michael@0: Cu.import("resource://gre/modules/CrashManager.jsm", this); michael@0: Cu.import("resource://gre/modules/Log.jsm", this); michael@0: Cu.import("resource://gre/modules/osfile.jsm", this); michael@0: Cu.import("resource://gre/modules/Promise.jsm", this); michael@0: Cu.import("resource://gre/modules/Task.jsm", this); michael@0: Cu.import("resource://gre/modules/Timer.jsm", this); michael@0: michael@0: let loggingConfigured = false; michael@0: michael@0: this.configureLogging = function () { michael@0: if (loggingConfigured) { michael@0: return; michael@0: } michael@0: michael@0: let log = Log.repository.getLogger("Crashes.CrashManager"); michael@0: log.level = Log.Level.All; michael@0: let appender = new Log.DumpAppender(); michael@0: appender.level = Log.Level.All; michael@0: log.addAppender(appender); michael@0: loggingConfigured = true; michael@0: }; michael@0: michael@0: this.sleep = function (wait) { michael@0: let deferred = Promise.defer(); michael@0: michael@0: setTimeout(() => { michael@0: deferred.resolve(); michael@0: }, wait); michael@0: michael@0: return deferred.promise; michael@0: }; michael@0: michael@0: this.TestingCrashManager = function (options) { michael@0: CrashManager.call(this, options); michael@0: } michael@0: michael@0: this.TestingCrashManager.prototype = { michael@0: __proto__: CrashManager.prototype, michael@0: michael@0: createDummyDump: function (submitted=false, date=new Date(), hr=false) { michael@0: let uuid = Cc["@mozilla.org/uuid-generator;1"] michael@0: .getService(Ci.nsIUUIDGenerator) michael@0: .generateUUID() michael@0: .toString(); michael@0: uuid = uuid.substring(1, uuid.length - 1); michael@0: michael@0: let path; michael@0: let mode; michael@0: if (submitted) { michael@0: if (hr) { michael@0: path = OS.Path.join(this._submittedDumpsDir, "bp-hr-" + uuid + ".txt"); michael@0: } else { michael@0: path = OS.Path.join(this._submittedDumpsDir, "bp-" + uuid + ".txt"); michael@0: } michael@0: mode = OS.Constants.libc.S_IRUSR | OS.Constants.libc.S_IWUSR | michael@0: OS.Constants.libc.S_IRGRP | OS.Constants.libc.S_IROTH; michael@0: } else { michael@0: path = OS.Path.join(this._pendingDumpsDir, uuid + ".dmp"); michael@0: mode = OS.Constants.libc.S_IRUSR | OS.Constants.libc.S_IWUSR; michael@0: } michael@0: michael@0: return Task.spawn(function* () { michael@0: let f = yield OS.File.open(path, {create: true}, {unixMode: mode}); michael@0: yield f.setDates(date, date); michael@0: yield f.close(); michael@0: dump("Created fake crash: " + path + "\n"); michael@0: michael@0: return uuid; michael@0: }); michael@0: }, michael@0: michael@0: createIgnoredDumpFile: function (filename, submitted=false) { michael@0: let path; michael@0: if (submitted) { michael@0: path = OS.Path.join(this._submittedDumpsDir, filename); michael@0: } else { michael@0: path = OS.Path.join(this._pendingDumpsDir, filename); michael@0: } michael@0: michael@0: return Task.spawn(function* () { michael@0: let mode = OS.Constants.libc.S_IRUSR | OS.Constants.libc.S_IWUSR; michael@0: yield OS.File.open(path, {create: true}, {unixMode: mode}); michael@0: dump ("Create ignored dump file: " + path + "\n"); michael@0: }); michael@0: }, michael@0: michael@0: createEventsFile: function (filename, type, date, content, index=0) { michael@0: let path = OS.Path.join(this._eventsDirs[index], filename); michael@0: michael@0: let data = type + "\n" + michael@0: Math.floor(date.getTime() / 1000) + "\n" + michael@0: content; michael@0: let encoder = new TextEncoder(); michael@0: let array = encoder.encode(data); michael@0: michael@0: return Task.spawn(function* () { michael@0: yield OS.File.writeAtomic(path, array); michael@0: yield OS.File.setDates(path, date, date); michael@0: }); michael@0: }, michael@0: michael@0: /** michael@0: * Overwrite event file handling to process our test file type. michael@0: * michael@0: * We can probably delete this once we have actual events defined. michael@0: */ michael@0: _handleEventFilePayload: function (store, entry, type, date, payload) { michael@0: if (type == "test.1") { michael@0: if (payload == "malformed") { michael@0: return this.EVENT_FILE_ERROR_MALFORMED; michael@0: } else if (payload == "success") { michael@0: return this.EVENT_FILE_SUCCESS; michael@0: } else { michael@0: return this.EVENT_FILE_ERROR_UNKNOWN_EVENT; michael@0: } michael@0: } michael@0: michael@0: return CrashManager.prototype._handleEventFilePayload.call(this, michael@0: store, michael@0: entry, michael@0: type, michael@0: date, michael@0: payload); michael@0: }, michael@0: }; michael@0: michael@0: let DUMMY_DIR_COUNT = 0; michael@0: michael@0: this.getManager = function () { michael@0: return Task.spawn(function* () { michael@0: const dirMode = OS.Constants.libc.S_IRWXU; michael@0: let baseFile = OS.Constants.Path.profileDir; michael@0: michael@0: function makeDir(create=true) { michael@0: return Task.spawn(function* () { michael@0: let path = OS.Path.join(baseFile, "dummy-dir-" + DUMMY_DIR_COUNT++); michael@0: michael@0: if (!create) { michael@0: return path; michael@0: } michael@0: michael@0: dump("Creating directory: " + path + "\n"); michael@0: yield OS.File.makeDir(path, {unixMode: dirMode}); michael@0: michael@0: return path; michael@0: }); michael@0: } michael@0: michael@0: let pendingD = yield makeDir(); michael@0: let submittedD = yield makeDir(); michael@0: let eventsD1 = yield makeDir(); michael@0: let eventsD2 = yield makeDir(); michael@0: michael@0: // Store directory is created at run-time if needed. Ensure those code michael@0: // paths are triggered. michael@0: let storeD = yield makeDir(false); michael@0: michael@0: let m = new TestingCrashManager({ michael@0: pendingDumpsDir: pendingD, michael@0: submittedDumpsDir: submittedD, michael@0: eventsDirs: [eventsD1, eventsD2], michael@0: storeDir: storeD, michael@0: }); michael@0: michael@0: return m; michael@0: }); michael@0: };