michael@0: /** Test for Bug 815105 **/ michael@0: /* michael@0: * gData is an array of object that tests using this framework must pass in michael@0: * The current tests only pass in a single element array. Each test in michael@0: * gData is executed by the framework for a given file michael@0: * michael@0: * Fields in gData object michael@0: * perms (required) Array of Strings michael@0: * list of permissions that this test will need. See michael@0: * http://mxr.mozilla.org/mozilla-central/source/dom/apps/src/PermissionsTable.jsm michael@0: * These permissions are added after a sanity check and removed at michael@0: * test conclusion michael@0: * michael@0: * obj (required for default verifier) String michael@0: * The name of the window.navigator object used for accessing the michael@0: * WebAPI during the tests michael@0: * michael@0: * webidl (required for default verifier) String michael@0: * idl (required for default verifier) String michael@0: * Only one of webidl / idl is required michael@0: * The IDL describing the navigator object. The returned object michael@0: * during tests /must/ be an instanceof this michael@0: * michael@0: * skip (optional) Array of Strings michael@0: * A list of navigator.userAgent's to skip the second part of tests michael@0: * on. The tests still verify that you can't get obj on those michael@0: * platforms without permissions, however it is expected that adding michael@0: * the permission still won't allow access to those objects michael@0: * michael@0: * settings (optional) Array of preference tuples michael@0: * A list of settings that need to be set before this API is michael@0: * enabled. Note the settings are set before the sanity check is michael@0: * performed. If an API gates access only by preferences, then it michael@0: * will fail the initial test michael@0: * michael@0: * verifier (optional) Function michael@0: * A function used to test whether a WebAPI is accessible or not. michael@0: * The function takes a success and failure callback which both michael@0: * accept a msg argument. msg is surfaced up to the top level tests michael@0: * A default verifier is provided which only attempts to access michael@0: * the navigator object. michael@0: * michael@0: * needParentPerm (optional) Boolean michael@0: * Whether or not the parent frame requires these permissions as michael@0: * well. Otherwise the test process may be killed. michael@0: */ michael@0: michael@0: SimpleTest.waitForExplicitFinish(); michael@0: var expand = SpecialPowers.Cu.import("resource://gre/modules/PermissionsTable.jsm").expandPermissions; michael@0: const permTable = SpecialPowers.Cu.import("resource://gre/modules/PermissionsTable.jsm").PermissionsTable; michael@0: michael@0: const TEST_DOMAIN = "http://example.org"; michael@0: const SHIM_PATH = "/tests/dom/permission/tests/file_shim.html" michael@0: var gContent = document.getElementById('content'); michael@0: michael@0: //var gData; defined in external files michael@0: var gCurrentTest = 0; michael@0: var gRemainingTests; michael@0: var pendingTests = {}; michael@0: michael@0: function PermTest(aData) { michael@0: var self = this; michael@0: var skip = aData.skip || false; michael@0: this.step = 0; michael@0: this.data = aData; michael@0: this.isSkip = skip && michael@0: skip.some(function (el) { michael@0: return navigator. michael@0: userAgent.toLowerCase(). michael@0: indexOf(el.toLowerCase()) != -1; michael@0: }); michael@0: michael@0: this.setupParent = false; michael@0: this.perms = expandPermissions(aData.perm); michael@0: this.id = gCurrentTest++; michael@0: this.iframe = null; michael@0: michael@0: // keep a reference to this for eventhandler michael@0: pendingTests[this.id] = this; michael@0: michael@0: this.createFrame = function() { michael@0: if (self.iframe) { michael@0: gContent.removeChild(self.iframe); michael@0: } michael@0: var iframe = document.createElement('iframe'); michael@0: iframe.setAttribute('id', 'testframe' + self.step + self.perms) michael@0: iframe.setAttribute('remote', true); michael@0: iframe.src = TEST_DOMAIN + SHIM_PATH; michael@0: iframe.addEventListener('load', function _iframeLoad() { michael@0: iframe.removeEventListener('load', _iframeLoad); michael@0: michael@0: // check permissions are correct michael@0: var allow = (self.step == 0 ? false : true); michael@0: self.perms.forEach(function (el) { michael@0: try { michael@0: var res = SpecialPowers.hasPermission(el, SpecialPowers.wrap(iframe) michael@0: .contentDocument); michael@0: is(res, allow, (allow ? "Has " : "Doesn't have ") + el); michael@0: } catch(e) { michael@0: ok(false, "failed " + e); michael@0: } michael@0: }); michael@0: michael@0: var msg = { michael@0: id: self.id, michael@0: step: self.step++, michael@0: testdata: self.data, michael@0: } michael@0: // start the tests michael@0: iframe.contentWindow.postMessage(msg, "*"); michael@0: }); michael@0: michael@0: self.iframe = iframe; michael@0: gContent.appendChild(iframe); michael@0: } michael@0: michael@0: this.next = function () { michael@0: switch(self.step) { michael@0: case 0: michael@0: self.createFrame(); michael@0: break; michael@0: case 1: michael@0: // add permissions michael@0: addPermissions(self.perms, SpecialPowers. michael@0: wrap(self.iframe). michael@0: contentDocument, michael@0: self.createFrame.bind(self)); michael@0: break; michael@0: case 2: michael@0: if (self.iframe) { michael@0: gContent.removeChild(self.iframe); michael@0: } michael@0: checkFinish(); michael@0: break; michael@0: default: michael@0: ok(false, "Should not be reached"); michael@0: break michael@0: } michael@0: } michael@0: michael@0: this.start = function() { michael@0: // some permissions need parent to have permission as well michael@0: if (!self.setupParent && self.data.needParentPerm && michael@0: !SpecialPowers.isMainProcess()) { michael@0: self.setupParent = true; michael@0: addPermissions(self.perms, window.document, self.start.bind(self)); michael@0: } else if (self.data.settings && self.data.settings.length) { michael@0: SpecialPowers.pushPrefEnv({'set': self.data.settings.slice(0)}, michael@0: self.next.bind(self)); michael@0: } else { michael@0: self.next(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: function addPermissions(aPerms, aDoc, aCallback) { michael@0: var permList = []; michael@0: aPerms.forEach(function (el) { michael@0: var obj = {'type': el, michael@0: 'allow': 1, michael@0: 'context': aDoc}; michael@0: permList.push(obj); michael@0: }); michael@0: SpecialPowers.pushPermissions(permList, aCallback); michael@0: } michael@0: michael@0: function expandPermissions(aPerms) { michael@0: var perms = []; michael@0: aPerms.forEach(function(el) { michael@0: var access = permTable[el].access ? "readwrite" : null; michael@0: var expanded = SpecialPowers.unwrap(expand(el, access)); michael@0: // COW arrays don't behave array-like enough, to allow michael@0: // using expanded.slice(0) here. michael@0: for (let i = 0; i < expanded.length; i++) { michael@0: perms.push(expanded[i]); michael@0: } michael@0: }); michael@0: michael@0: return perms; michael@0: } michael@0: michael@0: function msgHandler(evt) { michael@0: var data = evt.data; michael@0: var test = pendingTests[data.id]; michael@0: michael@0: /* michael@0: * step 2 of tests should fail on michael@0: * platforms which are skipped michael@0: */ michael@0: if (test.isSkip && test.step == 2) { michael@0: todo(data.result, data.msg); michael@0: } else { michael@0: ok(data.result, data.msg); michael@0: } michael@0: michael@0: if (test) { michael@0: test.next(); michael@0: } else { michael@0: ok(false, "Received unknown id " + data.id); michael@0: checkFinish(); michael@0: } michael@0: } michael@0: michael@0: function checkFinish() { michael@0: if (--gRemainingTests) { michael@0: gTestRunner.next(); michael@0: } else { michael@0: window.removeEventListener('message', msgHandler); michael@0: SimpleTest.finish(); michael@0: } michael@0: } michael@0: michael@0: function runTest() { michael@0: gRemainingTests = Object.keys(gData).length; michael@0: michael@0: for (var test in gData) { michael@0: var test = new PermTest(gData[test]); michael@0: test.start(); michael@0: yield undefined; michael@0: } michael@0: } michael@0: michael@0: var gTestRunner = runTest(); michael@0: michael@0: window.addEventListener('load', function() { gTestRunner.next(); }, false); michael@0: window.addEventListener('message', msgHandler, false);