summaryrefslogtreecommitdiffstats
path: root/dom/permission/tests/file_framework.js
blob: 27624f91e6eda958728f4f540e08e0ec9460e726 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/** Test for Bug 815105 **/
/*
 * gData is an array of object that tests using this framework must pass in
 * The current tests only pass in a single element array. Each test in
 * gData is executed by the framework for a given file
 *
 * Fields in gData object
 * perms   (required) Array of Strings
 *         list of permissions that this test will need. See
 *         http://dxr.mozilla.org/mozilla-central/source/dom/apps/src/PermissionsTable.jsm
 *         These permissions are added after a sanity check and removed at
 *         test conclusion
 *
 * obj     (required for default verifier) String
 *         The name of the window.navigator object used for accessing the
 *         WebAPI during the tests
 *
 * webidl  (required for default verifier) String
 * idl     (required for default verifier) String
 *         Only one of webidl / idl is required
 *         The IDL describing the navigator object. The returned object
 *         during tests /must/ be an instanceof this
 *
 * skip    (optional) Array of Strings
 *         A list of navigator.userAgent's to skip the second part of tests
 *         on. The tests still verify that you can't get obj on those
 *         platforms without permissions, however it is expected that adding
 *         the permission still won't allow access to those objects
 *
 * settings (optional) Array of preference tuples
 *         A list of settings that need to be set before this API is
 *         enabled. Note the settings are set before the sanity check is
 *         performed. If an API gates access only by preferences, then it
 *         will fail the initial test
 *
 * verifier (optional) Function
 *         A function used to test whether a WebAPI is accessible or not.
 *         The function takes a success and failure callback which both
 *         accept a msg argument. msg is surfaced up to the top level tests
 *         A default verifier is provided which only attempts to access
 *         the navigator object.
 *
 * needParentPerm (optional) Boolean
 *         Whether or not the parent frame requires these permissions as
 *         well. Otherwise the test process may be killed.
 */

SimpleTest.waitForExplicitFinish();
var expand = SpecialPowers.Cu.import("resource://gre/modules/PermissionsTable.jsm").expandPermissions;
const permTable = SpecialPowers.Cu.import("resource://gre/modules/PermissionsTable.jsm").PermissionsTable;

const TEST_DOMAIN = "http://example.org";
const SHIM_PATH = "/tests/dom/permission/tests/file_shim.html"
var gContent = document.getElementById('content');

//var gData; defined in external files
var gCurrentTest = 0;
var gRemainingTests;
var pendingTests = {};

function PermTest(aData) {
  var self = this;
  var skip = aData.skip || false;
  this.step = 0;
  this.data = aData;
  this.isSkip = skip &&
                skip.some(function (el) {
                          return navigator.
                                 userAgent.toLowerCase().
                                 indexOf(el.toLowerCase()) != -1;
                        });

  this.setupParent = false;
  this.perms = expandPermissions(aData.perm);
  this.id = gCurrentTest++;
  this.iframe = null;

  // keep a reference to this for eventhandler
  pendingTests[this.id] = this;

  this.createFrame = function() {
    if (self.iframe) {
      gContent.removeChild(self.iframe);
    }
    var iframe = document.createElement('iframe');
    iframe.setAttribute('id', 'testframe' + self.step + self.perms)
    iframe.setAttribute('remote', true);
    iframe.src = TEST_DOMAIN + SHIM_PATH;
    iframe.addEventListener('load', function _iframeLoad() {
      iframe.removeEventListener('load', _iframeLoad);

      // check permissions are correct
      var allow = (self.step == 0 ? false : true);
      self.perms.forEach(function (el) {
        try {
        var res = SpecialPowers.hasPermission(el, SpecialPowers.wrap(iframe)
                                                  .contentDocument);
        is(res, allow, (allow ? "Has " : "Doesn't have ") + el);
        } catch(e) {
          ok(false, "failed " + e);
        }
      });

      var msg = {
        id: self.id,
        step: self.step++,
        testdata: self.data,
      }
      // start the tests
      iframe.contentWindow.postMessage(msg, "*");
    });

    self.iframe = iframe;
    gContent.appendChild(iframe);
  }

  this.next = function () {
    switch(self.step) {
    case 0:
      self.createFrame();
    break;
    case 1:
      // add permissions
      addPermissions(self.perms, SpecialPowers.
                                 wrap(self.iframe).
                                 contentDocument,
                     self.createFrame.bind(self));
    break;
    case 2:
      if (self.iframe) {
        gContent.removeChild(self.iframe);
      }
      checkFinish();
    break;
    default:
      ok(false, "Should not be reached");
    break
    }
  }

  this.start = function() {
    // some permissions need parent to have permission as well
    if (!self.setupParent && self.data.needParentPerm &&
        !SpecialPowers.isMainProcess()) {
      self.setupParent = true;
      addPermissions(self.perms, window.document, self.start.bind(self));
    } else if (self.data.settings && self.data.settings.length) {
      SpecialPowers.pushPrefEnv({'set': self.data.settings.slice(0)},
                                self.next.bind(self));
    } else {
      self.next();
    }
  }
}

function addPermissions(aPerms, aDoc, aCallback) {
  var permList = [];
  aPerms.forEach(function (el) {
    var obj = {'type': el,
               'allow': 1,
               'context': aDoc};
    permList.push(obj);
  });
  SpecialPowers.pushPermissions(permList, aCallback);
}

function expandPermissions(aPerms) {
  var perms = [];
  aPerms.forEach(function(el) {
    var access = permTable[el].access ? "readwrite" : null;
    var expanded = expand(el, access);
    for (let i = 0; i < expanded.length; i++) {
      perms.push(SpecialPowers.unwrap(expanded[i]));
    }
  });

  return perms;
}

function msgHandler(evt) {
  var data = evt.data;
  var test = pendingTests[data.id];

  /*
   * step 2 of tests should fail on
   * platforms which are skipped
   */
  if (test.isSkip && test.step == 2) {
    todo(data.result, data.msg);
  } else {
    ok(data.result, data.msg);
  }

  if (test) {
    test.next();
  } else {
    ok(false, "Received unknown id " + data.id);
    checkFinish();
  }
}

function checkFinish() {
  if (--gRemainingTests) {
    gTestRunner.next();
  } else {
    window.removeEventListener('message', msgHandler);
    SimpleTest.finish();
  }
}

function runTest() {
  gRemainingTests = Object.keys(gData).length;

  for (var test in gData) {
    var test = new PermTest(gData[test]);
    test.start();
    yield undefined;
  }
}

var gTestRunner = runTest();

window.addEventListener('load', function() { gTestRunner.next(); }, false);
window.addEventListener('message', msgHandler, false);