This commit is contained in:
Phil Ringnalda 2014-03-16 21:54:29 -07:00
Родитель 585a4b69a2 ce1c96e4f6
Коммит 07d954a9e8
16 изменённых файлов: 259 добавлений и 273 удалений

Просмотреть файл

@ -118,6 +118,7 @@ tabbrowser {
visibility: hidden;
}
.tab-close-button,
.tab-background {
/* Explicitly set the visibility to override the value (collapsed)
* we inherit from #TabsToolbar[collapsed] upon opening a browser window. */
@ -126,6 +127,7 @@ tabbrowser {
transition: visibility 0ms 25ms;
}
.tab-close-button:not([fadein]):not([pinned]),
.tab-background:not([fadein]):not([pinned]) {
visibility: hidden;
/* Closing tabs are hidden without a delay. */
@ -134,8 +136,7 @@ tabbrowser {
.tab-throbber:not([fadein]):not([pinned]),
.tab-label:not([fadein]):not([pinned]),
.tab-icon-image:not([fadein]):not([pinned]),
.tab-close-button:not([fadein]):not([pinned]) {
.tab-icon-image:not([fadein]):not([pinned]) {
display: none;
}

Просмотреть файл

@ -1163,14 +1163,15 @@
<svg:svg height="0">
#include tab-shape.inc.svg
#ifndef XP_MACOSX
<svg:clipPath id="keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
#ifndef XP_UNIX
<svg:clipPath id="windows-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
<svg:path d="m 0,0 c .3,.25 .3,.75, 0,1 l 1,0 0,-1 z"/>
</svg:clipPath>
<svg:clipPath id="urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
<svg:clipPath id="windows-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
<svg:path d="m 0,-5 l 0,7.8 c 2.5,3.2 4,6.2 4,10.2 c 0,4 -1.5,7 -4,10 l 0,22l10000,0 l 0,-50 l -10000,0 z"/>
</svg:clipPath>
#else
#endif
#ifdef XP_MACOSX
<svg:clipPath id="osx-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
<svg:path d="M 0,0 C 0.15,0.12 0.25,0.3 0.25,0.5 0.25,0.7 0.15,0.88 0,1 L 1,1 1,0 0,0 z"/>
</svg:clipPath>

Просмотреть файл

@ -331,6 +331,7 @@ const PanelUI = {
viewNode.querySelector(".panel-subview-footer"));
let multiView = document.createElement("panelmultiview");
multiView.setAttribute("nosubviews", "true");
tempPanel.appendChild(multiView);
multiView.setAttribute("mainViewIsSubView", "true");
multiView.setMainView(viewNode);

Просмотреть файл

@ -17,6 +17,7 @@
background-color: transparent;
background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
background-position: 0 0, right top;
background-repeat: repeat-x, no-repeat;
}
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
@ -26,4 +27,5 @@
@fgTabTextureLWT@;/*,
lwtHeader;*/
background-position: 0 0, 0 0, right top;
background-repeat: repeat-x, repeat-x, no-repeat;
}

Просмотреть файл

@ -16,7 +16,7 @@
%define forwardTransitionLength 150ms
%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
%define conditionalForwardWithUrlbarWidth 27
%define conditionalForwardWithUrlbarWidth 40
#menubar-items {
-moz-box-orient: vertical; /* for flex hack */
@ -653,96 +653,19 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
-moz-margin-start: -4px;
}
#back-button {
padding-top: 3px;
padding-bottom: 3px;
-moz-padding-start: 5px;
-moz-padding-end: 0;
position: relative;
z-index: 1;
border-radius: 0 10000px 10000px 0;
}
#back-button:-moz-locale-dir(rtl) {
border-radius: 10000px 0 0 10000px;
}
#back-button > menupopup {
margin-top: -1px;
}
#back-button > .toolbarbutton-icon {
border-radius: 10000px;
padding: 5px;
margin-top: -5px;
margin-bottom: -5px;
border: none;
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
0 0 0 1px hsla(0,0%,100%,.3) inset,
0 0 0 1px hsla(210,54%,20%,.25),
0 1px 0 hsla(210,54%,20%,.35);
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
transition-property: background-color, box-shadow;
transition-duration: 250ms;
}
#back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
background-color: hsla(210,48%,96%,.75);
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
0 0 0 1px hsla(0,0%,100%,.3) inset,
0 0 0 1px hsla(210,54%,20%,.3),
0 1px 0 hsla(210,54%,20%,.4),
0 0 4px hsla(210,54%,20%,.2);
}
#back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
#back-button[open="true"] > .toolbarbutton-icon {
background-color: hsla(210,54%,20%,.15);
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
0 0 1px hsla(210,54%,20%,.2) inset,
0 0 0 1px hsla(210,54%,20%,.4),
0 1px 0 hsla(210,54%,20%,.2);
transition: none;
}
#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon {
box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
0 1px 0 hsla(210,54%,20%,.65) !important;
transition: none;
}
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
#forward-button:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
#forward-button[disabled] {
transform: scale(0);
opacity: 0;
pointer-events: none;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
transition: opacity @forwardTransitionLength@ ease-out;
transition: @forwardTransitionLength@ ease-out;
}
@conditionalForwardWithUrlbar@ > #forward-button[occluded-by-urlbar] {
visibility: hidden;
}
#forward-button {
padding: 0;
}
#forward-button > .toolbarbutton-icon {
background-clip: padding-box;
clip-path: url("chrome://browser/content/browser.xul#keyhole-forward-clip-path");
margin-left: -7px;
border-left-style: none;
border-radius: 0;
padding-left: 7px;
padding-right: 3px;
padding-top: 2px;
padding-bottom: 2px;
border: 1px solid #9a9a9a;
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
transform: scaleX(-1);
}
/* tabview menu item */
@ -853,21 +776,9 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
}
/* Location bar */
#urlbar,
.searchbar-textbox {
-moz-appearance: none;
padding: 1px;
border: 1px solid ThreeDShadow;
border-radius: 2px;
}
#urlbar[focused],
.searchbar-textbox[focused] {
border-color: Highlight;
}
#urlbar {
background-color: -moz-field;
-moz-appearance: textfield;
padding: 0;
}
.urlbar-textbox-container {
@ -889,56 +800,26 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
}
@conditionalForwardWithUrlbar@ > #urlbar-wrapper {
padding-left: @conditionalForwardWithUrlbarWidth@px;
-moz-padding-start: @conditionalForwardWithUrlbarWidth@px;
-moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
position: relative;
pointer-events: none;
}
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
-moz-border-start: none;
margin-left: 0;
pointer-events: all;
}
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
transition: margin-left @forwardTransitionLength@ ease-out;
transition: margin-left @forwardTransitionLength@ ease-out,
margin-right @forwardTransitionLength@ ease-out;
}
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
}
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
margin-left: -@conditionalForwardWithUrlbarWidth@px;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
/* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
transition-delay: 100s;
}
@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar,
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar {
/* when switching tabs, or when not hovered anymore, trigger a new transition
* to hide the forward button immediately */
margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
}
@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl),
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
/* let windows-urlbar-back-button-mask clip the urlbar's right side for RTL */
transform: scaleX(-1);
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
margin-right: -@conditionalForwardWithUrlbarWidth@px;
}
#urlbar-icons {
@ -978,66 +859,41 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
min-width: calc(54px + 11ch);
}
/* identity box */
%include ../shared/identity-block.inc.css
#page-proxy-favicon {
margin-top: 2px;
margin-bottom: 2px;
-moz-margin-start: 4px;
-moz-margin-end: 3px;
-moz-image-region: rect(0, 16px, 16px, 0);
}
#identity-box:hover > #page-proxy-favicon {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#identity-box:hover:active > #page-proxy-favicon,
#identity-box[open=true] > #page-proxy-favicon {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
/* Identity indicator */
#identity-box {
padding: 1px;
margin: -1px;
-moz-margin-end: 0;
font-size: .9em;
}
#identity-box:-moz-locale-dir(ltr) {
border-top-left-radius: 1.5px;
border-bottom-left-radius: 1.5px;
border-top-left-radius: 2.5px;
border-bottom-left-radius: 2.5px;
}
#identity-box:-moz-locale-dir(rtl) {
border-top-right-radius: 1.5px;
border-bottom-right-radius: 1.5px;
}
#notification-popup-box:not([hidden]) + #identity-box {
-moz-padding-start: 10px;
border-radius: 0;
}
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box {
border-radius: 0;
}
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: 5px;
transition: padding-left;
}
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: 5px;
transition: padding-right;
}
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box {
/* forward button hiding is delayed when hovered */
transition-delay: 100s;
}
@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr),
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
padding-left: 5.01px;
}
@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl),
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
padding-right: 5.01px;
}
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
-moz-margin-end: 4px;
}
#identity-box.verifiedIdentity:not(:-moz-lwtheme) {
background-color: #fff;
border-top-right-radius: 2.5px;
border-bottom-right-radius: 2.5px;
}
#identity-box:-moz-focusring {
@ -1050,27 +906,10 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
-moz-padding-end: 5px;
}
%include ../shared/identity-block.inc.css
#page-proxy-favicon {
margin-top: 1px;
margin-bottom: 1px;
-moz-margin-start: 3px;
-moz-margin-end: 2px;
-moz-image-region: rect(0, 16px, 16px, 0);
}
@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box > #page-proxy-favicon {
-moz-margin-end: 1px;
}
#identity-box:hover > #page-proxy-favicon {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#identity-box:hover:active > #page-proxy-favicon,
#identity-box[open=true] > #page-proxy-favicon {
-moz-image-region: rect(0, 48px, 16px, 32px);
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
background-color: #fff;
-moz-margin-end: 4px;
}
/* Identity popup icons */

Просмотреть файл

@ -16,6 +16,7 @@
background-color: transparent;
background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
background-position: 0 0, right top;
background-repeat: repeat-x, no-repeat;
}
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
@ -25,6 +26,7 @@
@fgTabTextureLWT@;/*,
lwtHeader;*/
background-position: 0 0, 0 0, right top;
background-repeat: repeat-x, repeat-x, no-repeat;
}
@media (min-resolution: 2dppx) {

Просмотреть файл

@ -5,6 +5,7 @@
%filter substitution
%define menuPanelWidth 22.35em
%define standaloneSubviewWidth 30em
% XXXgijs This is the ugliest bit of code I think I've ever written for Mozilla.
% Basically, the 0.1px is there to avoid CSS rounding errors causing buttons to wrap.
% For gory details, refer to https://bugzilla.mozilla.org/show_bug.cgi?id=963365#c11
@ -89,6 +90,10 @@
transform: translateX(-@menuPanelWidth@);
}
panelmultiview[nosubviews=true] > .panel-viewcontainer > .panel-viewstack > .panel-subviews {
display: none;
}
.panel-viewstack:not([viewtype="main"]) > .panel-mainview > #PanelUI-mainView {
-moz-box-flex: 1;
}
@ -186,10 +191,13 @@
-moz-margin-start: 0;
}
#PanelUI-contents,
#PanelUI-contents {
max-width: @menuPanelWidth@;
}
#BMB_bookmarksPopup,
.panel-mainview:not([panelid="PanelUI-popup"]) {
max-width: @menuPanelWidth@;
max-width: @standaloneSubviewWidth@;
}
panelview:not([mainview]) .toolbarbutton-text,

Просмотреть файл

@ -17,6 +17,7 @@
background-color: transparent;
background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
background-position: 0 0, right top;
background-repeat: repeat-x, no-repeat;
}
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
@ -26,4 +27,5 @@
@fgTabTextureLWT@;/*,
lwtHeader;*/
background-position: 0 0, 0 0, right top;
background-repeat: repeat-x, repeat-x, no-repeat;
}

Просмотреть файл

@ -764,7 +764,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
0 0 1px hsla(210,54%,20%,.2) inset,
/* allows keyhole-forward-clip-path to be used for non-hover as well as hover: */
/* allows windows-keyhole-forward-clip-path to be used for non-hover as well as hover: */
0 1px 0 hsla(210,54%,20%,0),
0 0 2px hsla(210,54%,20%,0);
text-shadow: none;
@ -818,7 +818,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
#forward-button > .toolbarbutton-icon {
background-clip: padding-box !important;
/*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
clip-path: url(chrome://browser/content/browser.xul#keyhole-forward-clip-path) !important;
clip-path: url(chrome://browser/content/browser.xul#windows-keyhole-forward-clip-path) !important;
margin-left: -7px !important;
border-left-style: none !important;
border-radius: 0 !important;
@ -1123,7 +1123,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
}
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
clip-path: url("chrome://browser/content/browser.xul#windows-urlbar-back-button-clip-path");
}
@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {

Просмотреть файл

@ -59,6 +59,7 @@ sync_testing_modules := \
fakeservices.js \
rotaryengine.js \
utils.js \
fxa_utils.js \
$(NULL)
PREF_JS_EXPORTS := $(srcdir)/services-sync.js

Просмотреть файл

@ -0,0 +1,67 @@
"use strict";
this.EXPORTED_SYMBOLS = [
"Assert_rejects",
"initializeIdentityWithTokenServerResponse",
];
const {utils: Cu} = Components;
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://services-sync/main.js");
Cu.import("resource://services-sync/browserid_identity.js");
Cu.import("resource://services-common/tokenserverclient.js");
Cu.import("resource://testing-common/services-common/logging.js");
Cu.import("resource://testing-common/services/sync/utils.js");
// This shouldn't be here - it should be part of the xpcshell harness.
// Maybe as Assert.rejects - so we name it like that.
function Assert_rejects(promise, message) {
let deferred = Promise.defer();
promise.then(
() => deferred.reject(message || "Expected the promise to be rejected"),
deferred.resolve
);
return deferred.promise;
}
// Create a new browserid_identity object and initialize it with a
// mocked TokenServerClient which always receives the specified response.
this.initializeIdentityWithTokenServerResponse = function(response) {
// First create a mock "request" object that well' hack into the token server.
// A log for it
let requestLog = Log.repository.getLogger("testing.mock-rest");
if (!requestLog.appenders.length) { // might as well see what it says :)
requestLog.addAppender(new Log.DumpAppender());
requestLog.level = Log.Level.Trace;
}
// A mock request object.
function MockRESTRequest(url) {};
MockRESTRequest.prototype = {
_log: requestLog,
setHeader: function() {},
get: function(callback) {
this.response = response;
callback.call(this);
}
}
// The mocked TokenServer client which will get the response.
function MockTSC() { }
MockTSC.prototype = new TokenServerClient();
MockTSC.prototype.constructor = MockTSC;
MockTSC.prototype.newRESTRequest = function(url) {
return new MockRESTRequest(url);
}
// tie it all together.
Weave.Status.__authManager = Weave.Service.identity = new BrowserIDManager();
Weave.Service._clusterManager = Weave.Service.identity.createClusterManager(Weave.Service);
let browseridManager = Weave.Service.identity;
// a sanity check
if (!(browseridManager instanceof BrowserIDManager)) {
throw new Error("sync isn't configured for browserid_identity");
}
let mockTSC = new MockTSC()
configureFxAccountIdentity(browseridManager);
browseridManager._tokenServerClient = mockTSC;
}

Просмотреть файл

@ -634,7 +634,28 @@ BrowserIDClusterManager.prototype = {
let cb = Async.makeSpinningCallback();
promiseClusterURL().then(function (clusterURL) {
cb(null, clusterURL);
}).then(null, cb);
}).then(
null, err => {
// service.js's verifyLogin() method will attempt to fetch a cluster
// URL when it sees a 401. If it gets null, it treats it as a "real"
// auth error and sets Status.login to LOGIN_FAILED_LOGIN_REJECTED, which
// in turn causes a notification bar to appear informing the user they
// need to re-authenticate.
// On the other hand, if fetching the cluster URL fails with an exception,
// verifyLogin() assumes it is a transient error, and thus doesn't show
// the notification bar under the assumption the issue will resolve
// itself.
// Thus:
// * On a real 401, we must return null.
// * On any other problem we must let an exception bubble up.
if (err instanceof AuthenticationError) {
// callback with no error and a null result - cb.wait() returns null.
cb(null, null);
} else {
// callback with an error - cb.wait() completes by raising an exception.
cb(err);
}
});
return cb.wait();
},

Просмотреть файл

@ -8,11 +8,11 @@ Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-common/utils.js");
Cu.import("resource://services-crypto/utils.js");
Cu.import("resource://testing-common/services/sync/utils.js");
Cu.import("resource://testing-common/services/sync/fxa_utils.js");
Cu.import("resource://services-common/hawkclient.js");
Cu.import("resource://gre/modules/FxAccounts.jsm");
Cu.import("resource://gre/modules/FxAccountsClient.jsm");
Cu.import("resource://gre/modules/FxAccountsCommon.js");
Cu.import("resource://services-common/tokenserverclient.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/status.js");
Cu.import("resource://services-sync/constants.js");
@ -21,17 +21,6 @@ const SECOND_MS = 1000;
const MINUTE_MS = SECOND_MS * 60;
const HOUR_MS = MINUTE_MS * 60;
// This shouldn't be here - it should be part of the xpcshell harness.
// Maybe as Assert.rejects - so we name it like that.
function Assert_rejects(promise, message) {
let deferred = Promise.defer();
promise.then(
() => deferred.reject(message || "Expected the promise to be rejected"),
deferred.resolve
);
return deferred.promise;
}
let identityConfig = makeIdentityConfig();
let browseridManager = new BrowserIDManager();
configureFxAccountIdentity(browseridManager, identityConfig);
@ -348,11 +337,16 @@ add_task(function test_getTokenErrors() {
_("BrowserIDManager correctly handles various failures to get a token.");
_("Arrange for a 401 - Sync should reflect an auth error.");
yield initializeIdentityWithTokenServerFailure({
initializeIdentityWithTokenServerResponse({
status: 401,
headers: {"content-type": "application/json"},
body: JSON.stringify({}),
});
let browseridManager = Service.identity;
yield browseridManager.initializeWithCurrentIdentity();
yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
"should reject due to 401");
Assert.equal(Status.login, LOGIN_FAILED_LOGIN_REJECTED, "login was rejected");
// XXX - other interesting responses to return?
@ -360,11 +354,15 @@ add_task(function test_getTokenErrors() {
// And for good measure, some totally "unexpected" errors - we generally
// assume these problems are going to magically go away at some point.
_("Arrange for an empty body with a 200 response - should reflect a network error.");
yield initializeIdentityWithTokenServerFailure({
initializeIdentityWithTokenServerResponse({
status: 200,
headers: [],
body: "",
});
browseridManager = Service.identity;
yield browseridManager.initializeWithCurrentIdentity();
yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
"should reject due to non-JSON response");
Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login state is LOGIN_FAILED_NETWORK_ERROR");
});
@ -375,12 +373,18 @@ add_task(function test_getTokenErrorWithRetry() {
// it should reflect the value we sent.
Status.backoffInterval = 0;
_("Arrange for a 503 with a Retry-After header.");
yield initializeIdentityWithTokenServerFailure({
initializeIdentityWithTokenServerResponse({
status: 503,
headers: {"content-type": "application/json",
"retry-after": "100"},
body: JSON.stringify({}),
});
let browseridManager = Service.identity;
yield browseridManager.initializeWithCurrentIdentity();
yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
"should reject due to 503");
// The observer should have fired - check it got the value in the response.
Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login was rejected");
// Sync will have the value in ms with some slop - so check it is at least that.
@ -388,12 +392,18 @@ add_task(function test_getTokenErrorWithRetry() {
_("Arrange for a 200 with an X-Backoff header.");
Status.backoffInterval = 0;
yield initializeIdentityWithTokenServerFailure({
initializeIdentityWithTokenServerResponse({
status: 503,
headers: {"content-type": "application/json",
"x-backoff": "200"},
body: JSON.stringify({}),
});
browseridManager = Service.identity;
yield browseridManager.initializeWithCurrentIdentity();
yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
"should reject due to no token in response");
// The observer should have fired - check it got the value in the response.
Assert.ok(Status.backoffInterval >= 200000);
});
@ -471,45 +481,6 @@ add_task(function test_getKeysError() {
// End of tests
// Utility functions follow
// Create a new browserid_identity object and initialize it with a
// mocked TokenServerClient which always gets the specified response.
function* initializeIdentityWithTokenServerFailure(response) {
// First create a mock "request" object that well' hack into the token server.
// A log for it
let requestLog = Log.repository.getLogger("testing.mock-rest");
if (!requestLog.appenders.length) { // might as well see what it says :)
requestLog.addAppender(new Log.DumpAppender());
requestLog.level = Log.Level.Trace;
}
// A mock request object.
function MockRESTRequest(url) {};
MockRESTRequest.prototype = {
_log: requestLog,
setHeader: function() {},
get: function(callback) {
this.response = response;
callback.call(this);
}
}
// The mocked TokenServer client which will get the response.
function MockTSC() { }
MockTSC.prototype = new TokenServerClient();
MockTSC.prototype.constructor = MockTSC;
MockTSC.prototype.newRESTRequest = function(url) {
return new MockRESTRequest(url);
}
// tie it all together.
let mockTSC = new MockTSC()
configureFxAccountIdentity(browseridManager);
browseridManager._tokenServerClient = mockTSC;
yield browseridManager.initializeWithCurrentIdentity();
yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
"expecting rejection due to tokenserver error");
}
// Create a new browserid_identity object and initialize it with a
// hawk mock that simulates a failure.
// A token server mock will be used that doesn't hit a server, so we move

Просмотреть файл

@ -0,0 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/fxa_utils.js");
Cu.import("resource://testing-common/services/sync/utils.js");
add_task(function test_findCluster() {
_("Test FxA _findCluster()");
_("_findCluster() throws on 500 errors.");
initializeIdentityWithTokenServerResponse({
status: 500,
headers: [],
body: "",
});
yield Service.identity.initializeWithCurrentIdentity();
yield Assert_rejects(Service.identity.whenReadyToAuthenticate.promise,
"should reject due to 500");
Assert.throws(function() {
Service._clusterManager._findCluster();
});
_("_findCluster() returns null on authentication errors.");
initializeIdentityWithTokenServerResponse({
status: 401,
headers: {"content-type": "application/json"},
body: "{}",
});
yield Service.identity.initializeWithCurrentIdentity();
yield Assert_rejects(Service.identity.whenReadyToAuthenticate.promise,
"should reject due to 401");
cluster = Service._clusterManager._findCluster();
Assert.strictEqual(cluster, null);
_("_findCluster() works with correct tokenserver response.");
let endpoint = "http://example.com/something";
initializeIdentityWithTokenServerResponse({
status: 200,
headers: {"content-type": "application/json"},
body:
JSON.stringify({
api_endpoint: endpoint,
duration: 300,
id: "id",
key: "key",
uid: "uid",
})
});
yield Service.identity.initializeWithCurrentIdentity();
yield Service.identity.whenReadyToAuthenticate.promise;
cluster = Service._clusterManager._findCluster();
// The cluster manager ensures a trailing "/"
Assert.strictEqual(cluster, endpoint + "/");
Svc.Prefs.resetBranch("");
});
function run_test() {
initTestLogging();
run_next_test();
}

Просмотреть файл

@ -37,6 +37,7 @@ const testingModules = [
"fakeservices.js",
"rotaryengine.js",
"utils.js",
"fxa_utils.js",
];
function run_test() {

Просмотреть файл

@ -124,6 +124,7 @@ skip-if = os == "android"
# Firefox Accounts specific tests
[test_fxa_startOver.js]
[test_fxa_service_cluster.js]
# Finally, we test each engine.
[test_addons_engine.js]