gecko-dev/dom/ipc/tests/test_permission_helper.js

354 строки
12 KiB
JavaScript

"use strict";
// Used to access the DOM node in this test
const DOM_PARENT_ID = "container";
const DOM_PARENT = document.getElementById(DOM_PARENT_ID);
const APP_IFRAME_ID = "appFrame";
const APP_IFRAME_ID2 = "appFrame2";
// Settings for testing the permission
const SESSION_PERSIST_MINUTES = 10;
const PERMISSION_TYPE = "geolocation";
const permManager = SpecialPowers.Cc["@mozilla.org/permissionmanager;1"]
.getService(SpecialPowers.Ci.nsIPermissionManager);
// Used to access App's information like appId
const gAppsService = SpecialPowers.Cc["@mozilla.org/AppsService;1"]
.getService(SpecialPowers.Ci.nsIAppsService);
// Target-app for this testing
const APP_URL = "http://example.org";
const APP_MANIFEST = "http://example.org/manifest.webapp";
// Used to embed a remote app that open the test-target-app above
const embedAppHostedManifestURL = window.location.origin +
'/tests/dom/ipc/tests/file_app.sjs?testToken=test_permission_embed.html&template=file_app.template.webapp';
var embedApp;
// Used to add listener for ipc:content-shutdown that
// will be triggered after ContentParent::DeallocateTabId
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('test_permission_framescript.js'));
// Delay reporting a result until after finish() got called
SimpleTest.waitForExplicitFinish();
// Run tests in order
function runTests() {
if (!tests.length) {
ok(true, "pass all tests!");
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
function test1() {
allocateAppFrame(APP_IFRAME_ID, DOM_PARENT, APP_URL, APP_MANIFEST);
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
{ url: APP_URL,
originAttributes: { appId: appId }})) {
errorHandler('[test 1] App should have permission: ' + PERMISSION_TYPE);
}
removeAppFrame(APP_IFRAME_ID);
// We expect there is no permission for the test-target-app
// after removing the in-process iframe embedding this app
runNextIfAppHasPermission(1, false, APP_URL, APP_MANIFEST);
}
function test2() {
var afterShutdown = function () {
// We expect there is no permission for the test-target-app
// after removing the remote iframe embedding this app
runNextIfAppHasPermission(2, false, APP_URL, APP_MANIFEST);
};
// Test permission after the child-process containing
// test-target-app is killed
afterContentShutdown(1, afterShutdown);
allocateAppFrame(APP_IFRAME_ID, DOM_PARENT, APP_URL, APP_MANIFEST, true);
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
{ url: APP_URL,
originAttributes: { appId: appId }})) {
errorHandler('[test 2] App should have permission: ' + PERMISSION_TYPE);
}
removeAppFrame(APP_IFRAME_ID);
}
function test3() {
var afterGrandchildShutdown = function () {
// We expect there is no permission for the test-target-app
// after removing the remote iframe embedding this app
runNextIfAppHasPermission(3, false, APP_URL, APP_MANIFEST);
};
// Test permission after the grandchild-process
// containing test-target-app is killed
afterContentShutdown(1, afterGrandchildShutdown);
allocateAppFrame(APP_IFRAME_ID,
DOM_PARENT,
embedApp.manifest.launch_path,
embedApp.manifestURL,
true);
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
if (!SpecialPowers.hasPermission(PERMISSION_TYPE,
{ url: APP_URL,
originAttributes: { appId: appId }})) {
errorHandler('[test 3] App should have permission: ' + PERMISSION_TYPE);
}
}
function test4() {
var afterGrandchildShutdown = function () {
// We expect there is still a permission for the test-target-app
// after killing test-target-app on 3rd-level process
runNextIfAppHasPermission(4, true, APP_URL, APP_MANIFEST);
};
// Test permission after the grandchild-process
// containing test-target-app is killed
afterContentShutdown(1, afterGrandchildShutdown);
// Open a child process(2nd level) and a grandchild process(3rd level)
// that contains a test-target-app
allocateAppFrame(APP_IFRAME_ID,
DOM_PARENT,
embedApp.manifest.launch_path,
embedApp.manifestURL,
true);
// Open another child process that contains
// another test-target-app(2nd level)
allocateAppFrame(APP_IFRAME_ID2,
DOM_PARENT,
APP_URL,
APP_MANIFEST,
true);
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
if (!SpecialPowers.hasPermission(PERMISSION_TYPE,
{ url: APP_URL,
originAttributes: { appId: appId }})) {
errorHandler('[test 4] App should have permission: ' + PERMISSION_TYPE);
}
}
function test5() {
var afterShutdown = function () {
// We expect there is no permission for the test-target-app
// after crashing its parent-process
runNextIfAppHasPermission(5, false, APP_URL, APP_MANIFEST);
};
// Test permission after the parent-process of test-target-app is crashed.
afterContentShutdown(2, afterShutdown);
allocateAppFrame(APP_IFRAME_ID,
DOM_PARENT,
embedApp.manifest.launch_path + '#' + encodeURIComponent('crash'),
embedApp.manifestURL,
true);
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
{ url: APP_URL,
originAttributes: { appId: appId }})) {
errorHandler('[test 5] App should have permission: ' + PERMISSION_TYPE);
}
// Crash the child-process on 2nd level after
// the grandchild process on 3rd is allocated
var handler = {'crash': function() {
gScript.sendAsyncMessage("crashreporter-status", {});
getCrashReporterStatus(function(enable) {
if (enable) {
SimpleTest.expectChildProcessCrash();
}
crashChildProcess(APP_IFRAME_ID);
});
}
};
receiveMessageFromChildFrame(APP_IFRAME_ID, handler);
}
// Setup the prefrences and permissions.
// This function should be called before any tests
function setupPrefsAndPermissions() {
SpecialPowers.pushPrefEnv({"set": [
["dom.mozBrowserFramesEnabled", true],
["dom.ipc.tabs.nested.enabled", true],
["dom.ipc.tabs.disabled", false]]},
function() {
var autoManageApp = function () {
SpecialPowers.setAllAppsLaunchable(true);
// No confirmation needed when an app is installed and uninstalled.
SpecialPowers.autoConfirmAppInstall(() => {
// This callback should trigger the first test
SpecialPowers.autoConfirmAppUninstall(runTests);
});
};
setupOpenAppPermission(document, autoManageApp);
}
);
}
function setupOpenAppPermission(ctx, callback) {
SpecialPowers.pushPermissions([
{ "type": "browser", "allow": true, "context": ctx}, // for mozbrowser
{ "type": "embed-apps", "allow": true, "context": ctx }, // for mozapp
{ "type": "webapps-manage", "allow": true, "context": ctx }], // for (un)installing apps
function checkPermissions() {
if (SpecialPowers.hasPermission("browser", ctx) &&
SpecialPowers.hasPermission("embed-apps", ctx) &&
SpecialPowers.hasPermission("webapps-manage", ctx)) {
callback();
} else {
errorHandler(">> At least one of required permissions to open app is disallowed!\n");
}
});
}
function installApp() {
// Install App from manifest
var request = navigator.mozApps.install(embedAppHostedManifestURL);
request.onerror = cbError;
request.onsuccess = function() {
// Get installed app
embedApp = request.result; // Assign to global variable
runTests();
}
}
function uninstallApp() {
var request = navigator.mozApps.mgmt.uninstall(embedApp);
request.onerror = cbError;
request.onsuccess = function() {
info("uninstall app susseccfully!");
runTests();
}
}
function removeAppFrame(id) {
var ifr = document.getElementById(id);
ifr.remove();
}
function allocateAppFrame(id, parentNode, appSRC, manifestURL, useRemote = false) {
var ifr = document.createElement('iframe');
ifr.setAttribute('id', id);
ifr.setAttribute('remote', useRemote? "true" : "false");
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', manifestURL);
ifr.setAttribute('src', appSRC);
parentNode.appendChild(ifr);
}
function receiveMessageFromChildFrame(id, handlers) {
var ifr = document.getElementById(id);
ifr.addEventListener('mozbrowsershowmodalprompt', function (recvMsg) {
var msg = recvMsg.detail.message;
handlers[msg]();
});
}
function addPermissionToApp(appURL, manifestURL) {
var appId = gAppsService.getAppLocalIdByManifestURL(manifestURL);
// Get the time now. This is used for permission manager's expire_time
var now = Number(Date.now());
// Add app's permission asynchronously
SpecialPowers.pushPermissions([
{ "type":PERMISSION_TYPE,
"allow": 1,
"expireType":permManager.EXPIRE_SESSION,
"expireTime":now + SESSION_PERSIST_MINUTES*60*1000,
"context": { url: appURL,
originAttributes: { appId: appId } }
}
], function() {
runTests();
});
}
function runNextIfAppHasPermission(round, expect, appURL, manifestURL) {
var appId = gAppsService.getAppLocalIdByManifestURL(manifestURL);
var hasPerm = SpecialPowers.hasPermission(PERMISSION_TYPE,
{ url: appURL,
originAttributes: { appId: appId }});
var result = (expect==hasPerm);
if (result) {
runTests();
} else {
errorHandler( '[test ' + round + '] App should ' + ((expect)? '':'NOT ') +
'have permission: ' + PERMISSION_TYPE);
}
}
function afterContentShutdown(times, callback) {
// handle the message from test_permission_framescript.js
var num = 0;
gScript.addMessageListener('content-shutdown', function onShutdown(data) {
num += 1;
if (num >= times) {
gScript.removeMessageListener('content-shutdown', onShutdown);
callback();
}
});
}
function getCrashReporterStatus(callback) {
gScript.addMessageListener('crashreporter-enable', function getStatus(data) {
gScript.removeMessageListener('crashreporter-enable', getStatus);
callback(data);
});
}
// Inject a frame script that crashes the content process
function crashChildProcess(frameId) {
var child = document.getElementById(frameId);
var mm = SpecialPowers.getBrowserFrameMessageManager(child);
var childFrameScriptStr =
'function ContentScriptScope() {' +
'var Cu = Components.utils;' +
'Cu.import("resource://gre/modules/ctypes.jsm");' +
'var crash = function() {' +
'var zero = new ctypes.intptr_t(8);' +
'var badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));' +
'badptr.contents;' +
'};' +
'privateNoteIntentionalCrash();' +
'crash();' +
'}';
mm.loadFrameScript('data:,new ' + childFrameScriptStr, false);
}
function errorHandler(errMsg) {
ok(false, errMsg);
SimpleTest.finish();
}
function cbError(e) {
errorHandler("Error callback invoked: " + this.error.name);
}