diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 782de64457f3..8676ee63c42b 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -40,6 +40,7 @@ #include "nsJSEnvironment.h" #include "nsJSUtils.h" +#include "mozilla/ChaosMode.h" #include "mozilla/EventStateManager.h" #include "mozilla/MiscEvents.h" #include "mozilla/MouseEvents.h" @@ -3776,6 +3777,22 @@ nsDOMWindowUtils::GetServiceWorkersTestingEnabled(bool *aEnabled) return NS_OK; } +NS_IMETHODIMP +nsDOMWindowUtils::EnterChaosMode() +{ + MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome()); + ChaosMode::enterChaosMode(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMWindowUtils::LeaveChaosMode() +{ + MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome()); + ChaosMode::leaveChaosMode(); + return NS_OK; +} + NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList) diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 20e765585c3e..6e829a744360 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -49,7 +49,7 @@ interface nsIJSRAIIHelper; interface nsIContentPermissionRequest; interface nsIObserver; -[scriptable, uuid(7719798a-62fa-4dff-a6ed-782256649232)] +[scriptable, uuid(098d9f0d-7809-4d3c-8fc6-e5b3fb71835b)] interface nsIDOMWindowUtils : nsISupports { /** @@ -1812,6 +1812,19 @@ interface nsIDOMWindowUtils : nsISupports { * Enable some service workers testing features. */ attribute boolean serviceWorkersTestingEnabled; + + /** + * Increase the chaos mode activation level. An equivalent number of + * calls to leaveChaosMode must be made in order to restore the original + * chaos mode state. If the activation level is nonzero all chaos mode + * features are activated. + */ + void enterChaosMode(); + + /** + * Decrease the chaos mode activation level. See enterChaosMode(). + */ + void leaveChaosMode(); }; [scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)] diff --git a/layout/tools/reftest/reftest.js b/layout/tools/reftest/reftest.js index 69a7285b75e9..5721021fcfd7 100644 --- a/layout/tools/reftest/reftest.js +++ b/layout/tools/reftest/reftest.js @@ -885,8 +885,9 @@ function ReadManifest(aURL, inherited_status) var refPrefSettings = defaultRefPrefSettings.concat(); var fuzzy_max_delta = 2; var fuzzy_max_pixels = 1; + var chaosMode = false; - while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy)/)) { + while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy|chaos-mode)/)) { var item = items.shift(); var stat; var cond; @@ -965,6 +966,9 @@ function ReadManifest(aURL, inherited_status) fuzzy_max_delta = Number(m[2]); fuzzy_max_pixels = Number(m[3]); } + } else if (item == "chaos-mode") { + cond = false; + chaosMode = true; } else { throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unexpected item " + item; } @@ -1053,7 +1057,8 @@ function ReadManifest(aURL, inherited_status) fuzzyMaxDelta: fuzzy_max_delta, fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, - url2: null }); + url2: null, + chaosMode: chaosMode }); } else if (items[0] == TYPE_SCRIPT) { if (items.length != 2) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to script"; @@ -1079,7 +1084,8 @@ function ReadManifest(aURL, inherited_status) fuzzyMaxDelta: fuzzy_max_delta, fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, - url2: null }); + url2: null, + chaosMode: chaosMode }); } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL) { if (items.length != 3) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to " + items[0]; @@ -1108,7 +1114,8 @@ function ReadManifest(aURL, inherited_status) fuzzyMaxDelta: fuzzy_max_delta, fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, - url2: refURI }); + url2: refURI, + chaosMode: chaosMode }); } else { throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unknown test type " + items[0]; } @@ -1242,6 +1249,9 @@ function StartCurrentTest() } else { gDumpLog("REFTEST TEST-START | " + gURLs[0].prettyPath + "\n"); + if (gURLs[0].chaosMode) { + gWindowUtils.enterChaosMode(); + } if (!gURLs[0].needsFocus) { Blur(); } @@ -1863,6 +1873,9 @@ function DoAssertionCheck(numAsserts) } } + if (gURLs[0].chaosMode) { + gWindowUtils.leaveChaosMode(); + } gDumpLog("REFTEST TEST-END | " + gURLs[0].prettyPath + "\n"); // And start the next test. diff --git a/mfbt/ChaosMode.cpp b/mfbt/ChaosMode.cpp new file mode 100644 index 000000000000..d33258f5ce57 --- /dev/null +++ b/mfbt/ChaosMode.cpp @@ -0,0 +1,15 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "mozilla/ChaosMode.h" + +namespace mozilla { +namespace detail { + +Atomic gChaosModeCounter(0); + +} /* namespace detail */ +} /* namespace mozilla */ diff --git a/mfbt/ChaosMode.h b/mfbt/ChaosMode.h index 4fd48a84623a..9378f6651548 100644 --- a/mfbt/ChaosMode.h +++ b/mfbt/ChaosMode.h @@ -7,6 +7,7 @@ #ifndef mozilla_ChaosMode_h #define mozilla_ChaosMode_h +#include "mozilla/Atomics.h" #include "mozilla/EnumSet.h" #include @@ -14,6 +15,10 @@ namespace mozilla { +namespace detail { +extern MFBT_DATA Atomic gChaosModeCounter; +} + /** * When "chaos mode" is activated, code that makes implicitly nondeterministic * choices is encouraged to make random and extreme choices, to test more @@ -44,9 +49,32 @@ private: public: static bool isActive(ChaosFeature aFeature) { + if (detail::gChaosModeCounter > 0) { + return true; + } return sChaosFeatures & aFeature; } + /** + * Increase the chaos mode activation level. An equivalent number of + * calls to leaveChaosMode must be made in order to restore the original + * chaos mode state. If the activation level is nonzero all chaos mode + * features are activated. + */ + static void enterChaosMode() + { + detail::gChaosModeCounter++; + } + + /** + * Decrease the chaos mode activation level. See enterChaosMode(). + */ + static void leaveChaosMode() + { + MOZ_ASSERT(detail::gChaosModeCounter > 0); + detail::gChaosModeCounter--; + } + /** * Returns a somewhat (but not uniformly) random uint32_t < aBound. * Not to be used for anything except ChaosMode, since it's not very random. diff --git a/mfbt/objs.mozbuild b/mfbt/objs.mozbuild index a1badda852df..444851a1839d 100644 --- a/mfbt/objs.mozbuild +++ b/mfbt/objs.mozbuild @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. mfbt_src_lcppsrcs = [ + 'ChaosMode.cpp', 'double-conversion/bignum-dtoa.cc', 'double-conversion/bignum.cc', 'double-conversion/cached-powers.cc', diff --git a/testing/mochitest/tests/SimpleTest/SimpleTest.js b/testing/mochitest/tests/SimpleTest/SimpleTest.js index 20df877fbdb0..08c6e590b097 100644 --- a/testing/mochitest/tests/SimpleTest/SimpleTest.js +++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js @@ -240,6 +240,7 @@ SimpleTest._stopOnLoad = true; SimpleTest._cleanupFunctions = []; SimpleTest.expected = 'pass'; SimpleTest.num_failed = 0; +SimpleTest._inChaosMode = false; SimpleTest.setExpected = function () { if (parent.TestRunner) { @@ -992,6 +993,15 @@ SimpleTest.registerCleanupFunction = function(aFunc) { SimpleTest._cleanupFunctions.push(aFunc); }; +SimpleTest.testInChaosMode = function() { + if (SimpleTest._inChaosMode) { + // It's already enabled for this test, don't enter twice + return; + } + SpecialPowers.DOMWindowUtils.enterChaosMode(); + SimpleTest._inChaosMode = true; +}; + /** * Finishes the tests. This is automatically called, except when * SimpleTest.waitForExplicitFinish() has been invoked. @@ -1020,6 +1030,11 @@ SimpleTest.finish = function() { SimpleTest._alreadyFinished = true; + if (SimpleTest._inChaosMode) { + SpecialPowers.DOMWindowUtils.leaveChaosMode(); + SimpleTest._inChaosMode = false; + } + var afterCleanup = function() { if (SpecialPowers.DOMWindowUtils.isTestControllingRefreshes) { SimpleTest.ok(false, "test left refresh driver under test control");