diff options
Diffstat (limited to 'services/common')
-rw-r--r-- | services/common/logmanager.sys.mjs | 447 | ||||
-rw-r--r-- | services/common/moz.build | 1 | ||||
-rw-r--r-- | services/common/tests/unit/test_load_modules.js | 8 | ||||
-rw-r--r-- | services/common/tests/unit/test_logmanager.js | 330 | ||||
-rw-r--r-- | services/common/tests/unit/xpcshell.toml | 2 |
5 files changed, 2 insertions, 786 deletions
diff --git a/services/common/logmanager.sys.mjs b/services/common/logmanager.sys.mjs deleted file mode 100644 index 724cfde38b..0000000000 --- a/services/common/logmanager.sys.mjs +++ /dev/null @@ -1,447 +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;"; - -import { Log } from "resource://gre/modules/Log.sys.mjs"; - -const lazy = {}; - -ChromeUtils.defineESModuleGetters(lazy, { - FileUtils: "resource://gre/modules/FileUtils.sys.mjs", - NetUtil: "resource://gre/modules/NetUtil.sys.mjs", -}); - -const DEFAULT_MAX_ERROR_AGE = 20 * 24 * 60 * 60; // 20 days - -// "shared" logs (ie, where the same log name is used by multiple LogManager -// instances) are a fact of life here - eg, FirefoxAccounts logs are used by -// both Sync and Reading List. -// However, different instances have different pref branches, so we need to -// handle when one pref branch says "Debug" and the other says "Error" -// So we (a) keep singleton console and dump appenders and (b) keep track -// of the minimum (ie, most verbose) level and use that. -// This avoids (a) the most recent setter winning (as that is indeterminate) -// and (b) multiple dump/console appenders being added to the same log multiple -// times, which would cause messages to appear twice. - -// Singletons used by each instance. -var formatter; -var dumpAppender; -var consoleAppender; - -// A set of all preference roots used by all instances. -var allBranches = new Set(); - -const STREAM_SEGMENT_SIZE = 4096; -const PR_UINT32_MAX = 0xffffffff; - -/** - * Append to an nsIStorageStream - * - * This writes logging output to an in-memory stream which can later be read - * back as an nsIInputStream. It can be used to avoid expensive I/O operations - * during logging. Instead, one can periodically consume the input stream and - * e.g. write it to disk asynchronously. - */ -class StorageStreamAppender extends Log.Appender { - constructor(formatter) { - super(formatter); - this._name = "StorageStreamAppender"; - - this._converterStream = null; // holds the nsIConverterOutputStream - this._outputStream = null; // holds the underlying nsIOutputStream - - this._ss = null; - } - - get outputStream() { - if (!this._outputStream) { - // First create a raw stream. We can bail out early if that fails. - this._outputStream = this.newOutputStream(); - if (!this._outputStream) { - return null; - } - - // Wrap the raw stream in an nsIConverterOutputStream. We can reuse - // the instance if we already have one. - if (!this._converterStream) { - this._converterStream = Cc[ - "@mozilla.org/intl/converter-output-stream;1" - ].createInstance(Ci.nsIConverterOutputStream); - } - this._converterStream.init(this._outputStream, "UTF-8"); - } - return this._converterStream; - } - - newOutputStream() { - let ss = (this._ss = Cc["@mozilla.org/storagestream;1"].createInstance( - Ci.nsIStorageStream - )); - ss.init(STREAM_SEGMENT_SIZE, PR_UINT32_MAX, null); - return ss.getOutputStream(0); - } - - getInputStream() { - if (!this._ss) { - return null; - } - return this._ss.newInputStream(0); - } - - reset() { - if (!this._outputStream) { - return; - } - this.outputStream.close(); - this._outputStream = null; - this._ss = null; - } - - doAppend(formatted) { - if (!formatted) { - return; - } - try { - this.outputStream.writeString(formatted + "\n"); - } catch (ex) { - if (ex.result == Cr.NS_BASE_STREAM_CLOSED) { - // The underlying output stream is closed, so let's open a new one - // and try again. - this._outputStream = null; - } - try { - this.outputStream.writeString(formatted + "\n"); - } catch (ex) { - // Ah well, we tried, but something seems to be hosed permanently. - } - } - } -} - -// A storage appender that is flushable to a file on disk. Policies for -// when to flush, to what file, log rotation etc are up to the consumer -// (although it does maintain a .sawError property to help the consumer decide -// based on its policies) -class FlushableStorageAppender extends StorageStreamAppender { - constructor(formatter) { - super(formatter); - this.sawError = false; - } - - append(message) { - if (message.level >= Log.Level.Error) { - this.sawError = true; - } - StorageStreamAppender.prototype.append.call(this, message); - } - - reset() { - super.reset(); - this.sawError = false; - } - - // Flush the current stream to a file. Somewhat counter-intuitively, you - // must pass a log which will be written to with details of the operation. - async flushToFile(subdirArray, filename, log) { - let inStream = this.getInputStream(); - this.reset(); - if (!inStream) { - log.debug("Failed to flush log to a file - no input stream"); - return; - } - log.debug("Flushing file log"); - log.trace("Beginning stream copy to " + filename + ": " + Date.now()); - try { - await this._copyStreamToFile(inStream, subdirArray, filename, log); - log.trace("onCopyComplete", Date.now()); - } catch (ex) { - log.error("Failed to copy log stream to file", ex); - } - } - - /** - * Copy an input stream to the named file, doing everything off the main - * thread. - * subDirArray is an array of path components, relative to the profile - * directory, where the file will be created. - * outputFileName is the filename to create. - * Returns a promise that is resolved on completion or rejected with an error. - */ - async _copyStreamToFile(inputStream, subdirArray, outputFileName, log) { - let outputDirectory = PathUtils.join(PathUtils.profileDir, ...subdirArray); - await IOUtils.makeDirectory(outputDirectory); - let fullOutputFileName = PathUtils.join(outputDirectory, outputFileName); - - let outputStream = Cc[ - "@mozilla.org/network/file-output-stream;1" - ].createInstance(Ci.nsIFileOutputStream); - - outputStream.init( - new lazy.FileUtils.File(fullOutputFileName), - -1, - -1, - Ci.nsIFileOutputStream.DEFER_OPEN - ); - - await new Promise(resolve => - lazy.NetUtil.asyncCopy(inputStream, outputStream, () => resolve()) - ); - - outputStream.close(); - log.trace("finished copy to", fullOutputFileName); - } -} - -// The public LogManager object. -export function LogManager(prefRoot, logNames, logFilePrefix) { - this._prefObservers = []; - this.init(prefRoot, logNames, logFilePrefix); -} - -LogManager.StorageStreamAppender = StorageStreamAppender; - -LogManager.prototype = { - _cleaningUpFileLogs: false, - - init(prefRoot, logNames, logFilePrefix) { - this._prefs = Services.prefs.getBranch(prefRoot); - this._prefsBranch = prefRoot; - - this.logFilePrefix = logFilePrefix; - if (!formatter) { - // Create a formatter and various appenders to attach to the logs. - formatter = new Log.BasicFormatter(); - consoleAppender = new Log.ConsoleAppender(formatter); - dumpAppender = new Log.DumpAppender(formatter); - } - - allBranches.add(this._prefsBranch); - // We create a preference observer for all our prefs so they are magically - // reflected if the pref changes after creation. - let setupAppender = ( - appender, - prefName, - defaultLevel, - findSmallest = false - ) => { - let observer = newVal => { - let level = Log.Level[newVal] || defaultLevel; - if (findSmallest) { - // As some of our appenders have global impact (ie, there is only one - // place 'dump' goes to), we need to find the smallest value from all - // prefs controlling this appender. - // For example, if consumerA has dump=Debug then consumerB sets - // dump=Error, we need to keep dump=Debug so consumerA is respected. - for (let branch of allBranches) { - let lookPrefBranch = Services.prefs.getBranch(branch); - let lookVal = - Log.Level[lookPrefBranch.getStringPref(prefName, null)]; - if (lookVal && lookVal < level) { - level = lookVal; - } - } - } - appender.level = level; - }; - this._prefs.addObserver(prefName, observer); - this._prefObservers.push([prefName, observer]); - // and call the observer now with the current pref value. - observer(this._prefs.getStringPref(prefName, null)); - return observer; - }; - - this._observeConsolePref = setupAppender( - consoleAppender, - "log.appender.console", - Log.Level.Fatal, - true - ); - this._observeDumpPref = setupAppender( - dumpAppender, - "log.appender.dump", - Log.Level.Error, - true - ); - - // The file appender doesn't get the special singleton behaviour. - let fapp = (this._fileAppender = new FlushableStorageAppender(formatter)); - // the stream gets a default of Debug as the user must go out of their way - // to see the stuff spewed to it. - this._observeStreamPref = setupAppender( - fapp, - "log.appender.file.level", - Log.Level.Debug - ); - - // now attach the appenders to all our logs. - for (let logName of logNames) { - let log = Log.repository.getLogger(logName); - for (let appender of [fapp, dumpAppender, consoleAppender]) { - log.addAppender(appender); - } - } - // and use the first specified log as a "root" for our log. - this._log = Log.repository.getLogger(logNames[0] + ".LogManager"); - }, - - /** - * Cleanup this instance - */ - finalize() { - for (let [prefName, observer] of this._prefObservers) { - this._prefs.removeObserver(prefName, observer); - } - this._prefObservers = []; - try { - allBranches.delete(this._prefsBranch); - } catch (e) {} - this._prefs = null; - }, - - get _logFileSubDirectoryEntries() { - // At this point we don't allow a custom directory for the logs, nor allow - // it to be outside the profile directory. - // This returns an array of the the relative directory entries below the - // profile dir, and is the directory about:sync-log uses. - return ["weave", "logs"]; - }, - - get sawError() { - return this._fileAppender.sawError; - }, - - // Result values for resetFileLog. - SUCCESS_LOG_WRITTEN: "success-log-written", - ERROR_LOG_WRITTEN: "error-log-written", - - /** - * Possibly generate a log file for all accumulated log messages and refresh - * the input & output streams. - * Whether a "success" or "error" log is written is determined based on - * whether an "Error" log entry was written to any of the logs. - * Returns a promise that resolves on completion with either null (for no - * file written or on error), SUCCESS_LOG_WRITTEN if a "success" log was - * written, or ERROR_LOG_WRITTEN if an "error" log was written. - */ - async resetFileLog() { - try { - let flushToFile; - let reasonPrefix; - let reason; - if (this._fileAppender.sawError) { - reason = this.ERROR_LOG_WRITTEN; - flushToFile = this._prefs.getBoolPref( - "log.appender.file.logOnError", - true - ); - reasonPrefix = "error"; - } else { - reason = this.SUCCESS_LOG_WRITTEN; - flushToFile = this._prefs.getBoolPref( - "log.appender.file.logOnSuccess", - false - ); - reasonPrefix = "success"; - } - - // might as well avoid creating an input stream if we aren't going to use it. - if (!flushToFile) { - this._fileAppender.reset(); - return null; - } - - // We have reasonPrefix at the start of the filename so all "error" - // logs are grouped in about:sync-log. - let filename = - reasonPrefix + "-" + this.logFilePrefix + "-" + Date.now() + ".txt"; - await this._fileAppender.flushToFile( - this._logFileSubDirectoryEntries, - filename, - this._log - ); - // It's not completely clear to markh why we only do log cleanups - // for errors, but for now the Sync semantics have been copied... - // (one theory is that only cleaning up on error makes it less - // likely old error logs would be removed, but that's not true if - // there are occasional errors - let's address this later!) - if (reason == this.ERROR_LOG_WRITTEN && !this._cleaningUpFileLogs) { - this._log.trace("Running cleanup."); - try { - await this.cleanupLogs(); - } catch (err) { - this._log.error("Failed to cleanup logs", err); - } - } - return reason; - } catch (ex) { - this._log.error("Failed to resetFileLog", ex); - return null; - } - }, - - /** - * Finds all logs older than maxErrorAge and deletes them using async I/O. - */ - cleanupLogs() { - let maxAge = this._prefs.getIntPref( - "log.appender.file.maxErrorAge", - DEFAULT_MAX_ERROR_AGE - ); - let threshold = Date.now() - 1000 * maxAge; - this._log.debug("Log cleanup threshold time: " + threshold); - - let shouldDelete = fileInfo => { - return fileInfo.lastModified < threshold; - }; - return this._deleteLogFiles(shouldDelete); - }, - - /** - * Finds all logs and removes them. - */ - removeAllLogs() { - return this._deleteLogFiles(() => true); - }, - - // Delete some log files. A callback is invoked for each found log file to - // determine if that file should be removed. - async _deleteLogFiles(cbShouldDelete) { - this._cleaningUpFileLogs = true; - let logDir = lazy.FileUtils.getDir( - "ProfD", - this._logFileSubDirectoryEntries - ); - for (const path of await IOUtils.getChildren(logDir.path)) { - const name = PathUtils.filename(path); - - if (!name.startsWith("error-") && !name.startsWith("success-")) { - continue; - } - - try { - const info = await IOUtils.stat(path); - if (!cbShouldDelete(info)) { - continue; - } - - this._log.trace(` > Cleanup removing ${name} (${info.lastModified})`); - await IOUtils.remove(path); - this._log.trace(`Deleted ${name}`); - } catch (ex) { - this._log.debug( - `Encountered error trying to clean up old log file ${name}`, - ex - ); - } - } - this._cleaningUpFileLogs = false; - this._log.debug("Done deleting files."); - // This notification is used only for tests. - Services.obs.notifyObservers( - null, - "services-tests:common:log-manager:cleanup-logs" - ); - }, -}; diff --git a/services/common/moz.build b/services/common/moz.build index 144ccaff04..42c5431de8 100644 --- a/services/common/moz.build +++ b/services/common/moz.build @@ -22,7 +22,6 @@ EXTRA_JS_MODULES["services-common"] += [ "kinto-http-client.sys.mjs", "kinto-offline-client.sys.mjs", "kinto-storage-adapter.sys.mjs", - "logmanager.sys.mjs", "observers.sys.mjs", "rest.sys.mjs", "uptake-telemetry.sys.mjs", diff --git a/services/common/tests/unit/test_load_modules.js b/services/common/tests/unit/test_load_modules.js index d86165266f..f188acb4f5 100644 --- a/services/common/tests/unit/test_load_modules.js +++ b/services/common/tests/unit/test_load_modules.js @@ -6,12 +6,7 @@ const { AppConstants } = ChromeUtils.importESModule( ); const MODULE_BASE = "resource://services-common/"; -const shared_modules = [ - "async.sys.mjs", - "logmanager.sys.mjs", - "rest.sys.mjs", - "utils.sys.mjs", -]; +const shared_modules = ["async.sys.mjs", "rest.sys.mjs", "utils.sys.mjs"]; const non_android_modules = ["tokenserverclient.sys.mjs"]; @@ -51,6 +46,7 @@ function expectImportsToFail(mm, base = MODULE_BASE) { function run_test() { expectImportsToSucceed(shared_modules); expectImportsToSucceed(shared_test_modules, TEST_BASE); + expectImportsToSucceed(["LogManager.sys.mjs"], "resource://gre/modules/"); if (AppConstants.platform != "android") { expectImportsToSucceed(non_android_modules); diff --git a/services/common/tests/unit/test_logmanager.js b/services/common/tests/unit/test_logmanager.js deleted file mode 100644 index 89ac274e61..0000000000 --- a/services/common/tests/unit/test_logmanager.js +++ /dev/null @@ -1,330 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// NOTE: The sync test_errorhandler_* tests have quite good coverage for -// other aspects of this. - -const { LogManager } = ChromeUtils.importESModule( - "resource://services-common/logmanager.sys.mjs" -); -const { FileUtils } = ChromeUtils.importESModule( - "resource://gre/modules/FileUtils.sys.mjs" -); - -// Returns an array of [consoleAppender, dumpAppender, [fileAppenders]] for -// the specified log. Note that fileAppenders will usually have length=1 -function getAppenders(log) { - let capps = log.appenders.filter(app => app instanceof Log.ConsoleAppender); - equal(capps.length, 1, "should only have one console appender"); - let dapps = log.appenders.filter(app => app instanceof Log.DumpAppender); - equal(dapps.length, 1, "should only have one dump appender"); - let fapps = log.appenders.filter( - app => app instanceof LogManager.StorageStreamAppender - ); - return [capps[0], dapps[0], fapps]; -} - -// Test that the correct thing happens when no prefs exist for the log manager. -add_task(async function test_noPrefs() { - // tell the log manager to init with a pref branch that doesn't exist. - let lm = new LogManager("no-such-branch.", ["TestLog"], "test"); - - let log = Log.repository.getLogger("TestLog"); - let [capp, dapp, fapps] = getAppenders(log); - // The console appender gets "Fatal" while the "dump" appender gets "Error" levels - equal(capp.level, Log.Level.Fatal); - equal(dapp.level, Log.Level.Error); - // and the file (stream) appender gets Debug by default - equal(fapps.length, 1, "only 1 file appender"); - equal(fapps[0].level, Log.Level.Debug); - lm.finalize(); -}); - -// Test that changes to the prefs used by the log manager are updated dynamically. -add_task(async function test_PrefChanges() { - Services.prefs.setStringPref( - "log-manager.test.log.appender.console", - "Trace" - ); - Services.prefs.setStringPref("log-manager.test.log.appender.dump", "Trace"); - Services.prefs.setStringPref( - "log-manager.test.log.appender.file.level", - "Trace" - ); - let lm = new LogManager("log-manager.test.", ["TestLog2"], "test"); - - let log = Log.repository.getLogger("TestLog2"); - let [capp, dapp, [fapp]] = getAppenders(log); - equal(capp.level, Log.Level.Trace); - equal(dapp.level, Log.Level.Trace); - equal(fapp.level, Log.Level.Trace); - // adjust the prefs and they should magically be reflected in the appenders. - Services.prefs.setStringPref( - "log-manager.test.log.appender.console", - "Debug" - ); - Services.prefs.setStringPref("log-manager.test.log.appender.dump", "Debug"); - Services.prefs.setStringPref( - "log-manager.test.log.appender.file.level", - "Debug" - ); - equal(capp.level, Log.Level.Debug); - equal(dapp.level, Log.Level.Debug); - equal(fapp.level, Log.Level.Debug); - // and invalid values should cause them to fallback to their defaults. - Services.prefs.setStringPref("log-manager.test.log.appender.console", "xxx"); - Services.prefs.setStringPref("log-manager.test.log.appender.dump", "xxx"); - Services.prefs.setStringPref( - "log-manager.test.log.appender.file.level", - "xxx" - ); - equal(capp.level, Log.Level.Fatal); - equal(dapp.level, Log.Level.Error); - equal(fapp.level, Log.Level.Debug); - lm.finalize(); -}); - -// Test that the same log used by multiple log managers does the right thing. -add_task(async function test_SharedLogs() { - // create the prefs for the first instance. - Services.prefs.setStringPref( - "log-manager-1.test.log.appender.console", - "Trace" - ); - Services.prefs.setStringPref("log-manager-1.test.log.appender.dump", "Trace"); - Services.prefs.setStringPref( - "log-manager-1.test.log.appender.file.level", - "Trace" - ); - let lm1 = new LogManager("log-manager-1.test.", ["TestLog3"], "test"); - - // and the second. - Services.prefs.setStringPref( - "log-manager-2.test.log.appender.console", - "Debug" - ); - Services.prefs.setStringPref("log-manager-2.test.log.appender.dump", "Debug"); - Services.prefs.setStringPref( - "log-manager-2.test.log.appender.file.level", - "Debug" - ); - let lm2 = new LogManager("log-manager-2.test.", ["TestLog3"], "test"); - - let log = Log.repository.getLogger("TestLog3"); - let [capp, dapp] = getAppenders(log); - - // console and dump appenders should be "trace" as it is more verbose than - // "debug" - equal(capp.level, Log.Level.Trace); - equal(dapp.level, Log.Level.Trace); - - // Set the prefs on the -1 branch to "Error" - it should then end up with - // "Debug" from the -2 branch. - Services.prefs.setStringPref( - "log-manager-1.test.log.appender.console", - "Error" - ); - Services.prefs.setStringPref("log-manager-1.test.log.appender.dump", "Error"); - Services.prefs.setStringPref( - "log-manager-1.test.log.appender.file.level", - "Error" - ); - - equal(capp.level, Log.Level.Debug); - equal(dapp.level, Log.Level.Debug); - - lm1.finalize(); - lm2.finalize(); -}); - -// A little helper to test what log files exist. We expect exactly zero (if -// prefix is null) or exactly one with the specified prefix. -function checkLogFile(prefix) { - let logsdir = FileUtils.getDir("ProfD", ["weave", "logs"]); - let entries = logsdir.directoryEntries; - if (!prefix) { - // expecting no files. - ok(!entries.hasMoreElements()); - } else { - // expecting 1 file. - ok(entries.hasMoreElements()); - let logfile = entries.getNext().QueryInterface(Ci.nsIFile); - equal(logfile.leafName.slice(-4), ".txt"); - ok(logfile.leafName.startsWith(prefix + "-test-"), logfile.leafName); - // and remove it ready for the next check. - logfile.remove(false); - } -} - -// Test that we correctly write error logs by default -add_task(async function test_logFileErrorDefault() { - let lm = new LogManager("log-manager.test.", ["TestLog2"], "test"); - - let log = Log.repository.getLogger("TestLog2"); - log.error("an error message"); - await lm.resetFileLog(lm.REASON_ERROR); - // One error log file exists. - checkLogFile("error"); - - lm.finalize(); -}); - -// Test that we correctly write success logs. -add_task(async function test_logFileSuccess() { - Services.prefs.setBoolPref( - "log-manager.test.log.appender.file.logOnError", - false - ); - Services.prefs.setBoolPref( - "log-manager.test.log.appender.file.logOnSuccess", - false - ); - - let lm = new LogManager("log-manager.test.", ["TestLog2"], "test"); - - let log = Log.repository.getLogger("TestLog2"); - log.info("an info message"); - await lm.resetFileLog(); - // Zero log files exist. - checkLogFile(null); - - // Reset logOnSuccess and do it again - log should appear. - Services.prefs.setBoolPref( - "log-manager.test.log.appender.file.logOnSuccess", - true - ); - log.info("an info message"); - await lm.resetFileLog(); - - checkLogFile("success"); - - // Now test with no "reason" specified and no "error" record. - log.info("an info message"); - await lm.resetFileLog(); - // should get a "success" entry. - checkLogFile("success"); - - // With no "reason" and an error record - should get no success log. - log.error("an error message"); - await lm.resetFileLog(); - // should get no entry - checkLogFile(null); - - // And finally now with no error, to ensure that the fact we had an error - // previously doesn't persist after the .resetFileLog call. - log.info("an info message"); - await lm.resetFileLog(); - checkLogFile("success"); - - lm.finalize(); -}); - -// Test that we correctly write error logs. -add_task(async function test_logFileError() { - Services.prefs.setBoolPref( - "log-manager.test.log.appender.file.logOnError", - false - ); - Services.prefs.setBoolPref( - "log-manager.test.log.appender.file.logOnSuccess", - false - ); - - let lm = new LogManager("log-manager.test.", ["TestLog2"], "test"); - - let log = Log.repository.getLogger("TestLog2"); - log.info("an info message"); - let reason = await lm.resetFileLog(); - Assert.equal(reason, null, "null returned when no file created."); - // Zero log files exist. - checkLogFile(null); - - // Reset logOnSuccess - success logs should appear if no error records. - Services.prefs.setBoolPref( - "log-manager.test.log.appender.file.logOnSuccess", - true - ); - log.info("an info message"); - reason = await lm.resetFileLog(); - Assert.equal(reason, lm.SUCCESS_LOG_WRITTEN); - checkLogFile("success"); - - // Set logOnError and unset logOnSuccess - error logs should appear. - Services.prefs.setBoolPref( - "log-manager.test.log.appender.file.logOnSuccess", - false - ); - Services.prefs.setBoolPref( - "log-manager.test.log.appender.file.logOnError", - true - ); - log.error("an error message"); - reason = await lm.resetFileLog(); - Assert.equal(reason, lm.ERROR_LOG_WRITTEN); - checkLogFile("error"); - - // Now test with no "error" record. - log.info("an info message"); - reason = await lm.resetFileLog(); - // should get no file - Assert.equal(reason, null); - checkLogFile(null); - - // With an error record we should get an error log. - log.error("an error message"); - reason = await lm.resetFileLog(); - // should get en error log - Assert.equal(reason, lm.ERROR_LOG_WRITTEN); - checkLogFile("error"); - - // And finally now with success, to ensure that the fact we had an error - // previously doesn't persist after the .resetFileLog call. - log.info("an info message"); - await lm.resetFileLog(); - checkLogFile(null); - - lm.finalize(); -}); - -function countLogFiles() { - let logsdir = FileUtils.getDir("ProfD", ["weave", "logs"]); - let count = 0; - for (let entry of logsdir.directoryEntries) { - void entry; - count += 1; - } - return count; -} - -// Test that removeAllLogs removes all log files. -add_task(async function test_logFileError() { - Services.prefs.setBoolPref( - "log-manager.test.log.appender.file.logOnError", - true - ); - Services.prefs.setBoolPref( - "log-manager.test.log.appender.file.logOnSuccess", - true - ); - - let lm = new LogManager("log-manager.test.", ["TestLog2"], "test"); - - let log = Log.repository.getLogger("TestLog2"); - log.info("an info message"); - let reason = await lm.resetFileLog(); - Assert.equal(reason, lm.SUCCESS_LOG_WRITTEN, "success log was written."); - - log.error("an error message"); - reason = await lm.resetFileLog(); - Assert.equal(reason, lm.ERROR_LOG_WRITTEN); - - Assert.equal(countLogFiles(), 2, "expect 2 log files"); - await lm.removeAllLogs(); - Assert.equal( - countLogFiles(), - 0, - "should be no log files after removing them" - ); - - lm.finalize(); -}); diff --git a/services/common/tests/unit/xpcshell.toml b/services/common/tests/unit/xpcshell.toml index e4035f66b2..35c10dfce3 100644 --- a/services/common/tests/unit/xpcshell.toml +++ b/services/common/tests/unit/xpcshell.toml @@ -20,8 +20,6 @@ tags = "blocklist" ["test_load_modules.js"] -["test_logmanager.js"] - ["test_observers.js"] ["test_restrequest.js"] |