Bug 898593 - Fix intermittent failures in test_bug413958.html and others by making SimpleTest.monitorConsole() ignore unexpected messages by default. r=ted, a=test-only
authorDrew Willcoxon <adw@mozilla.com>
Fri, 06 Dec 2013 18:07:09 -0800
changeset 166710 2e2f6d2947207acc043dbe0539b07e5755f0bee7
parent 166709 0ff7a838c4be2ee1dea078b973562ddeca3a340c
child 166711 624146380bb475c339bddce04e29b40a0bbecbcb
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted, test-only
bugs898593, 413958
milestone27.0a2
Bug 898593 - Fix intermittent failures in test_bug413958.html and others by making SimpleTest.monitorConsole() ignore unexpected messages by default. r=ted, a=test-only
content/base/test/test_bug631615.html
testing/mochitest/tests/SimpleTest/SimpleTest.js
--- a/content/base/test/test_bug631615.html
+++ b/content/base/test/test_bug631615.html
@@ -27,12 +27,15 @@ function doTest() {
   } catch (e) {
     results = "throws: " + e + "\n";
   }
 
   monitor.appendChild(document.createTextNode(results));
   is(results.slice(0, 6), "throws", "looking for an exception");
 }
 
-SimpleTest.runTestExpectingConsoleMessages(doTest, []);
+SimpleTest.runTestExpectingConsoleMessages(doTest, [{
+  forbid: true,
+  message: /An invalid or illegal string was specified/
+}]);
 </script>
 </body>
 </html>
--- a/testing/mochitest/tests/SimpleTest/SimpleTest.js
+++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js
@@ -785,62 +785,112 @@ SimpleTest.finish = function () {
           });
         });
     }
 };
 
 /**
  * Monitor console output from now until endMonitorConsole is called.
  *
- * Expect to receive as many console messages as there are elements of
- * |msgs|, an array; each element is an object which may have any
- * number of the following properties:
+ * Expect to receive all console messages described by the elements of
+ * |msgs|, an array, in the order listed in |msgs|; each element is an
+ * object which may have any number of the following properties:
  *   message, errorMessage, sourceName, sourceLine, category:
  *     string or regexp
  *   lineNumber, columnNumber: number
  *   isScriptError, isWarning, isException, isStrict: boolean
  * Strings, numbers, and booleans must compare equal to the named
  * property of the Nth console message.  Regexps must match.  Any
  * fields present in the message but not in the pattern object are ignored.
  *
+ * In addition to the above properties, elements in |msgs| may have a |forbid|
+ * boolean property.  When |forbid| is true, a failure is logged each time a
+ * matching message is received.
+ *
+ * If |forbidUnexpectedMsgs| is true, then the messages received in the console
+ * must exactly match the non-forbidden messages in |msgs|; for each received
+ * message not described by the next element in |msgs|, a failure is logged.  If
+ * false, then other non-forbidden messages are ignored, but all expected
+ * messages must still be received.
+ *
  * After endMonitorConsole is called, |continuation| will be called
  * asynchronously.  (Normally, you will want to pass |SimpleTest.finish| here.)
  *
  * It is incorrect to use this function in a test which has not called
  * SimpleTest.waitForExplicitFinish.
  */
-SimpleTest.monitorConsole = function (continuation, msgs) {
+SimpleTest.monitorConsole = function (continuation, msgs, forbidUnexpectedMsgs) {
   if (SimpleTest._stopOnLoad) {
     ok(false, "Console monitoring requires use of waitForExplicitFinish.");
   }
 
+  function msgMatches(msg, pat) {
+    for (k in pat) {
+      if (!(k in msg)) {
+        return false;
+      }
+      if (pat[k] instanceof RegExp && typeof(msg[k]) === 'string') {
+        if (!pat[k].test(msg[k])) {
+          return false;
+        }
+      } else if (msg[k] !== pat[k]) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  var forbiddenMsgs = [];
+  var i = 0;
+  while (i < msgs.length) {
+    var pat = msgs[i];
+    if ("forbid" in pat) {
+      var forbid = pat.forbid;
+      delete pat.forbid;
+      if (forbid) {
+        forbiddenMsgs.push(pat);
+        msgs.splice(i, 1);
+        continue;
+      }
+    }
+    i++;
+  }
+
   var counter = 0;
   function listener(msg) {
     if (msg.message === "SENTINEL" && !msg.isScriptError) {
       is(counter, msgs.length, "monitorConsole | number of messages");
       SimpleTest.executeSoon(continuation);
-    } else if (counter >= msgs.length) {
-      ok(false, "monitorConsole | extra message | " + JSON.stringify(msg));
+      return;
+    }
+    for (var pat of forbiddenMsgs) {
+      if (msgMatches(msg, pat)) {
+        ok(false, "monitorConsole | observed forbidden message " +
+                  JSON.stringify(msg));
+        return;
+      }
+    }
+    if (counter >= msgs.length) {
+      var str = "monitorConsole | extra message | " + JSON.stringify(msg);
+      if (forbidUnexpectedMsgs) {
+        ok(false, str);
+      } else {
+        info(str);
+      }
+      return;
+    }
+    var matches = msgMatches(msg, msgs[counter]);
+    if (forbidUnexpectedMsgs) {
+      ok(matches, "monitorConsole | [" + counter + "] must match " +
+                  JSON.stringify(msg));
     } else {
-      var pat = msgs[counter];
-      for (k in pat) {
-        ok(k in msg, "monitorConsole | [" + counter + "]." + k + " present");
-        if (k in msg) {
-          if (pat[k] instanceof RegExp && typeof(msg[k]) === 'string') {
-            ok(pat[k].test(msg[k]),
-               "monitorConsole | [" + counter + "]." + k + " value - " +
-               msg[k].quote() + " contains /" + pat[k].source + "/");
-          } else {
-            ise(msg[k], pat[k],
-                "monitorConsole | [" + counter + "]." + k + " value");
-          }
-        }
-      }
-      counter++;
+      info("monitorConsole | [" + counter + "] " +
+           (matches ? "matched " : "did not match ") + JSON.stringify(msg));
     }
+    counter++;
   }
   SpecialPowers.registerConsoleListener(listener);
 };
 
 /**
  * Stop monitoring console output.
  */
 SimpleTest.endMonitorConsole = function () {