Bug: Intermittent toolkit/components/nimbus/test/unit/test_RemoteSettingsExperimentLoader.js | single tracking bug
Status: RESOLVED
Priority: P5
Resolution: DUPLICATE
Created: 2022-06-21 20:02:28+00:00
Resolved: 2022-06-21 21:41:25+00:00

**Filed by:** ccozmuta [at] mozilla.com
**Parsed log:** https://treeherder.mozilla.org/logviewer?job_id=382063827&repo=autoland
**Full log:** https://firefox-ci-tc.services.mozilla.com/api/queue/v1/task/ED-ufYh9TlGKy4O8ThxHBw/runs/0/artifacts/public/logs/live_backing.log

---
```
[task 2022-06-21T19:50:17.201Z] 19:50:17     INFO -  TEST-START | toolkit/components/nimbus/test/unit/test_RemoteSettingsExperimentLoader.js
[task 2022-06-21T19:50:18.466Z] 19:50:18  WARNING -  TEST-UNEXPECTED-FAIL | toolkit/components/nimbus/test/unit/test_RemoteSettingsExperimentLoader.js | xpcshell return code: 0
[task 2022-06-21T19:50:18.466Z] 19:50:18     INFO -  TEST-INFO took 1264ms
[task 2022-06-21T19:50:18.466Z] 19:50:18     INFO -  >>>>>>>
[task 2022-06-21T19:50:18.466Z] 19:50:18     INFO -  TEST-PASS | toolkit/components/nimbus/test/unit/test_RemoteSettingsExperimentLoader.js | getTempFile - [getTempFile : 55] Sanity check the temporary file doesn't exist. - true == true
[task 2022-06-21T19:50:18.467Z] 19:50:18     INFO -  (xpcshell/head.js) | test MAIN run_test pending (1)
[task 2022-06-21T19:50:18.467Z] 19:50:18     INFO -  (xpcshell/head.js) | test run_next_test 0 pending (2)
[task 2022-06-21T19:50:18.467Z] 19:50:18     INFO -  (xpcshell/head.js) | test MAIN run_test finished (2)
[task 2022-06-21T19:50:18.467Z] 19:50:18     INFO -  running event loop
[task 2022-06-21T19:50:18.468Z] 19:50:18     INFO -  toolkit/components/nimbus/test/unit/test_RemoteSettingsExperimentLoader.js | Starting test_real_exp_manager
[task 2022-06-21T19:50:18.469Z] 19:50:18     INFO -  (xpcshell/head.js) | test test_real_exp_manager pending (2)
[task 2022-06-21T19:50:18.479Z] 19:50:18     INFO -  TEST-PASS | toolkit/components/nimbus/test/unit/test_RemoteSettingsExperimentLoader.js | test_real_exp_manager - [test_real_exp_manager : 21] should reference ExperimentManager singleton by default - {"id":"experimentmanager","store":{"_sharedDataKey":"ExperimentStoreData","_isParent":true,"_isReady":false,"_readyDeferred":{"resolve":"function () {\\n    [native code]\\n}","reject":"function () {\\n    [native code]\\n}","promise":{}},"_data":null,"_store":{"path":"undefined","_saver":{"_taskFn":"() => this._save()","_delayMs":1500,"_timeoutMs":"undefined","_caller":"JSONFile@resource://gre/modules/JSONFile.jsm:125:17"},"_options":{},"_finalizeAt":{"name":"IOUtils: waiting for profileBeforeChange IO to complete","addBlocker":"(name, condition, details) => {\\n      if (typeof name != \\"string\\") {\\n        throw new TypeError(\\"Expected a human-readable name as first argument\\");\\n      }\\n      if (details && typeof details == \\"function\\") {\\n        details = {\\n          fetchState: details,\\n        };\\n      } else if (!details) {\\n        details = {};\\n      }\\n      if (typeof details != \\"object\\") {\\n        throw new TypeError(\\n          \\"Expected an object as third argument to `addBlocker`, got \\" + details\\n        );\\n      }\\n      if (!this._waitForMe) {\\n        throw new Error(\\n          `Phase \\"${this._name}\\" is finished, it is too late to register completion condition \\"${name}\\"`\\n        );\\n      }\\n      debug(`Adding blocker ${name} for phase ${this._name}`);\\n\\n      // Normalize the details\\n\\n      let fetchState = details.fetchState || null;\\n      if (fetchState != null && typeof fetchState != \\"function\\") {\\n        throw new TypeError(\\"Expected a function for option `fetchState`\\");\\n      }\\n      let filename = details.filename || null;\\n      let lineNumber = details.lineNumber || null;\\n      let stack = details.stack || null;\\n\\n      // Split the condition between a trigger function and a promise.\\n\\n      // The function to call to notify the blocker that we have started waiting.\\n      // This function returns a promise resolved/rejected once the\\n      // condition is complete, and never throws.\\n      let trigger;\\n\\n      // A promise resolved once the condition is complete.\\n      let promise;\\n      if (typeof condition == \\"function\\") {\\n        promise = new Promise((resolve, reject) => {\\n          trigger = () => {\\n            try {\\n              resolve(condition());\\n            } catch (ex) {\\n              reject(ex);\\n            }\\n          };\\n        });\\n      } else {\\n        // If `condition` is not a function, `trigger` is not particularly\\n        // interesting, and `condition` needs to be normalized to a promise.\\n        trigger = () => {};\\n        promise = Promise.resolve(condition);\\n      }\\n\\n      // Make sure that `promise` never rejects.\\n      promise = promise\\n        .catch(error => {\\n          let msg = `A blocker encountered an error while we were waiting.\\n          Blocker:  ${name}\\n          Phase: ${this._name}\\n          State: ${safeGetState(fetchState)}`;\\n          warn(msg, error);\\n\\n          // The error should remain uncaught, to ensure that it\\n          // still causes tests to fail.\\n          Promise.reject(error);\\n        })\\n        .catch\\n        // Added as a last line of defense, in case `warn`, `this._name` or\\n        // `safeGetState` somehow throws an error.\\n        ();\\n\\n      let topFrame = null;\\n      if (filename == null || lineNumber == null || stack == null) {\\n        topFrame = Components.stack;\\n      }\\n\\n      let blocker = {\\n        trigger,\\n        promise,\\n        name,\\n        fetchState,\\n        getOrigin: () => getOrigin(topFrame, filename, lineNumber, stack),\\n      };\\n\\n      this._waitForMe.add(promise);\\n      this._promiseToBlocker.set(promise, blocker);\\n      this._conditionToPromise.set(condition, promise);\\n\\n      // As conditions may hold lots of memory, we attempt to cleanup\\n      // as soon as we are done (which might be in the next tick, if\\n      // we have been passed a resolved promise).\\n      promise = promise.then(() => {\\n        debug(`Completed blocker ${name} for phase ${this._name}`);\\n        this._removeBlocker(condition);\\n      });\\n\\n      if (this._isStarted) {\\n        // The wait has already started. The blocker should be\\n        // notified asap. We do it out of band as clients probably\\n        // expect `addBlocker` to return immediately.\\n        Promise.resolve().then(trigger);\\n      }\\n    }","removeBlocker":"condition => {\\n      return this._removeBlocker(condition);\\n    }"},"_finalizeInternalBound":"function() {\\n    [native code]\\n}"}},"sessions":{}} == {"id":"experimentmanager","store":{"_sharedDataKey":"ExperimentStoreData","_isParent":true,"_isReady":false,"_readyDeferred":{"resolve":"function () {\\n    [native code]\\n}","reject":"function () {\\n    [native code]\\n}","promise":{}},"_data":null,"_store":{"path":"undefined","_saver":{"_taskFn":"() => this._save()","_delayMs":1500,"_timeoutMs":"undefined","_caller":"JSONFile@resource://gre/modules/JSONFile.jsm:125:17"},"_options":{},"_finalizeAt":{"name":"IOUtils: waiting for profileBeforeChange IO to complete","addBlocker":"(name, condition, details) => {\\n      if (typeof name != \\"string\\") {\\n        throw new TypeError(\\"Expected a human-readable name as first argument\\");\\n      }\\n      if (details && typeof details == \\"function\\") {\\n        details = {\\n          fetchState: details,\\n        };\\n      } else if (!details) {\\n        details = {};\\n      }\\n      if (typeof details != \\"object\\") {\\n        throw new TypeError(\\n          \\"Expected an object as third argument to `addBlocker`, got \\" + details\\n        );\\n      }\\n      if (!this._waitForMe) {\\n        throw new Error(\\n          `Phase \\"${this._name}\\" is finished, it is too late to register completion condition \\"${name}\\"`\\n        );\\n      }\\n      debug(`Adding blocker ${name} for phase ${this._name}`);\\n\\n      // Normalize the details\\n\\n      let fetchState = details.fetchState || null;\\n      if (fetchState != null && typeof fetchState != \\"function\\") {\\n        throw new TypeError(\\"Expected a function for option `fetchState`\\");\\n      }\\n      let filename = details.filename || null;\\n      let lineNumber = details.lineNumber || null;\\n      let stack = details.stack || null;\\n\\n      // Split the condition between a trigger function and a promise.\\n\\n      // The function to call to notify the blocker that we have started waiting.\\n      // This function returns a promise resolved/rejected once the\\n      // condition is complete, and never throws.\\n      let trigger;\\n\\n      // A promise resolved once the condition is complete.\\n      let promise;\\n      if (typeof condition == \\"function\\") {\\n        promise = new Promise((resolve, reject) => {\\n          trigger = () => {\\n            try {\\n              resolve(condition());\\n            } catch (ex) {\\n              reject(ex);\\n            }\\n          };\\n        });\\n      } else {\\n        // If `condition` is not a function, `trigger` is not particularly\\n        // interesting, and `condition` needs to be normalized to a promise.\\n        trigger = () => {};\\n        promise = Promise.resolve(condition);\\n      }\\n\\n      // Make sure that `promise` never rejects.\\n      promise = promise\\n        .catch(error => {\\n          let msg = `A blocker encountered an error while we were waiting.\\n          Blocker:  ${name}\\n          Phase: ${this._name}\\n          State: ${safeGetState(fetchState)}`;\\n          warn(msg, error);\\n\\n          // The error should remain uncaught, to ensure that it\\n          // still causes tests to fail.\\n          Promise.reject(error);\\n        })\\n        .catch\\n        // Added as a last line of defense, in case `warn`, `this._name` or\\n        // `safeGetState` somehow throws an error.\\n        ();\\n\\n      let topFrame = null;\\n      if (filename == null || lineNumber == null || stack == null) {\\n        topFrame = Components.stack;\\n      }\\n\\n      let blocker = {\\n        trigger,\\n        promise,\\n        name,\\n        fetchState,\\n        getOrigin: () => getOrigin(topFrame, filename, lineNumber, stack),\\n      };\\n\\n      this._waitForMe.add(promise);\\n      this._promiseToBlocker.set(promise, blocker);\\n      this._conditionToPromise.set(condition, promise);\\n\\n      // As conditions may hold lots of memory, we attempt to cleanup\\n      // as soon as we are done (which might be in the next tick, if\\n      // we have been passed a resolved promise).\\n      promise = promise.then(() => {\\n        debug(`Completed blocker ${name} for phase ${this._name}`);\\n        this._removeBlocker(condition);\\n      });\\n\\n      if (this._isStarted) {\\n        // The wait has already started. The blocker should be\\n        // notified asap. We do it out of band as clients probably\\n        // expect `addBlocker` to return immediately.\\n        Promise.resolve().then(trigger);\\n      }\\n    }","removeBlocker":"condition => {\\n      return this._removeBlocker(condition);\\n    }"},"_finalizeInternalBound":"function() {\\n    [native code]\\n}"}},"sessions":{}}
[task 2022-06-21T19:50:18.483Z] 19:50:18     INFO -  (xpcshell/head.js) | test run_next_test 0 finished (2)
[task 2022-06-21T19:50:18.484Z] 19:50:18     INFO -  (xpcshell/head.js) | test run_next_test 1 pending (2)
[task 2022-06-21T19:50:18.484Z] 19:50:18     INFO -  (xpcshell/head.js) | test test_real_exp_manager finished (2)
```