Closed
Bug 1149868
Opened 10 years ago
Closed 9 years ago
|SpecialPowers.pushPermissions| leads a time out in mochitest if the last permission is undone before test finishes
Categories
(Testing :: Mochitest, defect)
Tracking
(firefox41 fixed)
RESOLVED
FIXED
mozilla41
Tracking | Status | |
---|---|---|
firefox41 | --- | fixed |
People
(Reporter: CuveeHsu, Assigned: chunmin)
References
Details
Attachments
(1 file, 6 obsolete files)
(deleted),
patch
|
chunmin
:
review+
|
Details | Diff | Splinter Review |
Per bug 1097468 comment 19, we need to have a way to avoid this trap instead of |popPermissions| workaround.
Assignee | ||
Comment 1•10 years ago
|
||
pushPermissions() will create a undoStack[1] to clear the permissions and this undoStack will be popped by popPermissions() or flushPermissions()(it will call popPermissions actually). If we use other way(e.g. removePermission()) to clear the permissions we set, instead of popPermissions(), then SimpleTest.finish() will never be terminated. The reason is that flushPermissions()[2] will remove all the permissions in undoStack by popPermissions() that wait a "perm-changed" signal. However, the permissions were already removed by other way(e.g. removePermission()), so flushPermissions() will never received the "perm-changed" signal
[1] https://dxr.mozilla.org/mozilla-central/source/testing/specialpowers/content/specialpowersAPI.js#833
[2] https://dxr.mozilla.org/mozilla-central/source/testing/mochitest/tests/SimpleTest/SimpleTest.js#1010
Assignee: nobody → cchang
Comment 2•10 years ago
|
||
I think you shouldn't use SpecialPowers.removePermission at all in mochitest. See discussion in bug 951272.
However, this seems indeed like a bug.
Comment 3•10 years ago
|
||
would the concept of removePermissions remove the permissions from the stack to flush? Ideally we would just have a way to cherry pick permissions from that stack and remove them. Likewise we should include a timeout in the waiting for perm-changed and generate an error when we timeout. This error can be used for test developers to change their tests accordingly if this is the intended behavior.
Assignee | ||
Comment 4•10 years ago
|
||
(In reply to Martijn Wargers [:mwargers] (QA) from comment #2)
> I think you shouldn't use SpecialPowers.removePermission at all in
> mochitest. See discussion in bug 951272.
> However, this seems indeed like a bug.
Hi, Martijn
Thanks for your comment. Yes, removePermissions() may be not a good example. I just want to reproduce the situation bug 1097468 comment 18 faced in a simplest way. I think the real situations is:
The items in UndoStack will be executed before flushPermissions()[1] by uninstalling the app[2] and fire "perm-changed" signals[3]. Thus, when SimpleTest.finish() call flushPermissions() and try to execute the items in UndoStack that were already executed by [2], the flushPermissions() can't receive "perm-changed" signals[3].
[1] https://dxr.mozilla.org/mozilla-central/source/testing/mochitest/tests/SimpleTest/SimpleTest.js#1010
[2] https://dxr.mozilla.org/mozilla-central/source/dom/apps/Webapps.js#929
[3] https://dxr.mozilla.org/mozilla-central/source/extensions/cookie/nsPermissionManager.cpp#1745
Assignee | ||
Comment 5•10 years ago
|
||
(In reply to Joel Maher (:jmaher) from comment #3)
> would the concept of removePermissions remove the permissions from the stack
> to flush? Ideally we would just have a way to cherry pick permissions from
> that stack and remove them. Likewise we should include a timeout in the
> waiting for perm-changed and generate an error when we timeout. This error
> can be used for test developers to change their tests accordingly if this is
> the intended behavior.
Hi, Joel Maher
It's glad to get your feedback! Yes, removePermissions() may not be a good choice to reproduce this bug. The real situation faced is explained in comment #4.
Would you let me know which one do you suggest in the below cases:
1) Make permissionObserver to monitor all the "perm-changed" signals. If the items in UndoStack are executed by others(not specialpowersAPI.js itself), then the items will be removed from UndoStack.
2) Use a timeout mechanism before adding a permissionObserver to wait "perm-changed" signal. If the "perm-changed" signal is not fired after timeout, then the behavior is normal or not, will be decided by developers(Does it need to prompt: "forget to call |popPermissions| after pushing?").
or any other better case than these?
Comment 6•10 years ago
|
||
I think observing all perm-changed is interesting although it could be problematic. One concern here is that we pushPermission(), the change is caught and it is on our stack, then we remove app which catches more permission changes. These would be caught and put on the stack. Now we have two permission changes on the stack for the same thing, both of which we don't need and undoing them could be problematic. When we pop them off, we would add the permission first, then remove it- in fact this might work pretty good.
timeout mechanism- my original thought, ensures that folks writing tests are explicit about what permissions they require and expect. Regarding the timeout, anytime we hit it should be a failure with a clear message about what perm-changed we didn't get and your suggestion about 'forgot to call ...' seems great.
Either approach or some hybrid would be nice. Permissions are different than preferences, we just happen to have similar approaches for both to date.
Assignee | ||
Comment 7•10 years ago
|
||
Attachment #8600220 -
Attachment is obsolete: true
Assignee | ||
Comment 8•10 years ago
|
||
Comment on attachment 8600734 [details] [diff] [review]
[v1] make permissionObserver listen all 'perm-changed' signals to operate the undostack
(In reply to Joel Maher (:jmaher) from comment #6)
> I think observing all perm-changed is interesting although it could be
> problematic. One concern here is that we pushPermission(), the change is
> caught and it is on our stack, then we remove app which catches more
> permission changes. These would be caught and put on the stack. Now we
> have two permission changes on the stack for the same thing, both of which
> we don't need and undoing them could be problematic. When we pop them off,
> we would add the permission first, then remove it- in fact this might work
> pretty good.
Hi, Joel
Could you review this patch? I would be grateful for any feedback you could give me :)
In this patch, |permissionObserver| is able to listen all "perm-changed" signals includes but is not limited to specialpowersAPI.js itself. To keep the original design of |permissionObserver|, flag |_applyingPermissions| is used to distinguish the "perm-changed" signal is trigger from specialpowersAPI.js itself or not. If the "perm-changed" signal is fired by itself, then code flow is same as before. Otherwise, it will ckeck whether the operation is duplicate in undostack or not. If it's duplicate, it means that we don't need to do it again(others has already executed this action). Thus, the duplicate action in undostack will be removed.
Attachment #8600734 -
Flags: review?(jmaher)
Assignee | ||
Comment 9•10 years ago
|
||
Move permissionObserver to SpecialPowersObserver.js to listen all 'perm-changed' signals because SpecialPowersAPI.js is not in chrome-process
Attachment #8600734 -
Attachment is obsolete: true
Attachment #8600734 -
Flags: review?(jmaher)
Assignee | ||
Comment 10•10 years ago
|
||
> Created attachment 8601311 [details] [diff] [review]
Hi, Joel,
Could you take a look at this patch?
It seems that the calling of this._addMessageListener in specialpowersAPI.js will lead a "TypeError: this._addMessageListener is not a function" in dom/power/test/browser_wakelocks.js[1]
Is there any way to avoid this error?
[1]https://treeherder.mozilla.org/#/jobs?repo=try&revision=cd618cd38a8c
Flags: needinfo?(jmaher)
Comment 11•10 years ago
|
||
If this code is all in specialpowersobserver.js, it could be that you need this.messageManager.addMessageListener.
We define _addMessageListener in specialpowers proper, but the observer is the observer service in the chrome space. Could that be the issue?
Flags: needinfo?(jmaher)
Assignee | ||
Comment 12•10 years ago
|
||
(In reply to Joel Maher (:jmaher) from comment #11)
Thx for your help. I find the reason is that there is no implementation of _addMessageListener in ChromePowers.js[1].
[1] https://dxr.mozilla.org/mozilla-central/source/testing/mochitest/tests/SimpleTest/ChromePowers.js#20
Assignee | ||
Comment 13•10 years ago
|
||
Assignee | ||
Updated•10 years ago
|
Attachment #8601311 -
Attachment is obsolete: true
Comment 14•10 years ago
|
||
I was trying to get rid of ChromePowers.js in bug 1041563.
ChromePowers.js is basically a stub, because specialpowers.js gave some problems in browser-chrome/chrome mochitests. But it should be possible to merge the code and then get rid of ChromePowers.js.
Assignee | ||
Comment 15•10 years ago
|
||
(In reply to Martijn Wargers [:mwargers] (QA) from comment #14)
> I was trying to get rid of ChromePowers.js in bug 1041563.
> ChromePowers.js is basically a stub, because specialpowers.js gave some
> problems in browser-chrome/chrome mochitests. But it should be possible to
> merge the code and then get rid of ChromePowers.js.
Thanks for your message! I take a work-around solution now. I think this patch could be revised after ChromePowers.js is removed.
Assignee | ||
Comment 16•10 years ago
|
||
Comment on attachment 8602042 [details] [diff] [review]
[v3] bug-1149868: move permissionObserver to SpecialPowersObserverand make it listen all 'perm-changed' signals to operate the undostack if specialpowers is in content process
Hi, Joel
Could you review this patch?
p.s. I already tested on try-server[1].
[1] https://treeherder.mozilla.org/#/jobs?repo=try&revision=d8e8a52c2024
Attachment #8602042 -
Flags: review?(jmaher)
Comment 17•10 years ago
|
||
Comment on attachment 8602042 [details] [diff] [review]
[v3] bug-1149868: move permissionObserver to SpecialPowersObserverand make it listen all 'perm-changed' signals to operate the undostack if specialpowers is in content process
Review of attachment 8602042 [details] [diff] [review]:
-----------------------------------------------------------------
Ideally I would like the modifications to the test to be in a new file:
test_SpecialPowersPushAppPermissions.html
I believe that should be fairly easy to do.
::: testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html
@@ +160,5 @@
> +
> +// Setup the prefrences and permissions
> +function allowManagingApps() {
> + SpecialPowers.pushPermissions([
> + //{ "type": "embed-apps", "allow": true, "context": document },
why is this commented out?
::: testing/specialpowers/components/SpecialPowersObserver.js
@@ +129,5 @@
> var obs = Services.obs;
> obs.removeObserver(this, "chrome-document-global-created");
> obs.removeObserver(this, "http-on-modify-request");
> obs.removeObserver(this, "xpcom-shutdown");
> + this._registerObservers._topics.forEach(function(element){
nit: space between ){
@@ +195,5 @@
> + this._topics.push(topic);
> + Services.obs.addObserver(this, topic, false);
> + }
> + },
> + _sendAsyncMessageToSpecialpowers: function(topic, msg) {
nit: capitalize powers -> _sendAsyncMessageToSpecialPowers
@@ +203,5 @@
> + var msg = { aData: aData };
> + switch (aTopic) {
> + case "perm-changed":
> + var permission = aSubject.QueryInterface(Ci.nsIPermission);
> + msg.permission = { appId: permission.appId, type: permission.type };
do we always have an appId available for a permission? I assume there are cases unrelated to webapps or firefoxOS where we would add a permission.
@@ +205,5 @@
> + case "perm-changed":
> + var permission = aSubject.QueryInterface(Ci.nsIPermission);
> + msg.permission = { appId: permission.appId, type: permission.type };
> + default:
> + this._sendAsyncMessageToSpecialpowers(aTopic, msg);
why not just do:
this._self._sendAsyncMessage('specialpowers-'+topic, msg);
this would save an extra function that doesn't do much. Can we not just do:
this._sendAsyncMessage(...); ?
::: testing/specialpowers/content/specialpowersAPI.js
@@ +894,5 @@
> + observe: function (aSubject, aTopic, aData)
> + {
> + if (aTopic == "perm-changed") {
> + var permission = aSubject.QueryInterface(Ci.nsIPermission);
> + this._self._permissionObserver.observe(permission, aData);
I would rather see _self be call _specialPowersAPI
Attachment #8602042 -
Flags: review?(jmaher) → review-
Assignee | ||
Comment 18•10 years ago
|
||
(In reply to Joel Maher (:jmaher) from comment #17)
> Comment on attachment 8602042 [details] [diff] [review]
> [v3] bug-1149868: move permissionObserver to SpecialPowersObserverand make
> it listen all 'perm-changed' signals to operate the undostack if
> specialpowers is in content process
>
> Review of attachment 8602042 [details] [diff] [review]:
> -----------------------------------------------------------------
Thanks for your review.
> Ideally I would like the modifications to the test to be in a new file:
> test_SpecialPowersPushAppPermissions.html
>
> I believe that should be fairly easy to do.
I agree with you.
> :::
> testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html
> @@ +160,5 @@
> > +
> > +// Setup the prefrences and permissions
> > +function allowManagingApps() {
> > + SpecialPowers.pushPermissions([
> > + //{ "type": "embed-apps", "allow": true, "context": document },
>
> why is this commented out?
Oh, it's a typo! I don't use the mozApp iframe here, sp I will remove it.
> ::: testing/specialpowers/components/SpecialPowersObserver.js
> @@ +129,5 @@
> > var obs = Services.obs;
> > obs.removeObserver(this, "chrome-document-global-created");
> > obs.removeObserver(this, "http-on-modify-request");
> > obs.removeObserver(this, "xpcom-shutdown");
> > + this._registerObservers._topics.forEach(function(element){
>
> nit: space between ){
ok!
> @@ +195,5 @@
> > + this._topics.push(topic);
> > + Services.obs.addObserver(this, topic, false);
> > + }
> > + },
> > + _sendAsyncMessageToSpecialpowers: function(topic, msg) {
>
> nit: capitalize powers -> _sendAsyncMessageToSpecialPowers
>
> @@ +205,5 @@
> > + case "perm-changed":
> > + var permission = aSubject.QueryInterface(Ci.nsIPermission);
> > + msg.permission = { appId: permission.appId, type: permission.type };
> > + default:
> > + this._sendAsyncMessageToSpecialpowers(aTopic, msg);
>
> why not just do:
> this._self._sendAsyncMessage('specialpowers-'+topic, msg);
>
> this would save an extra function that doesn't do much. Can we not just do:
> this._sendAsyncMessage(...); ?
I will follow your advice to save an extra function.
> @@ +203,5 @@
> > + var msg = { aData: aData };
> > + switch (aTopic) {
> > + case "perm-changed":
> > + var permission = aSubject.QueryInterface(Ci.nsIPermission);
> > + msg.permission = { appId: permission.appId, type: permission.type };
>
> do we always have an appId available for a permission? I assume there are
> cases unrelated to webapps or firefoxOS where we would add a permission.
The permission has an appId to be tracked by permissionManager. The appId here is to distinguish the owner of received perm-changed signal.
Please consider the case like:
1. We install an app
2. We push the permissions to the app installed and the document
the document's appId is 0, and the appId of appContext is assumed to be 1001.
After pushing the following permissions:
SpecialPowers.pushPermissions([{ "type": "pUnknow", "allow": true, "context": document }], callback());
SpecialPowers.pushPermissions([{ "type": "pUnknow", "allow": true, "context": appContext }], callback());
the UndoStack will have 2 rows and each contains a the same type permission item.
3. uninstall the app
the app's permission(pUnknow) will be removed after uninstalling
and we should remove the corresponding item(pUnknow) from UndoStack.
If we only compare the permission's type with the item's type in UndoStack,
we can not find which one should be deleted because two items have the same type.
> ::: testing/specialpowers/content/specialpowersAPI.js
> @@ +894,5 @@
> > + observe: function (aSubject, aTopic, aData)
> > + {
> > + if (aTopic == "perm-changed") {
> > + var permission = aSubject.QueryInterface(Ci.nsIPermission);
> > + this._self._permissionObserver.observe(permission, aData);
>
> I would rather see _self be call _specialPowersAPI
OK!
Assignee | ||
Comment 19•10 years ago
|
||
Attachment #8602042 -
Attachment is obsolete: true
Assignee | ||
Updated•10 years ago
|
Attachment #8606185 -
Flags: review?(jmaher)
Comment 20•10 years ago
|
||
Comment on attachment 8606185 [details] [diff] [review]
[v4] move permissionObserver to SpecialPowersObserverand make it listen all 'perm-changed' signals to operate the undostack if specialpowers is in content process
Review of attachment 8606185 [details] [diff] [review]:
-----------------------------------------------------------------
Thanks for addressing my previous comments!
I do have a few questions, marking as r- for now, but could change to r+ as I understand my concerns via replies.
::: testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushAppPermissions.html
@@ +37,5 @@
> + SpecialPowers.pushPermissions([
> + { "type": "pAppPermission-4", "allow": true, "context": document },
> + { "type": "pAppPermission-6", "allow": true, "context": document },
> + ], allowManagingApps);
> + }
why do you split 1/3 and 4/6 up?
@@ +86,5 @@
> + SpecialPowers.pushPermissions([
> + { "type": "pAppPermission-4", "allow": true, "context": context },
> + { "type": "pAppPermission-5", "allow": true, "context": context },
> + { "type": "pAppPermission-6", "allow": true, "context": context }
> + ], testPermissionsForApp);
why do you split 1/2/3 and 4/5/6 up?
::: testing/specialpowers/content/specialpowersAPI.js
@@ +959,5 @@
> + undo.type == permission.type) {
> + // Remove this undo item if it has been done by others(not
> + // specialpowers itself.)
> + undos.splice(j,1);
> + --j;
when we change undos and fiddle with the iterator 'j', does this work with a length of 1? when do we evaluate 'j < undos.length'? I assume undos.length is evaluated once when we enter the loop, but as we splice it and play with the iterator, we could get in a situation where we end up accessing undos[length] which would be undefined.
This is also a concern for the outler loop with 'i' and this._self._permissionsUndoStack.
Attachment #8606185 -
Flags: review?(jmaher) → review-
Assignee | ||
Comment 21•10 years ago
|
||
(In reply to Joel Maher (:jmaher) from comment #20)
> Comment on attachment 8606185 [details] [diff] [review]
> [v4] move permissionObserver to SpecialPowersObserverand make it listen all
> 'perm-changed' signals to operate the undostack if specialpowers is in
> content process
>
> Review of attachment 8606185 [details] [diff] [review]:
> -----------------------------------------------------------------
> :::
> testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushAppPermissions.
> html
> @@ +37,5 @@
> > + SpecialPowers.pushPermissions([
> > + { "type": "pAppPermission-4", "allow": true, "context": document },
> > + { "type": "pAppPermission-6", "allow": true, "context": document },
> > + ], allowManagingApps);
> > + }
>
> why do you split 1/3 and 4/6 up?
>
> @@ +86,5 @@
> > + SpecialPowers.pushPermissions([
> > + { "type": "pAppPermission-4", "allow": true, "context": context },
> > + { "type": "pAppPermission-5", "allow": true, "context": context },
> > + { "type": "pAppPermission-6", "allow": true, "context": context }
> > + ], testPermissionsForApp);
>
> why do you split 1/2/3 and 4/5/6 up?
>
Oh, It's my arbitrary test to demonstrate why I need to use appId to compare. Yes, it's indeed redundant. I change it to a simpler one in this patch.
> ::: testing/specialpowers/content/specialpowersAPI.js
> @@ +959,5 @@
> > + undo.type == permission.type) {
> > + // Remove this undo item if it has been done by others(not
> > + // specialpowers itself.)
> > + undos.splice(j,1);
> > + --j;
>
> when we change undos and fiddle with the iterator 'j', does this work with a
> length of 1? when do we evaluate 'j < undos.length'? I assume undos.length
> is evaluated once when we enter the loop, but as we splice it and play with
> the iterator, we could get in a situation where we end up accessing
> undos[length] which would be undefined.
>
> This is also a concern for the outler loop with 'i' and
> this._self._permissionsUndoStack.
I think it will be clearer if I use break-style here.
I am testing this new patch on tryserver now. I might need your help after the testing. Thanks for your careful review! It make this work better!
Attachment #8606185 -
Attachment is obsolete: true
Assignee | ||
Updated•10 years ago
|
Attachment #8607967 -
Flags: review?(jmaher)
Comment 22•10 years ago
|
||
Comment on attachment 8607967 [details] [diff] [review]
[v5] move permissionObserver to SpecialPowersObserverand make it listen all 'perm-changed' signals to operate the undostack if specialpowers is in content process
Review of attachment 8607967 [details] [diff] [review]:
-----------------------------------------------------------------
please clean up the two nits and thanks for coming back with good patches. You can carry over the r+ and land/checkin-needed.
::: testing/specialpowers/content/specialpowersAPI.js
@@ +949,5 @@
> + this._nextCallback = null;
> + }
> + } else {
> + var find = false;
> + for (var i = 0 ; !find && i < this._self._permissionsUndoStack.length ; i++) {
two small nits:
1: change find -> found; small english difference
2: i=0; <- notice no space between 0 and ';'. This applies to the j loop below as well.
I normally see:
while(!found) {
if (i == this._self._permissionsUndoStack.length) {
found = true;
break;
}
...
your version is fine as well!
Attachment #8607967 -
Flags: review?(jmaher) → review+
Assignee | ||
Comment 23•9 years ago
|
||
Clear nits and carry r+
test on tryserver: https://treeherder.mozilla.org/#/jobs?repo=try&revision=f13a331f64e7
Attachment #8607967 -
Attachment is obsolete: true
Attachment #8609926 -
Flags: review+
Assignee | ||
Updated•9 years ago
|
Keywords: checkin-needed
Comment 24•9 years ago
|
||
Keywords: checkin-needed
Comment 25•9 years ago
|
||
Status: NEW → RESOLVED
Closed: 9 years ago
status-firefox41:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla41
You need to log in
before you can comment on or make changes to this bug.
Description
•