import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,7 @@
"use strict";
module.exports = {
"extends": [
"../../../../testing/mochitest/mochitest.eslintrc.js"
]
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1,82 @@
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr, Constructor: CC } = Components;
Cu.import("resource://gre/modules/Timer.jsm");
const LocalFile = CC("@mozilla.org/file/local;1", "nsILocalFile",
"initWithPath");
const FileInputStream = CC("@mozilla.org/network/file-input-stream;1",
"nsIFileInputStream", "init");
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream", "setInputStream");
function handleRequest(request, response) {
let params = parseQueryString(request.queryString);
response.setStatusLine(request.httpVersion, 200, "OK");
// Compare and increment a cookie for this request. This is used to test
// private browsing mode; the cookie should not be set if the image is
// loaded anonymously.
if (params.has("c")) {
let expectedValue = parseInt(params.get("c"), 10);
let actualValue = !request.hasHeader("Cookie") ? 0 :
parseInt(request.getHeader("Cookie")
.replace(/^counter=(\d+)/, "$1"), 10);
if (actualValue != expectedValue) {
response.setStatusLine(request.httpVersion, 400, "Wrong counter value");
return;
}
response.setHeader("Set-Cookie", `counter=${expectedValue + 1}`, false);
}
// Wait to send the image if a timeout is given.
let timeout = parseInt(params.get("t"), 10);
if (timeout > 0) {
response.processAsync();
setTimeout(() => {
respond(params, request, response);
response.finish();
}, timeout * 1000);
return;
}
respond(params, request, response);
}
function parseQueryString(queryString) {
return queryString.split("&").reduce((params, param) => {
let [key, value] = param.split("=", 2);
params.set(key, value);
return params;
}, new Map());
}
function respond(params, request, response) {
if (params.has("s")) {
let statusCode = parseInt(params.get("s"), 10);
response.setStatusLine(request.httpVersion, statusCode, "Custom status");
return;
}
var filename = params.get("f");
writeFile(filename, response);
}
function writeFile(name, response) {
var file = new LocalFile(getState("__LOCATION__")).parent;
file.append(name);
let mimeType = Cc["@mozilla.org/uriloader/external-helper-app-service;1"]
.getService(Ci.nsIMIMEService)
.getTypeFromFile(file);
let fileStream = new FileInputStream(file, 1, 0, false);
let binaryStream = new BinaryInputStream(fileStream);
response.setHeader("Content-Type", mimeType, false);
response.bodyOutputStream.writeFrom(binaryStream, binaryStream.available());
binaryStream.close();
fileStream.close();
}

View file

@ -0,0 +1,16 @@
[DEFAULT]
support-files =
image.gif
image.png
image_server.sjs
# Synchronous tests like test_alerts.html must come before
# asynchronous tests like test_alerts_noobserve.html!
[test_alerts.html]
skip-if = toolkit == 'android'
[test_alerts_noobserve.html]
[test_alerts_requireinteraction.html]
[test_image.html]
[test_multiple_alerts.html]
[test_principal.html]
skip-if = toolkit == 'android'

View file

@ -0,0 +1,89 @@
<!DOCTYPE HTML>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<head>
<title>Test for Alerts Service</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<br>Alerts service, with observer "synchronous" case.
<br>
<br>Did a notification appear anywhere?
<br>If so, the test will finish once the notification disappears.
<pre id="test">
<script class="testbody" type="text/javascript">
var observer = {
alertShow: false,
observe: function (aSubject, aTopic, aData) {
is(aData, "foobarcookie", "Checking whether the alert cookie was passed correctly");
if (aTopic == "alertclickcallback") {
todo(false, "Did someone click the notification while running mochitests? (Please don't.)");
} else if (aTopic == "alertshow") {
ok(!this.alertShow, "Alert should not be shown more than once");
this.alertShow = true;
} else {
is(aTopic, "alertfinished", "Checking the topic for a finished notification");
SimpleTest.finish();
}
}
};
function runTest() {
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
if (!("@mozilla.org/alerts-service;1" in Cc)) {
todo(false, "Alerts service does not exist in this application");
return;
}
ok(true, "Alerts service exists in this application");
var notifier;
try {
notifier = Cc["@mozilla.org/alerts-service;1"].
getService(Ci.nsIAlertsService);
ok(true, "Alerts service is available");
} catch (ex) {
todo(false,
"Alerts service is not available.", ex);
return;
}
try {
var alertName = "fiorello";
SimpleTest.waitForExplicitFinish();
notifier.showAlertNotification(null, "Notification test",
"Surprise! I'm here to test notifications!",
false, "foobarcookie", observer, alertName);
ok(true, "showAlertNotification() succeeded. Waiting for notification...");
if ("@mozilla.org/system-alerts-service;1" in Cc) {
// Notifications are native on OS X 10.8 and later, as well as GNOME
// Shell with libnotify (bug 1236036). These notifications persist in the
// Notification Center, and only fire the `alertfinished` event when
// closed. For platforms where native notifications may be used, we need
// to close explicitly to avoid a hang. This also works for XUL
// notifications when running this test on OS X < 10.8, or a window
// manager like Ubuntu Unity with incomplete libnotify support.
notifier.closeAlert(alertName);
}
} catch (ex) {
todo(false, "showAlertNotification() failed.", ex);
SimpleTest.finish();
}
}
runTest();
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,96 @@
<!DOCTYPE HTML>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<head>
<title>Test for Alerts Service</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<br>Alerts service, without observer "asynchronous" case.
<br>
<br>A notification should soon appear somewhere.
<br>If there has been no crash when the notification (later) disappears, assume all is good.
<pre id="test">
<script class="testbody" type="text/javascript">
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
const chromeScript = SpecialPowers.loadChromeScript(_ => {
const { utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
function anyXULAlertsVisible() {
var windows = Services.wm.getEnumerator("alert:alert");
return windows.hasMoreElements();
}
addMessageListener("anyXULAlertsVisible", anyXULAlertsVisible);
addMessageListener("waitForAlerts", function waitForAlerts() {
if (anyXULAlertsVisible()) {
setTimeout(waitForAlerts, 1000);
} else {
sendAsyncMessage("waitedForAlerts");
}
});
});
function waitForAlertsThenFinish() {
chromeScript.addMessageListener("waitedForAlerts", function waitedForAlerts() {
chromeScript.removeMessageListener("waitedForAlerts", waitedForAlerts);
ok(true, "Alert disappeared.");
SimpleTest.finish();
});
chromeScript.sendAsyncMessage("waitForAlerts");
}
function runTest() {
if (!("@mozilla.org/alerts-service;1" in Cc)) {
todo(false, "Alerts service does not exist in this application");
} else {
ok(true, "Alerts service exists in this application");
var notifier;
try {
notifier = Cc["@mozilla.org/alerts-service;1"].
getService(Ci.nsIAlertsService);
ok(true, "Alerts service is available");
} catch (ex) {
todo(false, "Alerts service is not available.", ex);
}
if (notifier) {
try {
notifier.showAlertNotification(null, "Notification test",
"This notification has no observer");
ok(true, "showAlertNotification() succeeded");
} catch (ex) {
todo(false, "showAlertNotification() failed.", ex);
}
}
}
}
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
// sendSyncMessage returns an array of arrays: the outer array is from the
// message manager, and the inner array is from the chrome script's listeners.
// See the comment in test_SpecialPowersLoadChromeScript.html.
var [[alertsVisible]] = chromeScript.sendSyncMessage("anyXULAlertsVisible");
ok(!alertsVisible, "Alerts should not be present at the start of the test.");
runTest();
setTimeout(waitForAlertsThenFinish, 1000);
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,168 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for alerts with requireInteraction</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
const chromeScript = SpecialPowers.loadChromeScript(_ => {
const { utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
addMessageListener("waitForXULAlert", function() {
var timer = setTimeout(function() {
Services.ww.unregisterNotification(windowObserver);
sendAsyncMessage("waitForXULAlert", false);
}, 2000);
var windowObserver = function(aSubject, aTopic, aData) {
if (aTopic != "domwindowopened") {
return;
}
var win = aSubject.QueryInterface(Components.interfaces.nsIDOMWindow);
win.addEventListener("load", function onLoad() {
win.removeEventListener("load", onLoad);
let windowType = win.document.documentElement.getAttribute("windowtype");
if (windowType == "alert:alert") {
clearTimeout(timer);
Services.ww.unregisterNotification(windowObserver);
sendAsyncMessage("waitForXULAlert", true);
}
});
};
Services.ww.registerNotification(windowObserver);
});
});
var cookie = 0;
function promiseCreateXULAlert(alertService, listener, name) {
return new Promise(resolve => {
chromeScript.addMessageListener("waitForXULAlert", function waitedForAlert(result) {
chromeScript.removeMessageListener("waitForXULAlert", waitedForAlert);
resolve(result);
});
chromeScript.sendAsyncMessage("waitForXULAlert");
alertService.showAlertNotification(null, "title", "body",
true, cookie++, listener, name, null, null, null,
null, false, true);
});
}
add_task(function* test_require_interaction() {
if (!("@mozilla.org/alerts-service;1" in Cc)) {
todo(false, "Alerts service does not exist in this application.");
return;
}
ok(true, "Alerts service exists in this application.");
var alertService;
try {
alertService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
ok(true, "Alerts service is available.");
} catch (ex) {
todo(false, "Alerts service is not available.");
return;
}
yield SpecialPowers.pushPrefEnv({"set": [
[ "dom.webnotifications.requireinteraction.enabled", true ],
[ "dom.webnotifications.requireinteraction.count", 2 ]
]});
var expectedSequence = [
"first show",
"second show",
"second finished",
"second replacement show",
"third finished",
"first finished",
"third replacement show",
"second replacement finished",
"third replacement finished"
];
var actualSequence = [];
function createAlertListener(name, showCallback, finishCallback) {
return (subject, topic, data) => {
if (topic == "alertshow") {
actualSequence.push(name + " show");
if (showCallback) {
showCallback();
}
} else if (topic == "alertfinished") {
actualSequence.push(name + " finished");
if (finishCallback) {
finishCallback();
}
}
}
}
var xulAlertCreated = yield promiseCreateXULAlert(alertService,
createAlertListener("first"), "first");
if (!xulAlertCreated) {
ok(true, "Platform does not use XUL alerts.");
alertService.closeAlert("first");
return;
}
xulAlertCreated = yield promiseCreateXULAlert(alertService,
createAlertListener("second"), "second");
ok(xulAlertCreated, "Create XUL alert");
// Replace second alert
xulAlertCreated = yield promiseCreateXULAlert(alertService,
createAlertListener("second replacement"), "second");
ok(xulAlertCreated, "Create XUL alert");
var testFinishResolve;
var testFinishPromise = new Promise((resolve) => { testFinishResolve = resolve; });
xulAlertCreated = yield promiseCreateXULAlert(alertService,
createAlertListener("third"), "third"),
ok(!xulAlertCreated, "XUL alert should not be visible");
// Replace the not-yet-visible third alert.
xulAlertCreated = yield promiseCreateXULAlert(alertService,
createAlertListener("third replacement",
function showCallback() {
alertService.closeAlert("second");
alertService.closeAlert("third");
},
function finishCallback() {
// Check actual sequence of alert events compared to expected sequence.
for (var i = 0; i < actualSequence.length; i++) {
is(actualSequence[i], expectedSequence[i],
"Alert callback at index " + i + " should be in expected order.");
}
testFinishResolve();
}), "third");
ok(!xulAlertCreated, "XUL alert should not be visible");
alertService.closeAlert("first");
yield testFinishPromise;
});
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,118 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 1233086</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="text/javascript">
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
const Services = SpecialPowers.Services;
const imageServerURL = "http://mochi.test:8888/tests/toolkit/components/alerts/test/image_server.sjs";
function makeAlert(...params) {
var alert = Cc["@mozilla.org/alert-notification;1"]
.createInstance(Ci.nsIAlertNotification);
alert.init(...params);
return alert;
}
function promiseImage(alert, timeout = 0, userData = null) {
return new Promise(resolve => {
var isDone = false;
function done(value) {
ok(!isDone, "Should call the image listener once");
isDone = true;
resolve(value);
}
alert.loadImage(timeout, SpecialPowers.wrapCallbackObject({
onImageReady(aUserData, aRequest) {
done([true, aRequest, aUserData]);
},
onImageMissing(aUserData) {
done([false, aUserData]);
},
}), SpecialPowers.wrap(userData));
});
}
add_task(function* testContext() {
var inUserData = Cc["@mozilla.org/supports-PRInt64;1"]
.createInstance(Ci.nsISupportsPRInt64);
inUserData.data = 123;
var alert = makeAlert(null, imageServerURL + "?f=image.png");
var [ready, , userData] = yield promiseImage(alert, 0, inUserData);
ok(ready, "Should load requested image");
is(userData.QueryInterface(Ci.nsISupportsPRInt64).data, 123,
"Should pass user data for loaded image");
alert = makeAlert(null, imageServerURL + "?s=404");
[ready, userData] = yield promiseImage(alert, 0, inUserData);
ok(!ready, "Should not load missing image");
is(userData.QueryInterface(Ci.nsISupportsPRInt64).data, 123,
"Should pass user data for missing image");
});
add_task(function* testTimeout() {
var alert = makeAlert(null, imageServerURL + "?f=image.png&t=3");
var [ready] = yield promiseImage(alert, 1000);
ok(!ready, "Should cancel request if timeout fires");
[ready, request] = yield promiseImage(alert, 45000);
ok(ready, "Should load image if request finishes before timeout");
});
add_task(function* testAnimatedGIF() {
var alert = makeAlert(null, imageServerURL + "?f=image.gif");
var [ready, request] = yield promiseImage(alert);
ok(ready, "Should load first animated GIF frame");
is(request.mimeType, "image/gif", "Should report correct GIF MIME type");
is(request.image.width, 256, "GIF width should be 256px");
is(request.image.height, 256, "GIF height should be 256px");
});
add_task(function* testCancel() {
var alert = makeAlert(null, imageServerURL + "?f=image.gif&t=180");
yield new Promise((resolve, reject) => {
var request = alert.loadImage(0, SpecialPowers.wrapCallbackObject({
onImageReady() {
reject(new Error("Should not load cancelled request"));
},
onImageMissing() {
resolve();
},
}), null);
request.cancel(SpecialPowers.Cr.NS_BINDING_ABORTED);
});
});
add_task(function* testMixedContent() {
// Loading principal is HTTPS; image URL is HTTP.
var origin = "https://mochi.test:8888";
var principal = Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin(origin);
var alert = makeAlert(null, imageServerURL + "?f=image.png",
null, null, false, null, null, null,
null, principal);
var [ready, request] = yield promiseImage(alert);
ok(ready, "Should load cross-protocol image");
is(request.mimeType, "image/png", "Should report correct MIME type");
is(request.image.width, 32, "Width should be 32px");
is(request.image.height, 32, "Height should be 32px");
});
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,103 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for multiple alerts</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
const chromeScript = SpecialPowers.loadChromeScript(_ => {
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/Timer.jsm");
const alertService = Components.classes["@mozilla.org/alerts-service;1"]
.getService(Components.interfaces.nsIAlertsService);
addMessageListener("waitForPosition", function() {
var timer = setTimeout(function() {
Services.ww.unregisterNotification(windowObserver);
sendAsyncMessage("waitedForPosition", null);
}, 2000);
var windowObserver = function(aSubject, aTopic, aData) {
if (aTopic != "domwindowopened") {
return;
}
// Alerts are implemented using XUL.
clearTimeout(timer);
Services.ww.unregisterNotification(windowObserver);
var win = aSubject.QueryInterface(Components.interfaces.nsIDOMWindow);
win.addEventListener("pageshow", function onPageShow() {
win.removeEventListener("pageshow", onPageShow, false);
var x = win.screenX;
var y = win.screenY;
win.addEventListener("pagehide", function onPageHide() {
win.removeEventListener("pagehide", onPageHide, false);
sendAsyncMessage("waitedForPosition", { x, y });
}, false);
alertService.closeAlert();
}, false);
};
Services.ww.registerNotification(windowObserver);
});
});
function promiseAlertPosition(alertService) {
return new Promise(resolve => {
chromeScript.addMessageListener("waitedForPosition", function waitedForPosition(result) {
chromeScript.removeMessageListener("waitedForPosition", waitedForPosition);
resolve(result);
});
chromeScript.sendAsyncMessage("waitForPosition");
alertService.showAlertNotification(null, "title", "body");
ok(true, "Alert shown.");
});
}
add_task(function* test_multiple_alerts() {
if (!("@mozilla.org/alerts-service;1" in Cc)) {
todo(false, "Alerts service does not exist in this application.");
return;
}
ok(true, "Alerts service exists in this application.");
var alertService;
try {
alertService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
ok(true, "Alerts service is available.");
} catch (ex) {
todo(false, "Alerts service is not available.");
return;
}
var firstAlertPosition = yield promiseAlertPosition(alertService);
if (!firstAlertPosition) {
ok(true, "Platform does not use XUL alerts.");
return;
}
var secondAlertPosition = yield promiseAlertPosition(alertService);
is(secondAlertPosition.x, firstAlertPosition.x, "Second alert should be opened in the same position.");
is(secondAlertPosition.y, firstAlertPosition.y, "Second alert should be opened in the same position.");
});
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,122 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 1202933</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="text/javascript">
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
const Services = SpecialPowers.Services;
const notifier = Cc["@mozilla.org/alerts-service;1"]
.getService(Ci.nsIAlertsService);
const chromeScript = SpecialPowers.loadChromeScript(_ => {
Components.utils.import("resource://gre/modules/Services.jsm");
addMessageListener("anyXULAlertsVisible", function() {
var windows = Services.wm.getEnumerator("alert:alert");
return windows.hasMoreElements();
});
addMessageListener("getAlertSource", function() {
var alertWindows = Services.wm.getEnumerator("alert:alert");
if (!alertWindows) {
return null;
}
var alertWindow = alertWindows.getNext();
return alertWindow.document.getElementById("alertSourceLabel").getAttribute("value");
});
});
function notify(alertName, principal) {
return new Promise((resolve, reject) => {
var source;
function observe(subject, topic, data) {
if (topic == "alertclickcallback") {
reject(new Error("Alerts should not be clicked during test"));
} else if (topic == "alertshow") {
source = chromeScript.sendSyncMessage("getAlertSource")[0][0];
notifier.closeAlert(alertName);
} else {
is(topic, "alertfinished", "Should hide alert");
resolve(source);
}
}
notifier.showAlertNotification(null, "Notification test",
"Surprise! I'm here to test notifications!",
false, alertName, observe, alertName,
null, null, null, principal);
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
notifier.closeAlert(alertName);
}
});
}
function* testNoPrincipal() {
var source = yield notify("noPrincipal", null);
ok(!source, "Should omit source without principal");
}
function* testSystemPrincipal() {
var principal = Services.scriptSecurityManager.getSystemPrincipal();
var source = yield notify("systemPrincipal", principal);
ok(!source, "Should omit source for system principal");
}
function* testNullPrincipal() {
var principal = Services.scriptSecurityManager.createNullPrincipal({});
var source = yield notify("nullPrincipal", principal);
ok(!source, "Should omit source for null principal");
}
function* testNodePrincipal() {
var principal = SpecialPowers.wrap(document).nodePrincipal;
var source = yield notify("nodePrincipal", principal);
var stringBundle = Services.strings.createBundle(
"chrome://alerts/locale/alert.properties"
);
var localizedSource = stringBundle.formatStringFromName(
"source.label", [principal.URI.hostPort], 1);
is(source, localizedSource, "Should include source for node principal");
}
function runTest() {
if (!("@mozilla.org/alerts-service;1" in Cc)) {
todo(false, "Alerts service does not exist in this application");
return;
}
if ("@mozilla.org/system-alerts-service;1" in Cc) {
todo(false, "Native alerts service exists in this application");
return;
}
ok(true, "Alerts service exists in this application");
// sendSyncMessage returns an array of arrays. See the comments in
// test_alerts_noobserve.html and test_SpecialPowersLoadChromeScript.html.
var [[alertsVisible]] = chromeScript.sendSyncMessage("anyXULAlertsVisible");
ok(!alertsVisible, "Alerts should not be present at the start of the test.");
add_task(testNoPrincipal);
add_task(testSystemPrincipal);
add_task(testNullPrincipal);
add_task(testNodePrincipal);
}
runTest();
</script>
</pre>
</body>
</html>