mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1065153 - Support call URLs with guest or FxA hawk session types, r=MattN
This commit is contained in:
parent
bc8d2f36a9
commit
e6b2d35f6f
@ -5,7 +5,16 @@
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
// Make it possible to load LoopStorage.jsm in xpcshell tests
|
||||
try {
|
||||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
} catch (ex) {
|
||||
// don't write this is out in xpcshell, since it's expected there
|
||||
if (typeof window !== 'undefined' && "console" in window) {
|
||||
console.log("Failed to import indexedDB; if this isn't a unit test," +
|
||||
" something is wrong", ex);
|
||||
}
|
||||
}
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
@ -115,6 +115,8 @@ function injectLoopAPI(targetWindow) {
|
||||
/**
|
||||
* Gets an object with data that represents the currently
|
||||
* authenticated user's identity.
|
||||
*
|
||||
* @return null if user not logged in; profile object otherwise
|
||||
*/
|
||||
userProfile: {
|
||||
enumerable: true,
|
||||
@ -378,6 +380,9 @@ function injectLoopAPI(targetWindow) {
|
||||
* }
|
||||
* - {String} The body of the response.
|
||||
*
|
||||
* @param {LOOP_SESSION_TYPE} sessionType The type of session to use for
|
||||
* the request. This is one of the
|
||||
* LOOP_SESSION_TYPE members
|
||||
* @param {String} path The path to make the request to.
|
||||
* @param {String} method The request method, e.g. 'POST', 'GET'.
|
||||
* @param {Object} payloadObj An object which is converted to JSON and
|
||||
@ -387,10 +392,9 @@ function injectLoopAPI(targetWindow) {
|
||||
hawkRequest: {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function(path, method, payloadObj, callback) {
|
||||
// XXX: Bug 1065153 - Should take a sessionType parameter instead of hard-coding GUEST
|
||||
value: function(sessionType, path, method, payloadObj, callback) {
|
||||
// XXX Should really return a DOM promise here.
|
||||
MozLoopService.hawkRequest(LOOP_SESSION_TYPE.GUEST, path, method, payloadObj).then((response) => {
|
||||
MozLoopService.hawkRequest(sessionType, path, method, payloadObj).then((response) => {
|
||||
callback(null, response.body);
|
||||
}, hawkError => {
|
||||
// The hawkError.error property, while usually a string representing
|
||||
@ -409,10 +413,9 @@ function injectLoopAPI(targetWindow) {
|
||||
|
||||
LOOP_SESSION_TYPE: {
|
||||
enumerable: true,
|
||||
writable: false,
|
||||
value: function() {
|
||||
return LOOP_SESSION_TYPE;
|
||||
},
|
||||
get: function() {
|
||||
return Cu.cloneInto(LOOP_SESSION_TYPE, targetWindow);
|
||||
}
|
||||
},
|
||||
|
||||
logInToFxA: {
|
||||
@ -450,11 +453,21 @@ function injectLoopAPI(targetWindow) {
|
||||
if (!appVersionInfo) {
|
||||
let defaults = Services.prefs.getDefaultBranch(null);
|
||||
|
||||
appVersionInfo = Cu.cloneInto({
|
||||
channel: defaults.getCharPref("app.update.channel"),
|
||||
version: appInfo.version,
|
||||
OS: appInfo.OS
|
||||
}, targetWindow);
|
||||
// If the lazy getter explodes, we're probably loaded in xpcshell,
|
||||
// which doesn't have what we need, so log an error.
|
||||
try {
|
||||
appVersionInfo = Cu.cloneInto({
|
||||
channel: defaults.getCharPref("app.update.channel"),
|
||||
version: appInfo.version,
|
||||
OS: appInfo.OS
|
||||
}, targetWindow);
|
||||
} catch (ex) {
|
||||
// only log outside of xpcshell to avoid extra message noise
|
||||
if (typeof window !== 'undefined' && "console" in window) {
|
||||
console.log("Failed to construct appVersionInfo; if this isn't " +
|
||||
"an xpcshell unit test, something is wrong", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return appVersionInfo;
|
||||
}
|
||||
@ -510,17 +523,23 @@ function injectLoopAPI(targetWindow) {
|
||||
Services.obs.addObserver(onStatusChanged, "loop-status-changed", false);
|
||||
Services.obs.addObserver(onDOMWindowDestroyed, "dom-window-destroyed", false);
|
||||
|
||||
targetWindow.navigator.wrappedJSObject.__defineGetter__("mozLoop", function() {
|
||||
// We do this in a getter, so that we create these objects
|
||||
// only on demand (this is a potential concern, since
|
||||
// otherwise we might add one per iframe, and keep them
|
||||
// alive for as long as the window is alive).
|
||||
delete targetWindow.navigator.wrappedJSObject.mozLoop;
|
||||
return targetWindow.navigator.wrappedJSObject.mozLoop = contentObj;
|
||||
});
|
||||
if ("navigator" in targetWindow) {
|
||||
targetWindow.navigator.wrappedJSObject.__defineGetter__("mozLoop", function () {
|
||||
// We do this in a getter, so that we create these objects
|
||||
// only on demand (this is a potential concern, since
|
||||
// otherwise we might add one per iframe, and keep them
|
||||
// alive for as long as the window is alive).
|
||||
delete targetWindow.navigator.wrappedJSObject.mozLoop;
|
||||
return targetWindow.navigator.wrappedJSObject.mozLoop = contentObj;
|
||||
});
|
||||
|
||||
// Handle window.close correctly on the panel and chatbox.
|
||||
hookWindowCloseForPanelClose(targetWindow);
|
||||
} else {
|
||||
// This isn't a window; but it should be a JS scope; used for testing
|
||||
return targetWindow.mozLoop = contentObj;
|
||||
}
|
||||
|
||||
// Handle window.close correctly on the panel and chatbox.
|
||||
hookWindowCloseForPanelClose(targetWindow);
|
||||
}
|
||||
|
||||
function getChromeWindow(contentWin) {
|
||||
|
@ -703,6 +703,11 @@ this.MozLoopService = {
|
||||
* push and loop servers.
|
||||
*/
|
||||
initialize: function() {
|
||||
|
||||
// Do this here, rather than immediately after definition, so that we can
|
||||
// stub out API functions for unit testing
|
||||
Object.freeze(this);
|
||||
|
||||
// Don't do anything if loop is not enabled.
|
||||
if (!Services.prefs.getBoolPref("loop.enabled") ||
|
||||
Services.prefs.getBoolPref("loop.throttled")) {
|
||||
@ -1052,4 +1057,3 @@ this.MozLoopService = {
|
||||
return MozLoopServiceInternal.hawkRequest(sessionType, path, method, payloadObj);
|
||||
},
|
||||
};
|
||||
Object.freeze(this.MozLoopService);
|
||||
|
@ -108,29 +108,37 @@ loop.Client = (function($) {
|
||||
* @param {Function} cb Callback(err, callUrlData)
|
||||
*/
|
||||
_requestCallUrlInternal: function(nickname, cb) {
|
||||
this.mozLoop.hawkRequest("/call-url/", "POST", {callerId: nickname},
|
||||
function (error, responseText) {
|
||||
if (error) {
|
||||
this._telemetryAdd("LOOP_CLIENT_CALL_URL_REQUESTS_SUCCESS", false);
|
||||
this._failureHandler(cb, error);
|
||||
return;
|
||||
}
|
||||
var sessionType;
|
||||
if (this.mozLoop.userProfile) {
|
||||
sessionType = this.mozLoop.LOOP_SESSION_TYPE.FXA;
|
||||
} else {
|
||||
sessionType = this.mozLoop.LOOP_SESSION_TYPE.GUEST;
|
||||
}
|
||||
|
||||
this.mozLoop.hawkRequest(sessionType, "/call-url/", "POST",
|
||||
{callerId: nickname},
|
||||
function (error, responseText) {
|
||||
if (error) {
|
||||
this._telemetryAdd("LOOP_CLIENT_CALL_URL_REQUESTS_SUCCESS", false);
|
||||
this._failureHandler(cb, error);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var urlData = JSON.parse(responseText);
|
||||
try {
|
||||
var urlData = JSON.parse(responseText);
|
||||
|
||||
// This throws if the data is invalid, in which case only the failure
|
||||
// telementry will be recorded.
|
||||
var returnData = this._validate(urlData, expectedCallUrlProperties);
|
||||
// This throws if the data is invalid, in which case only the failure
|
||||
// telemetry will be recorded.
|
||||
var returnData = this._validate(urlData, expectedCallUrlProperties);
|
||||
|
||||
this._telemetryAdd("LOOP_CLIENT_CALL_URL_REQUESTS_SUCCESS", true);
|
||||
cb(null, returnData);
|
||||
} catch (err) {
|
||||
this._telemetryAdd("LOOP_CLIENT_CALL_URL_REQUESTS_SUCCESS", false);
|
||||
console.log("Error requesting call info", err);
|
||||
cb(err);
|
||||
}
|
||||
}.bind(this));
|
||||
this._telemetryAdd("LOOP_CLIENT_CALL_URL_REQUESTS_SUCCESS", true);
|
||||
cb(null, returnData);
|
||||
} catch (err) {
|
||||
this._telemetryAdd("LOOP_CLIENT_CALL_URL_REQUESTS_SUCCESS", false);
|
||||
console.log("Error requesting call info", err);
|
||||
cb(err);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -154,8 +162,7 @@ loop.Client = (function($) {
|
||||
},
|
||||
|
||||
_deleteCallUrlInternal: function(token, cb) {
|
||||
this.mozLoop.hawkRequest("/call-url/" + token, "DELETE", null,
|
||||
function (error, responseText) {
|
||||
function deleteRequestCallback(error, responseText) {
|
||||
if (error) {
|
||||
this._failureHandler(cb, error);
|
||||
return;
|
||||
@ -167,12 +174,19 @@ loop.Client = (function($) {
|
||||
console.log("Error deleting call info", err);
|
||||
cb(err);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// XXX hard-coding of GUEST to be removed by 1065155
|
||||
this.mozLoop.hawkRequest(this.mozLoop.LOOP_SESSION_TYPE.GUEST,
|
||||
"/call-url/" + token, "DELETE", null,
|
||||
deleteRequestCallback.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Requests a call URL from the Loop server. It will note the
|
||||
* expiry time for the url with the mozLoop api.
|
||||
* expiry time for the url with the mozLoop api. It will select the
|
||||
* appropriate hawk session to use based on whether or not the user
|
||||
* is currently logged into a Firefox account profile.
|
||||
*
|
||||
* Callback parameters:
|
||||
* - err null on successful registration, non-null otherwise.
|
||||
|
@ -35,7 +35,12 @@ describe("loop.Client", function() {
|
||||
ensureRegistered: sinon.stub().callsArgWith(0, null),
|
||||
noteCallUrlExpiry: sinon.spy(),
|
||||
hawkRequest: sinon.stub(),
|
||||
telemetryAdd: sinon.spy(),
|
||||
LOOP_SESSION_TYPE: {
|
||||
GUEST: 1,
|
||||
FXA: 2
|
||||
},
|
||||
userProfile: null,
|
||||
telemetryAdd: sinon.spy()
|
||||
};
|
||||
// Alias for clearer tests.
|
||||
hawkRequestStub = mozLoop.hawkRequest;
|
||||
@ -70,6 +75,7 @@ describe("loop.Client", function() {
|
||||
|
||||
sinon.assert.calledOnce(hawkRequestStub);
|
||||
sinon.assert.calledWith(hawkRequestStub,
|
||||
mozLoop.LOOP_SESSION_TYPE.GUEST,
|
||||
"/call-url/" + fakeToken, "DELETE");
|
||||
});
|
||||
|
||||
@ -78,7 +84,7 @@ describe("loop.Client", function() {
|
||||
|
||||
// Sets up the hawkRequest stub to trigger the callback with no error
|
||||
// and the url.
|
||||
hawkRequestStub.callsArgWith(3, null);
|
||||
hawkRequestStub.callsArgWith(4, null);
|
||||
|
||||
client.deleteCallUrl(fakeToken, callback);
|
||||
|
||||
@ -88,7 +94,7 @@ describe("loop.Client", function() {
|
||||
it("should send an error when the request fails", function() {
|
||||
// Sets up the hawkRequest stub to trigger the callback with
|
||||
// an error
|
||||
hawkRequestStub.callsArgWith(3, fakeErrorRes);
|
||||
hawkRequestStub.callsArgWith(4, fakeErrorRes);
|
||||
|
||||
client.deleteCallUrl(fakeToken, callback);
|
||||
|
||||
@ -119,8 +125,32 @@ describe("loop.Client", function() {
|
||||
client.requestCallUrl("foo", callback);
|
||||
|
||||
sinon.assert.calledOnce(hawkRequestStub);
|
||||
sinon.assert.calledWith(hawkRequestStub,
|
||||
"/call-url/", "POST", {callerId: "foo"});
|
||||
sinon.assert.calledWithExactly(hawkRequestStub, sinon.match.number,
|
||||
"/call-url/", "POST", {callerId: "foo"}, sinon.match.func);
|
||||
});
|
||||
|
||||
it("should send a sessionType of LOOP_SESSION_TYPE.GUEST when " +
|
||||
"mozLoop.userProfile returns null", function() {
|
||||
mozLoop.userProfile = null;
|
||||
|
||||
client.requestCallUrl("foo", callback);
|
||||
|
||||
sinon.assert.calledOnce(hawkRequestStub);
|
||||
sinon.assert.calledWithExactly(hawkRequestStub,
|
||||
mozLoop.LOOP_SESSION_TYPE.GUEST, "/call-url/", "POST",
|
||||
{callerId: "foo"}, sinon.match.func);
|
||||
});
|
||||
|
||||
it("should send a sessionType of LOOP_SESSION_TYPE.FXA when " +
|
||||
"mozLoop.userProfile returns an object", function () {
|
||||
mozLoop.userProfile = {};
|
||||
|
||||
client.requestCallUrl("foo", callback);
|
||||
|
||||
sinon.assert.calledOnce(hawkRequestStub);
|
||||
sinon.assert.calledWithExactly(hawkRequestStub,
|
||||
mozLoop.LOOP_SESSION_TYPE.FXA, "/call-url/", "POST",
|
||||
{callerId: "foo"}, sinon.match.func);
|
||||
});
|
||||
|
||||
it("should call the callback with the url when the request succeeds",
|
||||
@ -132,8 +162,7 @@ describe("loop.Client", function() {
|
||||
|
||||
// Sets up the hawkRequest stub to trigger the callback with no error
|
||||
// and the url.
|
||||
hawkRequestStub.callsArgWith(3, null,
|
||||
JSON.stringify(callUrlData));
|
||||
hawkRequestStub.callsArgWith(4, null, JSON.stringify(callUrlData));
|
||||
|
||||
client.requestCallUrl("foo", callback);
|
||||
|
||||
@ -149,8 +178,7 @@ describe("loop.Client", function() {
|
||||
|
||||
// Sets up the hawkRequest stub to trigger the callback with no error
|
||||
// and the url.
|
||||
hawkRequestStub.callsArgWith(3, null,
|
||||
JSON.stringify(callUrlData));
|
||||
hawkRequestStub.callsArgWith(4, null, JSON.stringify(callUrlData));
|
||||
|
||||
client.requestCallUrl("foo", callback);
|
||||
|
||||
@ -166,7 +194,7 @@ describe("loop.Client", function() {
|
||||
|
||||
// Sets up the hawkRequest stub to trigger the callback with no error
|
||||
// and the url.
|
||||
hawkRequestStub.callsArgWith(3, null,
|
||||
hawkRequestStub.callsArgWith(4, null,
|
||||
JSON.stringify(callUrlData));
|
||||
|
||||
client.requestCallUrl("foo", function(err) {
|
||||
@ -184,7 +212,7 @@ describe("loop.Client", function() {
|
||||
it("should send an error when the request fails", function() {
|
||||
// Sets up the hawkRequest stub to trigger the callback with
|
||||
// an error
|
||||
hawkRequestStub.callsArgWith(3, fakeErrorRes);
|
||||
hawkRequestStub.callsArgWith(4, fakeErrorRes);
|
||||
|
||||
client.requestCallUrl("foo", callback);
|
||||
|
||||
@ -197,7 +225,7 @@ describe("loop.Client", function() {
|
||||
it("should send an error if the data is not valid", function() {
|
||||
// Sets up the hawkRequest stub to trigger the callback with
|
||||
// an error
|
||||
hawkRequestStub.callsArgWith(3, null, "{}");
|
||||
hawkRequestStub.callsArgWith(4, null, "{}");
|
||||
|
||||
client.requestCallUrl("foo", callback);
|
||||
|
||||
@ -211,7 +239,7 @@ describe("loop.Client", function() {
|
||||
function(done) {
|
||||
// Sets up the hawkRequest stub to trigger the callback with
|
||||
// an error
|
||||
hawkRequestStub.callsArgWith(3, fakeErrorRes);
|
||||
hawkRequestStub.callsArgWith(4, fakeErrorRes);
|
||||
|
||||
client.requestCallUrl("foo", function(err) {
|
||||
expect(err).not.to.be.null;
|
||||
|
@ -0,0 +1,71 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Unit tests for the hawkRequest API
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource:///modules/loop/MozLoopAPI.jsm");
|
||||
|
||||
let sandbox;
|
||||
function assertInSandbox(expr, msg_opt) {
|
||||
Assert.ok(Cu.evalInSandbox(expr, sandbox), msg_opt);
|
||||
}
|
||||
|
||||
sandbox = Cu.Sandbox("about:looppanel", { wantXrays: false } );
|
||||
injectLoopAPI(sandbox, true);
|
||||
|
||||
add_task(function* hawk_session_scope_constants() {
|
||||
assertInSandbox("typeof mozLoop.LOOP_SESSION_TYPE !== 'undefined'");
|
||||
|
||||
assertInSandbox("mozLoop.LOOP_SESSION_TYPE.GUEST === 1");
|
||||
|
||||
assertInSandbox("mozLoop.LOOP_SESSION_TYPE.FXA === 2");
|
||||
});
|
||||
|
||||
function generateSessionTypeVerificationStub(desiredSessionType) {
|
||||
|
||||
function hawkRequestStub(sessionType, path, method, payloadObj, callback) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
Assert.equal(desiredSessionType, sessionType);
|
||||
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
return hawkRequestStub;
|
||||
}
|
||||
|
||||
const origHawkRequest = MozLoopService.oldHawkRequest;
|
||||
do_register_cleanup(function() {
|
||||
MozLoopService.hawkRequest = origHawkRequest;
|
||||
});
|
||||
|
||||
add_task(function* hawk_request_scope_passthrough() {
|
||||
|
||||
// add a stub that verifies the parameter we want
|
||||
MozLoopService.hawkRequest =
|
||||
generateSessionTypeVerificationStub(sandbox.mozLoop.LOOP_SESSION_TYPE.FXA);
|
||||
|
||||
// call mozLoop.hawkRequest, which calls MozLoopAPI.hawkRequest, which calls
|
||||
// MozLoopService.hawkRequest
|
||||
Cu.evalInSandbox(
|
||||
"mozLoop.hawkRequest(mozLoop.LOOP_SESSION_TYPE.FXA," +
|
||||
" 'call-url/fakeToken', 'POST', {}, function() {})",
|
||||
sandbox);
|
||||
|
||||
MozLoopService.hawkRequest =
|
||||
generateSessionTypeVerificationStub(sandbox.mozLoop.LOOP_SESSION_TYPE.GUEST);
|
||||
|
||||
Cu.evalInSandbox(
|
||||
"mozLoop.hawkRequest(mozLoop.LOOP_SESSION_TYPE.GUEST," +
|
||||
" 'call-url/fakeToken', 'POST', {}, function() {})",
|
||||
sandbox);
|
||||
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
@ -3,6 +3,7 @@ head = head.js
|
||||
tail =
|
||||
firefox-appdir = browser
|
||||
|
||||
[test_loopapi_hawk_request.js]
|
||||
[test_looppush_initialize.js]
|
||||
[test_loopservice_dnd.js]
|
||||
[test_loopservice_expiry.js]
|
||||
|
Loading…
Reference in New Issue
Block a user