diff --git a/browser/base/content/syncQuota.js b/browser/base/content/syncQuota.js index 3eaa09b64a10..3984876cadf4 100644 --- a/browser/base/content/syncQuota.js +++ b/browser/base/content/syncQuota.js @@ -93,7 +93,7 @@ let gSyncQuota = { if (engines.length) { // The 'Weave' object will disappear once the window closes. let Service = Weave.Service; - Weave.Utils.delay(function() Service.sync(), 0); + Weave.Utils.nextTick(function() { Service.sync(); }); } return true; }, diff --git a/browser/base/content/syncSetup.js b/browser/base/content/syncSetup.js index 1a29093de645..87653e074d6a 100644 --- a/browser/base/content/syncSetup.js +++ b/browser/base/content/syncSetup.js @@ -72,6 +72,7 @@ var gSyncSetup = { Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), + haveCaptcha: true, captchaBrowser: null, wizard: null, _disabledSites: [], @@ -143,6 +144,7 @@ var gSyncSetup = { return false; this._settingUpNew = true; this.wizard.pageIndex = NEW_ACCOUNT_START_PAGE; + this.loadCaptcha(); }, useExistingAccount: function () { @@ -271,8 +273,9 @@ var gSyncSetup = { if (this._usingMainServers) return true; - if (this._validateServer(document.getElementById("existingServer"), false)) + if (this._validateServer(document.getElementById("existingServer"))) { return true; + } } return false; } @@ -365,6 +368,11 @@ var gSyncSetup = { this.onPassphraseGenerate(); this.checkFields(); break; + case NEW_ACCOUNT_CAPTCHA_PAGE: + if (!this.haveCaptcha) { + gSyncSetup.wizard.advance(); + } + break; case NEW_ACCOUNT_START_PAGE: this.wizard.getButton("extra1").hidden = false; this.wizard.getButton("next").hidden = false; @@ -478,12 +486,6 @@ var gSyncSetup = { image.setAttribute("status", "error"); label.value = Weave.Utils.getErrorString(error); return false; - case NEW_ACCOUNT_PP_PAGE: - // Time to load the captcha. - // First check for NoScript and whitelist the right sites. - this._handleNoScript(true); - this.captchaBrowser.loadURI(Weave.Service.miscAPI + "captcha_html"); - break; case EXISTING_ACCOUNT_LOGIN_PAGE: Weave.Service.account = Weave.Utils.normalizeAccount( document.getElementById("existingAccountName").value); @@ -553,9 +555,6 @@ var gSyncSetup = { gSyncUtils.openAddedClientFirstrun(); } - if (!Weave.Service.isLoggedIn) - Weave.Service.login(); - Weave.Service.syncOnIdle(1); }, @@ -715,6 +714,9 @@ var gSyncSetup = { } control.removeAttribute("editable"); Weave.Svc.Prefs.reset("serverURL"); + if (this._settingUpNew) { + this.loadCaptcha(); + } this.checkAccount(); this.status.server = true; document.getElementById("serverFeedbackRow").hidden = true; @@ -737,7 +739,7 @@ var gSyncSetup = { let feedback = document.getElementById("serverFeedbackRow"); let str = ""; if (el.value) { - valid = this._validateServer(el, true); + valid = this._validateServer(el); let str = valid ? "" : "serverInvalid.label"; this._setFeedbackMessage(feedback, valid, str); } @@ -752,9 +754,7 @@ var gSyncSetup = { this.checkFields(); }, - // xxxmpc - checkRemote is a hack, we can't verify a minimal server is live - // without auth, so we won't validate in the existing-server case. - _validateServer: function (element, checkRemote) { + _validateServer: function (element) { let valid = false; let val = element.value; if (!val) @@ -765,7 +765,7 @@ var gSyncSetup = { if (!uri) uri = Weave.Utils.makeURI("https://" + val); - if (uri && checkRemote) { + if (uri && this._settingUpNew) { function isValid(uri) { Weave.Service.serverURL = uri.spec; let check = Weave.Service.checkAccount("a"); @@ -782,6 +782,10 @@ var gSyncSetup = { } if (!valid) valid = isValid(uri); + + if (valid) { + this.loadCaptcha(); + } } else if (uri) { valid = true; @@ -949,6 +953,12 @@ var gSyncSetup = { this._setFeedback(element, success, str); }, + loadCaptcha: function loadCaptcha() { + // First check for NoScript and whitelist the right sites. + this._handleNoScript(true); + this.captchaBrowser.loadURI(Weave.Service.miscAPI + "captcha_html"); + }, + onStateChange: function(webProgress, request, stateFlags, status) { // We're only looking for the end of the frame load if ((stateFlags & Ci.nsIWebProgressListener.STATE_STOP) == 0) @@ -959,8 +969,18 @@ var gSyncSetup = { return; // If we didn't find the captcha, assume it's not needed and move on - if (request.QueryInterface(Ci.nsIHttpChannel).responseStatus == 404) - this.onWizardAdvance(); + if (request.QueryInterface(Ci.nsIHttpChannel).responseStatus == 404) { + this.haveCaptcha = false; + // Hide the browser just in case we end up displaying the captcha page + // due to a sign up error. + this.captchaBrowser.hidden = true; + if (this.wizard.pageIndex == NEW_ACCOUNT_CAPTCHA_PAGE) { + this.onWizardAdvance(); + } + } else { + this.haveCaptcha = true; + this.captchaBrowser.hidden = false; + } }, onProgressChange: function() {}, onStatusChange: function() {}, diff --git a/browser/base/content/syncSetup.xul b/browser/base/content/syncSetup.xul index b756dd020632..33b57b3aebcc 100644 --- a/browser/base/content/syncSetup.xul +++ b/browser/base/content/syncSetup.xul @@ -229,7 +229,8 @@ + onextra1="gSyncSetup.onSyncOptions()" + onpageshow="gSyncSetup.onPageShow();"> #include -#ifdef DEBUG #include -#endif - /* GLIBCXX_3.4.8 is from gcc 4.1.1 (111691) GLIBCXX_3.4.9 is from gcc 4.2.0 (111690) @@ -63,10 +60,9 @@ namespace std { template ostream& __ostream_insert(ostream&, const char*, streamsize); template istream& istream::_M_extract(double&); #endif -#ifdef DEBUG #if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14) /* Instantiate these templates to avoid GLIBCXX_3.4.14 symbol versions - * in debug builds */ + * depending on optimization level */ template char *string::_S_construct_aux_2(size_type, char, allocator const&); #ifdef _GLIBCXX_USE_WCHAR_T template wchar_t *wstring::_S_construct_aux_2(size_type, wchar_t, allocator const&); @@ -79,7 +75,6 @@ namespace std { template wstring& wstring::assign(wstring&&); #endif /* __GXX_EXPERIMENTAL_CXX0X__ */ #endif /* (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5) */ -#endif /* DEBUG */ } namespace std __attribute__((visibility("default"))) { diff --git a/config/rules.mk b/config/rules.mk index 9b4f271967db..c27f141979f5 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -903,6 +903,17 @@ endif endif # SHARED_LIBRARY || PROGRAM endif # WINNT_ endif # MOZ_PROFILE_GENERATE || MOZ_PROFILE_USE +ifdef MOZ_PROFILE_GENERATE +# Clean up profiling data during PROFILE_GENERATE phase +export:: +ifeq ($(OS_ARCH)_$(GNU_CC), WINNT_) + -$(RM) *.pgd +else +ifdef GNU_CC + -$(RM) *.gcda +endif +endif +endif endif # NO_PROFILE_GUIDED_OPTIMIZE ############################################## diff --git a/content/base/public/nsINodeInfo.h b/content/base/public/nsINodeInfo.h index 981e368b3b2c..8d3f216baf36 100644 --- a/content/base/public/nsINodeInfo.h +++ b/content/base/public/nsINodeInfo.h @@ -309,7 +309,7 @@ public: */ nsIDocument* GetDocument() const { - return mOwnerManager->GetDocument(); + return mDocument; } protected: @@ -359,6 +359,8 @@ protected: // nsNodeInfoManager needs to pass mInner to the hash table. friend class nsNodeInfoManager; + nsIDocument* mDocument; // Weak. Cache of mOwnerManager->mDocument + nsNodeInfoInner mInner; nsCOMPtr mIDAttributeAtom; diff --git a/content/base/src/nsDOMParser.cpp b/content/base/src/nsDOMParser.cpp index ca0bc66ddd49..041a8e10bf97 100644 --- a/content/base/src/nsDOMParser.cpp +++ b/content/base/src/nsDOMParser.cpp @@ -50,7 +50,6 @@ #include "nsIDOMClassInfo.h" #include "nsReadableUtils.h" #include "nsCRT.h" -#include "nsLoadListenerProxy.h" #include "nsStreamUtils.h" #include "nsThreadUtils.h" #include "nsNetCID.h" @@ -63,60 +62,13 @@ using namespace mozilla; -// nsIDOMEventListener -nsresult -nsDOMParser::HandleEvent(nsIDOMEvent* aEvent) -{ - return NS_OK; -} - -// nsIDOMLoadListener -nsresult -nsDOMParser::Load(nsIDOMEvent* aEvent) -{ - mLoopingForSyncLoad = PR_FALSE; - - return NS_OK; -} - -nsresult -nsDOMParser::BeforeUnload(nsIDOMEvent* aEvent) -{ - return NS_OK; -} - -nsresult -nsDOMParser::Unload(nsIDOMEvent* aEvent) -{ - return NS_OK; -} - -nsresult -nsDOMParser::Abort(nsIDOMEvent* aEvent) -{ - mLoopingForSyncLoad = PR_FALSE; - - return NS_OK; -} - -nsresult -nsDOMParser::Error(nsIDOMEvent* aEvent) -{ - mLoopingForSyncLoad = PR_FALSE; - - return NS_OK; -} - nsDOMParser::nsDOMParser() - : mLoopingForSyncLoad(PR_FALSE), - mAttemptedInit(PR_FALSE) + : mAttemptedInit(PR_FALSE) { } nsDOMParser::~nsDOMParser() { - NS_ABORT_IF_FALSE(!mLoopingForSyncLoad, "we rather crash than hang"); - mLoopingForSyncLoad = PR_FALSE; } DOMCI_DATA(DOMParser, nsDOMParser) @@ -126,8 +78,6 @@ NS_INTERFACE_MAP_BEGIN(nsDOMParser) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMParser) NS_INTERFACE_MAP_ENTRY(nsIDOMParser) NS_INTERFACE_MAP_ENTRY(nsIDOMParserJS) - NS_INTERFACE_MAP_ENTRY(nsIDOMLoadListener) - NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMParser) @@ -237,19 +187,6 @@ nsDOMParser::ParseFromStream(nsIInputStream *stream, getter_AddRefs(domDocument)); NS_ENSURE_SUCCESS(rv, rv); - // Register as a load listener on the document - nsCOMPtr target(do_QueryInterface(domDocument)); - if (target) { - nsWeakPtr requestWeak(do_GetWeakReference(static_cast(this))); - nsLoadListenerProxy* proxy = new nsLoadListenerProxy(requestWeak); - if (!proxy) return NS_ERROR_OUT_OF_MEMORY; - - // This will addref the proxy - rv = target->AddEventListenerByIID(static_cast(proxy), - NS_GET_IID(nsIDOMLoadListener)); - NS_ENSURE_SUCCESS(rv, rv); - } - // Create a fake channel nsCOMPtr parserChannel; NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI, nsnull, @@ -266,9 +203,6 @@ nsDOMParser::ParseFromStream(nsIInputStream *stream, // Tell the document to start loading nsCOMPtr listener; - AutoRestore restoreSyncLoop(mLoopingForSyncLoad); - mLoopingForSyncLoad = PR_TRUE; - // Have to pass PR_FALSE for reset here, else the reset will remove // our event listener. Should that listener addition move to later // than this call? Then we wouldn't need to mess around with @@ -319,15 +253,6 @@ nsDOMParser::ParseFromStream(nsIInputStream *stream, return NS_ERROR_FAILURE; } - // Process events until we receive a load, abort, or error event for the - // document object. That event may have already fired. - - nsIThread *thread = NS_GetCurrentThread(); - while (mLoopingForSyncLoad) { - if (!NS_ProcessNextEvent(thread)) - break; - } - domDocument.swap(*aResult); return NS_OK; diff --git a/content/base/src/nsDOMParser.h b/content/base/src/nsDOMParser.h index eaf829662c19..1acacfbd475a 100644 --- a/content/base/src/nsDOMParser.h +++ b/content/base/src/nsDOMParser.h @@ -41,13 +41,11 @@ #include "nsIDOMParser.h" #include "nsCOMPtr.h" #include "nsIURI.h" -#include "nsIDOMLoadListener.h" #include "nsWeakReference.h" #include "nsIJSNativeInitializer.h" class nsDOMParser : public nsIDOMParser, public nsIDOMParserJS, - public nsIDOMLoadListener, public nsIJSNativeInitializer, public nsSupportsWeakReference { @@ -63,16 +61,6 @@ public: // nsIDOMParserJS NS_DECL_NSIDOMPARSERJS - // nsIDOMEventListener - NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); - - // nsIDOMLoadListener - NS_IMETHOD Load(nsIDOMEvent* aEvent); - NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent); - NS_IMETHOD Unload(nsIDOMEvent* aEvent); - NS_IMETHOD Abort(nsIDOMEvent* aEvent); - NS_IMETHOD Error(nsIDOMEvent* aEvent); - // nsIJSNativeInitializer NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj, PRUint32 argc, jsval *argv); diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index ca65e2889f32..c304010242df 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -817,8 +817,11 @@ nsINode::IsEqualTo(nsINode* aOther) if (nodeType != node2->NodeType()) { return PR_FALSE; } - - if (!node1->mNodeInfo->Equals(node2->mNodeInfo)) { + + nsINodeInfo* nodeInfo1 = node1->mNodeInfo; + nsINodeInfo* nodeInfo2 = node2->mNodeInfo; + if (!nodeInfo1->Equals(nodeInfo2) || + nodeInfo1->GetExtraName() != nodeInfo2->GetExtraName()) { return PR_FALSE; } @@ -867,16 +870,6 @@ nsINode::IsEqualTo(nsINode* aOther) return PR_FALSE; } - if (nodeType == nsIDOMNode::PROCESSING_INSTRUCTION_NODE) { - nsCOMPtr domNode1 = do_QueryInterface(node1); - nsCOMPtr domNode2 = do_QueryInterface(node2); - domNode1->GetNodeName(string1); - domNode2->GetNodeName(string2); - if (!string1.Equals(string2)) { - return PR_FALSE; - } - } - break; } case nsIDOMNode::DOCUMENT_NODE: @@ -899,18 +892,11 @@ nsINode::IsEqualTo(nsINode* aOther) } case nsIDOMNode::DOCUMENT_TYPE_NODE: { - nsCOMPtr docType1 = do_QueryInterface(this); - nsCOMPtr docType2 = do_QueryInterface(aOther); + nsCOMPtr docType1 = do_QueryInterface(node1); + nsCOMPtr docType2 = do_QueryInterface(node2); NS_ASSERTION(docType1 && docType2, "Why don't we have a document type node?"); - // Node name - docType1->GetNodeName(string1); - docType2->GetNodeName(string2); - if (!string1.Equals(string2)) { - return PR_FALSE; - } - // Public ID docType1->GetPublicId(string1); docType2->GetPublicId(string2); diff --git a/content/base/src/nsNodeInfo.cpp b/content/base/src/nsNodeInfo.cpp index 8004e51915b4..e9e82ad4b3a7 100644 --- a/content/base/src/nsNodeInfo.cpp +++ b/content/base/src/nsNodeInfo.cpp @@ -120,6 +120,8 @@ nsNodeInfo::nsNodeInfo(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID, NS_ADDREF(mOwnerManager = aOwnerManager); NS_IF_ADDREF(mInner.mExtraName = aExtraName); + mDocument = aOwnerManager->GetDocument(); + // Now compute our cached members. // Qualified name. If we have no prefix, use ToString on diff --git a/content/base/src/nsNodeInfoManager.cpp b/content/base/src/nsNodeInfoManager.cpp index c57556451454..66c5ab7ff2d6 100644 --- a/content/base/src/nsNodeInfoManager.cpp +++ b/content/base/src/nsNodeInfoManager.cpp @@ -194,6 +194,14 @@ nsNodeInfoManager::Init(nsIDocument *aDocument) return NS_OK; } +// static +PRIntn +nsNodeInfoManager::DropNodeInfoDocument(PLHashEntry *he, PRIntn hashIndex, void *arg) +{ + static_cast(he->value)->mDocument = nsnull; + return HT_ENUMERATE_NEXT; +} + void nsNodeInfoManager::DropDocumentReference() { @@ -201,6 +209,8 @@ nsNodeInfoManager::DropDocumentReference() mBindingManager->DropDocumentReference(); } + PL_HashTableEnumerateEntries(mNodeInfoHash, DropNodeInfoDocument, nsnull); + mDocument = nsnull; } diff --git a/content/base/src/nsNodeInfoManager.h b/content/base/src/nsNodeInfoManager.h index 02a23d8dc57f..87e3eab2f4d4 100644 --- a/content/base/src/nsNodeInfoManager.h +++ b/content/base/src/nsNodeInfoManager.h @@ -153,6 +153,8 @@ protected: private: static PRIntn NodeInfoInnerKeyCompare(const void *key1, const void *key2); static PLHashNumber GetNodeInfoInnerHashValue(const void *key); + static PRIntn DropNodeInfoDocument(PLHashEntry *he, PRIntn hashIndex, + void *arg); PLHashTable *mNodeInfoHash; nsIDocument *mDocument; // WEAK diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp index e8c6f99469ef..97abaa73c440 100644 --- a/content/canvas/src/nsCanvasRenderingContext2D.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp @@ -3388,7 +3388,7 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1, // (!FloatValidate(sx, sy, sw, sh) || !FloatValidate(dx, dy, dw, dh)) // but we would also need to validate some sums for overflow (e.g. sx + sw). if (!FloatValidate(sx + sw, sy + sh, dx + dw, dy + dh)) { - return NS_ERROR_DOM_SYNTAX_ERR; + return NS_OK; } // Handle negative sw, sh, dw and dh by flipping the rectangle over in the diff --git a/content/canvas/test/test_canvas.html b/content/canvas/test/test_canvas.html index 1bccbcdac8dc..e0658e561cd4 100644 --- a/content/canvas/test/test_canvas.html +++ b/content/canvas/test/test_canvas.html @@ -3452,7 +3452,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -todo(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, 'should not throw exception'); } diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp index 4f262fd98df9..cf8a2ec2065d 100644 --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -631,18 +631,9 @@ static PRBool HasSourceChildren(nsIContent *aElement) return PR_FALSE; } -// Returns true if aElement has a src attribute, or a child. -static PRBool HasPotentialResource(nsIContent *aElement) -{ - nsAutoString src; - if (aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) - return PR_TRUE; - return HasSourceChildren(aElement); -} - void nsHTMLMediaElement::SelectResource() { - if (!HasPotentialResource(this)) { + if (!HasAttr(kNameSpaceID_None, nsGkAtoms::src) && !HasSourceChildren(this)) { // The media element has neither a src attribute nor any source // element children, abort the load. mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY; diff --git a/content/media/nsBuiltinDecoderStateMachine.cpp b/content/media/nsBuiltinDecoderStateMachine.cpp index 0671a752ddac..20bf08155947 100644 --- a/content/media/nsBuiltinDecoderStateMachine.cpp +++ b/content/media/nsBuiltinDecoderStateMachine.cpp @@ -1035,7 +1035,7 @@ PRInt64 nsBuiltinDecoderStateMachine::GetUndecodedData() const NS_ENSURE_SUCCESS(res, 0); if (start <= currentTime && end >= currentTime) { - return static_cast((end - currentTime) * 1000); + return static_cast((end - currentTime) * USECS_PER_S); } } return 0; diff --git a/content/test/unit/test_isequalnode.js b/content/test/unit/test_isequalnode.js index 2e8529fa6cf2..0ae07ddc3c7a 100644 --- a/content/test/unit/test_isequalnode.js +++ b/content/test/unit/test_isequalnode.js @@ -50,6 +50,7 @@ function run_test() test_isEqualNode_normalization(); test_isEqualNode_whitespace(); test_isEqualNode_namespaces(); + test_isEqualNode_wholeDoc(); // XXX should Node.isEqualNode(null) throw or return false? //test_isEqualNode_null(); @@ -400,6 +401,21 @@ function test_isEqualNode_null() } } +function test_isEqualNode_wholeDoc() +{ + doc = ParseFile("isequalnode_data.xml"); + var doc2 = ParseFile("isequalnode_data.xml"); + var tw1 = + doc.createTreeWalker(doc, Components.interfaces.nsIDOMNodeFilter.SHOW_ALL, + null, false); + var tw2 = + doc2.createTreeWalker(doc2, Components.interfaces.nsIDOMNodeFilter.SHOW_ALL, + null, false); + do { + check_eq_nodes(tw1.currentNode, tw2.currentNode); + tw1.nextNode(); + } while(tw2.nextNode()); +} // UTILITY FUNCTIONS diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk index 9b4f271967db..c27f141979f5 100644 --- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -903,6 +903,17 @@ endif endif # SHARED_LIBRARY || PROGRAM endif # WINNT_ endif # MOZ_PROFILE_GENERATE || MOZ_PROFILE_USE +ifdef MOZ_PROFILE_GENERATE +# Clean up profiling data during PROFILE_GENERATE phase +export:: +ifeq ($(OS_ARCH)_$(GNU_CC), WINNT_) + -$(RM) *.pgd +else +ifdef GNU_CC + -$(RM) *.gcda +endif +endif +endif endif # NO_PROFILE_GUIDED_OPTIMIZE ############################################## diff --git a/js/src/jit-test/tests/basic/testStackIterDebug.js b/js/src/jit-test/tests/basic/testStackIterDebug.js index 2fe3fe31a951..92e1a7f92061 100644 --- a/js/src/jit-test/tests/basic/testStackIterDebug.js +++ b/js/src/jit-test/tests/basic/testStackIterDebug.js @@ -50,3 +50,13 @@ function assertStackIs(s1) { (function f() { var o = { toString:function() { evalInFrame(1, "assertStackIs(['eval-code', f, 'global-code'])"); }}; [o,o].sort() })(); (function f() { var o = { toString:function() { evalInFrame(1, "assertStackIs(['eval-code', f, 'global-code'])", true); }}; [o,o].sort() })(); + +function inner() { + (function puppies() { + evalInFrame(1, "assertStackIs(['eval-code', inner, String.prototype.replace, outer, String.prototype.replace, 'global-code'])"); + })(); +} +function outer() { + "bbb".replace(/b/g, inner); +} +"aaa".replace(/a/g, outer); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index bde955377d19..85335077666a 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -2806,7 +2806,8 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) newlen = 0; newarr = NULL; #endif - jsint start = 0, end = length, step = 1; + jsuint start = 0, end = length; + jsint step = 1; switch (mode) { case REDUCE_RIGHT: @@ -2875,7 +2876,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) Value objv = ObjectValue(*obj); AutoValueRooter tvr(cx); - for (jsint i = start; i != end; i += step) { + for (jsuint i = start; i != end; i += step) { JSBool hole; ok = JS_CHECK_OPERATION_LIMIT(cx) && GetElement(cx, obj, i, &hole, tvr.addr()); diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 6ff60df5fb95..21f3d52b3606 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -287,6 +287,12 @@ StackSegment::pushCall(CallArgsList &callList) calls_ = &callList; } +void +StackSegment::pointAtCall(CallArgsList &callList) +{ + calls_ = &callList; +} + void StackSegment::popCall() { @@ -647,7 +653,7 @@ ContextStack::pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thi /* pushRegs() below links the prev-frame; manually link the prev-call. */ if (evalInFrame && evalInFrameCalls) - seg_->pushCall(*evalInFrameCalls); + seg_->pointAtCall(*evalInFrameCalls); efg->prevRegs_ = seg_->pushRegs(efg->regs_); JS_ASSERT(space().firstUnused() == efg->regs_.sp); diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 5de8ad3cbb89..f677e86e7c66 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1272,6 +1272,7 @@ class StackSegment FrameRegs *pushRegs(FrameRegs ®s); void popRegs(FrameRegs *regs); void pushCall(CallArgsList &callList); + void pointAtCall(CallArgsList &callList); void popCall(); /* For jit access: */ diff --git a/layout/base/crashtests/663295.html b/layout/base/crashtests/663295.html new file mode 100644 index 000000000000..377f587e018d --- /dev/null +++ b/layout/base/crashtests/663295.html @@ -0,0 +1,2 @@ +A B C +ت diff --git a/layout/base/crashtests/663662-1.html b/layout/base/crashtests/663662-1.html new file mode 100644 index 000000000000..0dcba5679d2d --- /dev/null +++ b/layout/base/crashtests/663662-1.html @@ -0,0 +1 @@ +   X䍲Y diff --git a/layout/base/crashtests/663662-2.html b/layout/base/crashtests/663662-2.html new file mode 100644 index 000000000000..0aab12a79b15 --- /dev/null +++ b/layout/base/crashtests/663662-2.html @@ -0,0 +1 @@ +   X䍲Y diff --git a/layout/base/crashtests/crashtests.list b/layout/base/crashtests/crashtests.list index b640fe230346..760656daf8df 100644 --- a/layout/base/crashtests/crashtests.list +++ b/layout/base/crashtests/crashtests.list @@ -331,3 +331,6 @@ load 645193.html load 650475.xhtml load 650489.xhtml load 653133-1.html +load 663295.html +load 663662-1.html +load 663662-2.html diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index 890369aa065e..cc7355a66059 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -650,6 +650,33 @@ PRBool IsBidiLeaf(nsIFrame* aFrame) { || !aFrame->IsFrameOfType(nsIFrame::eBidiInlineContainer); } +void +nsBidiPresUtils::AdvanceAndAppendFrame(nsIFrame** aFrame, + nsBlockInFlowLineIterator* aLineIter, + nsIFrame** aNextSibling) +{ + nsIFrame* frame = *aFrame; + nsIFrame* nextSibling = *aNextSibling; + + frame = frame->GetNextContinuation(); + if (frame) { + mLogicalFrames.AppendElement(frame); + AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame); + mLinePerFrame.AppendElement(aLineIter->GetLine().get()); + + /* + * If we have already overshot the saved next-sibling while + * scanning the frame's continuations, advance it. + */ + if (frame == nextSibling) { + nextSibling = frame->GetNextSibling(); + } + } + + *aFrame = frame; + *aNextSibling = nextSibling; +} + void nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame, nsBlockInFlowLineIterator* aLineIter, @@ -753,14 +780,17 @@ nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame, PRInt32 start, end; frame->GetOffsets(start, end); - PRInt32 endLine = text.FindCharInSet(NS_LITERAL_STRING("\n\r"), - start); + PRInt32 endLine = text.FindChar('\n', start); if (endLine == -1) { /* - * If there is no newline in the frame, just save the text and - * do bidi resolution later + * If there is no newline in the text content, just save the + * text from this frame and its continuations, and do bidi + * resolution later */ mBuffer.Append(Substring(text, start)); + while (frame && nextSibling) { + AdvanceAndAppendFrame(&frame, aLineIter, &nextSibling); + } break; } @@ -775,24 +805,13 @@ nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame, * If the frame ends before the new line, save the text and move * into the next continuation */ - while (end < endLine) { + while (end < endLine && nextSibling) { mBuffer.Append(Substring(text, start, end - start)); - frame = frame->GetNextContinuation(); + + AdvanceAndAppendFrame(&frame, aLineIter, &nextSibling); NS_ASSERTION(frame, "Premature end of continuation chain"); frame->GetOffsets(start, end); - mLogicalFrames.AppendElement(frame); - AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame); - mLinePerFrame.AppendElement(aLineIter->GetLine().get()); - - /* - * If we have already overshot the saved next-sibling while - * scanning the frame's continuations, advance it. - */ - if (frame == nextSibling) { - nextSibling = frame->GetNextSibling(); - } } - mBuffer.Append(Substring(text, start, endLine - start)); PRBool createdContinuation = PR_FALSE; diff --git a/layout/base/nsBidiPresUtils.h b/layout/base/nsBidiPresUtils.h index 1f335f99e93e..22d88f9de104 100644 --- a/layout/base/nsBidiPresUtils.h +++ b/layout/base/nsBidiPresUtils.h @@ -362,6 +362,9 @@ private: nsBidiPositionResolve* aPosResolve, /* may be null */ PRInt32 aPosResolveCount, nscoord* aWidth /* may be null */); + void AdvanceAndAppendFrame(nsIFrame** aFrame, + nsBlockInFlowLineIterator* aLineIter, + nsIFrame** aNextSibling); /** * Traverse the child frames of the block element and: diff --git a/layout/base/tests/Makefile.in b/layout/base/tests/Makefile.in index c817d9e427bb..8fffe90118a2 100644 --- a/layout/base/tests/Makefile.in +++ b/layout/base/tests/Makefile.in @@ -149,6 +149,8 @@ _TEST_FILES = \ test_bug548545.xhtml \ test_bug558663.html \ test_bug559499.html \ + test_bug582181-1.html \ + test_bug582181-2.html \ test_flush_on_paint.html \ test_mozPaintCount.html \ test_scroll_selection_into_view.html \ diff --git a/layout/base/tests/test_bug582181-1.html b/layout/base/tests/test_bug582181-1.html new file mode 100644 index 000000000000..2fea21f012a3 --- /dev/null +++ b/layout/base/tests/test_bug582181-1.html @@ -0,0 +1,58 @@ + + + + + Test for Bug 582181 + + + + + + + + +Mozilla Bug 582181 +

+
+ +
+
+
+
+ + diff --git a/layout/base/tests/test_bug582181-2.html b/layout/base/tests/test_bug582181-2.html new file mode 100644 index 000000000000..93a2d5abcf02 --- /dev/null +++ b/layout/base/tests/test_bug582181-2.html @@ -0,0 +1,61 @@ + + + + + Test for Bug 582181 + + + + + + + + +Mozilla Bug 582181 +

+
+ +
+
+
+
+ + diff --git a/media/libvpx/bug646815.patch b/media/libvpx/bug646815.patch new file mode 100644 index 000000000000..16a1fc1bb5f0 --- /dev/null +++ b/media/libvpx/bug646815.patch @@ -0,0 +1,683 @@ +diff --git a/media/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm b/media/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm +--- a/media/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm ++++ b/media/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm +@@ -27,17 +27,17 @@ + stmdb sp!, {r4 - r11, lr} + str r3, [sp, #-184]! ;reserve space on stack for temporary storage, store yoffset + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + add lr, sp, #4 ;point to temporary buffer + beq skip_firstpass_filter + + ;first-pass filter +- ldr r12, _filter8_coeff_ ++ adr r12, filter8_coeff + sub r0, r0, r1, lsl #1 + + add r2, r12, r2, lsl #4 ;calculate filter location + add r0, r0, #3 ;adjust src only for loading convinience + + ldr r3, [r2] ; load up packed filter coefficients + ldr r4, [r2, #4] + ldr r5, [r2, #8] +@@ -116,17 +116,17 @@ + secondpass_filter + ldr r3, [sp], #4 ; load back yoffset + ldr r0, [sp, #216] ; load dst address from stack 180+36 + ldr r1, [sp, #220] ; load dst stride from stack 180+40 + + cmp r3, #0 + beq skip_secondpass_filter + +- ldr r12, _filter8_coeff_ ++ adr r12, filter8_coeff + add lr, r12, r3, lsl #4 ;calculate filter location + + mov r2, #0x00080000 + + ldr r3, [lr] ; load up packed filter coefficients + ldr r4, [lr, #4] + ldr r5, [lr, #8] + +@@ -242,18 +242,16 @@ skip_secondpass_hloop + + ENDP + + ;----------------- + AREA subpelfilters8_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_filter8_coeff_ +- DCD filter8_coeff + filter8_coeff + DCD 0x00000000, 0x00000080, 0x00000000, 0x00000000 + DCD 0xfffa0000, 0x000c007b, 0x0000ffff, 0x00000000 + DCD 0xfff50002, 0x0024006c, 0x0001fff8, 0x00000000 + DCD 0xfff70000, 0x0032005d, 0x0000fffa, 0x00000000 + DCD 0xfff00003, 0x004d004d, 0x0003fff0, 0x00000000 + DCD 0xfffa0000, 0x005d0032, 0x0000fff7, 0x00000000 + DCD 0xfff80001, 0x006c0024, 0x0002fff5, 0x00000000 +diff --git a/media/libvpx/vp8/common/arm/neon/bilinearpredict16x16_neon.asm b/media/libvpx/vp8/common/arm/neon/bilinearpredict16x16_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/bilinearpredict16x16_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/bilinearpredict16x16_neon.asm +@@ -20,17 +20,17 @@ + ; r2 int xoffset, + ; r3 int yoffset, + ; r4 unsigned char *dst_ptr, + ; stack(r5) int dst_pitch + + |vp8_bilinear_predict16x16_neon| PROC + push {r4-r5, lr} + +- ldr r12, _bifilter16_coeff_ ++ adr r12, bifilter16_coeff + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_bfilter16x16_only + + add r2, r12, r2, lsl #3 ;calculate filter location + +@@ -349,14 +349,12 @@ filt_blk2d_spo16x16_loop_neon + + ENDP + + ;----------------- + AREA bifilters16_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_bifilter16_coeff_ +- DCD bifilter16_coeff + bifilter16_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END +diff --git a/media/libvpx/vp8/common/arm/neon/bilinearpredict4x4_neon.asm b/media/libvpx/vp8/common/arm/neon/bilinearpredict4x4_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/bilinearpredict4x4_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/bilinearpredict4x4_neon.asm +@@ -20,17 +20,17 @@ + ; r2 int xoffset, + ; r3 int yoffset, + ; r4 unsigned char *dst_ptr, + ; stack(lr) int dst_pitch + + |vp8_bilinear_predict4x4_neon| PROC + push {r4, lr} + +- ldr r12, _bifilter4_coeff_ ++ adr r12, bifilter4_coeff + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq skip_firstpass_filter + + ;First pass: output_height lines x output_width columns (5x4) + vld1.u8 {d2}, [r0], r1 ;load src data +@@ -122,14 +122,12 @@ skip_secondpass_filter + + ENDP + + ;----------------- + AREA bilinearfilters4_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_bifilter4_coeff_ +- DCD bifilter4_coeff + bifilter4_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END +diff --git a/media/libvpx/vp8/common/arm/neon/bilinearpredict8x4_neon.asm b/media/libvpx/vp8/common/arm/neon/bilinearpredict8x4_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/bilinearpredict8x4_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/bilinearpredict8x4_neon.asm +@@ -20,17 +20,17 @@ + ; r2 int xoffset, + ; r3 int yoffset, + ; r4 unsigned char *dst_ptr, + ; stack(lr) int dst_pitch + + |vp8_bilinear_predict8x4_neon| PROC + push {r4, lr} + +- ldr r12, _bifilter8x4_coeff_ ++ adr r12, bifilter8x4_coeff + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq skip_firstpass_filter + + ;First pass: output_height lines x output_width columns (5x8) + add r2, r12, r2, lsl #3 ;calculate filter location +@@ -127,14 +127,12 @@ skip_secondpass_filter + + ENDP + + ;----------------- + AREA bifilters8x4_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_bifilter8x4_coeff_ +- DCD bifilter8x4_coeff + bifilter8x4_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END +diff --git a/media/libvpx/vp8/common/arm/neon/bilinearpredict8x8_neon.asm b/media/libvpx/vp8/common/arm/neon/bilinearpredict8x8_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/bilinearpredict8x8_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/bilinearpredict8x8_neon.asm +@@ -20,17 +20,17 @@ + ; r2 int xoffset, + ; r3 int yoffset, + ; r4 unsigned char *dst_ptr, + ; stack(lr) int dst_pitch + + |vp8_bilinear_predict8x8_neon| PROC + push {r4, lr} + +- ldr r12, _bifilter8_coeff_ ++ adr r12, bifilter8_coeff + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq skip_firstpass_filter + + ;First pass: output_height lines x output_width columns (9x8) + add r2, r12, r2, lsl #3 ;calculate filter location +@@ -175,14 +175,12 @@ skip_secondpass_filter + + ENDP + + ;----------------- + AREA bifilters8_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_bifilter8_coeff_ +- DCD bifilter8_coeff + bifilter8_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END +diff --git a/media/libvpx/vp8/common/arm/neon/loopfilter_neon.asm b/media/libvpx/vp8/common/arm/neon/loopfilter_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/loopfilter_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/loopfilter_neon.asm +@@ -303,17 +303,17 @@ + ; q4 p2 + ; q5 p1 + ; q6 p0 + ; q7 q0 + ; q8 q1 + ; q9 q2 + ; q10 q3 + |vp8_loop_filter_neon| PROC +- ldr r12, _lf_coeff_ ++ adr r12, lf_coeff + + ; vp8_filter_mask + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q4, q10, q9 ; abs(q3 - q2) +@@ -393,17 +393,15 @@ + veor q6, q11, q0 ; *op0 = u^0x80 + veor q7, q10, q0 ; *oq0 = u^0x80 + veor q8, q12, q0 ; *oq1 = u^0x80 + + bx lr + ENDP ; |vp8_loop_filter_horizontal_edge_y_neon| + + AREA loopfilter_dat, DATA, READONLY +-_lf_coeff_ +- DCD lf_coeff + lf_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + DCD 0x01010101, 0x01010101, 0x01010101, 0x01010101 + + END +diff --git a/media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm b/media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm +@@ -23,17 +23,17 @@ + ; r2 const signed char *flimit, + ; r3 const signed char *limit, + ; stack(r4) const signed char *thresh, + ; //stack(r5) int count --unused + + |vp8_loop_filter_simple_horizontal_edge_neon| PROC + sub r0, r0, r1, lsl #1 ; move src pointer down by 2 lines + +- ldr r12, _lfhy_coeff_ ++ adr r12, lfhy_coeff + vld1.u8 {q5}, [r0], r1 ; p1 + vld1.s8 {d2[], d3[]}, [r2] ; flimit + vld1.s8 {d26[], d27[]}, [r3] ; limit -> q13 + vld1.u8 {q6}, [r0], r1 ; p0 + vld1.u8 {q0}, [r12]! ; 0x80 + vld1.u8 {q7}, [r0], r1 ; q0 + vld1.u8 {q10}, [r12]! ; 0x03 + vld1.u8 {q8}, [r0] ; q1 +@@ -103,16 +103,14 @@ + bx lr + ENDP ; |vp8_loop_filter_simple_horizontal_edge_neon| + + ;----------------- + AREA hloopfiltery_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 16 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_lfhy_coeff_ +- DCD lfhy_coeff + lfhy_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + + END +diff --git a/media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm b/media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm +@@ -27,17 +27,17 @@ + + |vp8_loop_filter_simple_vertical_edge_neon| PROC + sub r0, r0, #2 ; move src pointer down by 2 columns + + vld4.8 {d6[0], d7[0], d8[0], d9[0]}, [r0], r1 + vld1.s8 {d2[], d3[]}, [r2] ; flimit + vld1.s8 {d26[], d27[]}, [r3] ; limit -> q13 + vld4.8 {d6[1], d7[1], d8[1], d9[1]}, [r0], r1 +- ldr r12, _vlfy_coeff_ ++ adr r12, vlfy_coeff + vld4.8 {d6[2], d7[2], d8[2], d9[2]}, [r0], r1 + vld4.8 {d6[3], d7[3], d8[3], d9[3]}, [r0], r1 + vld4.8 {d6[4], d7[4], d8[4], d9[4]}, [r0], r1 + vld4.8 {d6[5], d7[5], d8[5], d9[5]}, [r0], r1 + vld4.8 {d6[6], d7[6], d8[6], d9[6]}, [r0], r1 + vld4.8 {d6[7], d7[7], d8[7], d9[7]}, [r0], r1 + + vld4.8 {d10[0], d11[0], d12[0], d13[0]}, [r0], r1 +@@ -144,16 +144,14 @@ + bx lr + ENDP ; |vp8_loop_filter_simple_vertical_edge_neon| + + ;----------------- + AREA vloopfiltery_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 16 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_vlfy_coeff_ +- DCD vlfy_coeff + vlfy_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + + END +diff --git a/media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.asm b/media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.asm +@@ -367,17 +367,17 @@ + ; q5 p1 + ; q6 p0 + ; q7 q0 + ; q8 q1 + ; q9 q2 + ; q10 q3 + + |vp8_mbloop_filter_neon| PROC +- ldr r12, _mblf_coeff_ ++ adr r12, mblf_coeff + + ; vp8_filter_mask + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q0, q10, q9 ; abs(q3 - q2) +@@ -501,18 +501,16 @@ + veor q5, q12, q0 ; *op2 = s^0x80 + veor q7, q15, q0 ; *oq0 = s^0x80 + veor q6, q14, q0 ; *op0 = s^0x80 + + bx lr + ENDP ; |vp8_mbloop_filter_neon| + + AREA mbloopfilter_dat, DATA, READONLY +-_mblf_coeff_ +- DCD mblf_coeff + mblf_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + DCD 0x003f003f, 0x003f003f, 0x003f003f, 0x003f003f + DCD 0x09090909, 0x09090909, 0x12121212, 0x12121212 + DCD 0x1b1b1b1b, 0x1b1b1b1b + +diff --git a/media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.asm b/media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.asm +@@ -26,17 +26,17 @@ + ;static const int sinpi8sqrt2 =35468; + ;static const int rounding = 0; + ;Optimization note: The resulted data from dequantization are signed 13-bit data that is + ;in the range of [-4096, 4095]. This allows to use "vqdmulh"(neon) instruction since + ;it won't go out of range (13+16+1=30bits<32bits). This instruction gives the high half + ;result of the multiplication that is needed in IDCT. + + |vp8_short_idct4x4llm_neon| PROC +- ldr r12, _idct_coeff_ ++ adr r12, idct_coeff + vld1.16 {q1, q2}, [r0] + vld1.16 {d0}, [r12] + + vswp d3, d4 ;q2(vp[4] vp[12]) + + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + +@@ -112,16 +112,14 @@ + + ENDP + + ;----------------- + AREA idct4x4_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_idct_coeff_ +- DCD idct_coeff + idct_coeff + DCD 0x4e7b4e7b, 0x8a8c8a8c + + ;20091, 20091, 35468, 35468 + + END +diff --git a/media/libvpx/vp8/common/arm/neon/sixtappredict16x16_neon.asm b/media/libvpx/vp8/common/arm/neon/sixtappredict16x16_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/sixtappredict16x16_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/sixtappredict16x16_neon.asm +@@ -28,17 +28,17 @@ + ; that the result can be a large positive number (> 2^15-1), which could be confused as a + ; negtive number. To avoid that error, apply filter coeffs in the order of 0, 1, 4 ,5 ,2, + ; which ensures that the result stays in s16 range. Finally, saturated add the result by + ; applying 3rd filter coeff. Same applys to other filter functions. + + |vp8_sixtap_predict16x16_neon| PROC + push {r4-r5, lr} + +- ldr r12, _filter16_coeff_ ++ adrl r12, filter16_coeff + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter16x16_only + + add r2, r12, r2, lsl #5 ;calculate filter location + +@@ -475,18 +475,16 @@ secondpass_only_inner_loop_neon + + ENDP + + ;----------------- + AREA subpelfilters16_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_filter16_coeff_ +- DCD filter16_coeff + filter16_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 +diff --git a/media/libvpx/vp8/common/arm/neon/sixtappredict4x4_neon.asm b/media/libvpx/vp8/common/arm/neon/sixtappredict4x4_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/sixtappredict4x4_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/sixtappredict4x4_neon.asm +@@ -20,17 +20,17 @@ + ; r2 int xoffset, + ; r3 int yoffset, + ; stack(r4) unsigned char *dst_ptr, + ; stack(lr) int dst_pitch + + |vp8_sixtap_predict_neon| PROC + push {r4, lr} + +- ldr r12, _filter4_coeff_ ++ adrl r12, filter4_coeff + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter4x4_only + + add r2, r12, r2, lsl #5 ;calculate filter location + +@@ -406,18 +406,16 @@ secondpass_filter4x4_only + + ENDP + + ;----------------- + AREA subpelfilters4_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_filter4_coeff_ +- DCD filter4_coeff + filter4_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 +diff --git a/media/libvpx/vp8/common/arm/neon/sixtappredict8x4_neon.asm b/media/libvpx/vp8/common/arm/neon/sixtappredict8x4_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/sixtappredict8x4_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/sixtappredict8x4_neon.asm +@@ -20,17 +20,17 @@ + ; r2 int xoffset, + ; r3 int yoffset, + ; r4 unsigned char *dst_ptr, + ; stack(r5) int dst_pitch + + |vp8_sixtap_predict8x4_neon| PROC + push {r4-r5, lr} + +- ldr r12, _filter8_coeff_ ++ adrl r12, filter8_coeff + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter8x4_only + + add r2, r12, r2, lsl #5 ;calculate filter location + +@@ -457,18 +457,16 @@ secondpass_filter8x4_only + + ENDP + + ;----------------- + AREA subpelfilters8_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_filter8_coeff_ +- DCD filter8_coeff + filter8_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 +diff --git a/media/libvpx/vp8/common/arm/neon/sixtappredict8x8_neon.asm b/media/libvpx/vp8/common/arm/neon/sixtappredict8x8_neon.asm +--- a/media/libvpx/vp8/common/arm/neon/sixtappredict8x8_neon.asm ++++ b/media/libvpx/vp8/common/arm/neon/sixtappredict8x8_neon.asm +@@ -20,17 +20,17 @@ + ; r2 int xoffset, + ; r3 int yoffset, + ; stack(r4) unsigned char *dst_ptr, + ; stack(r5) int dst_pitch + + |vp8_sixtap_predict8x8_neon| PROC + push {r4-r5, lr} + +- ldr r12, _filter8_coeff_ ++ adrl r12, filter8_coeff + + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter8x8_only + + add r2, r12, r2, lsl #5 ;calculate filter location +@@ -508,18 +508,16 @@ filt_blk2d_spo8x8_loop_neon + + ENDP + + ;----------------- + AREA subpelfilters8_dat, DATA, READWRITE ;read/write by default + ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. + ;One word each is reserved. Label filter_coeff can be used to access the data. + ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +-_filter8_coeff_ +- DCD filter8_coeff + filter8_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 +diff --git a/media/libvpx/vp8/decoder/arm/neon/dequant_idct_neon.asm b/media/libvpx/vp8/decoder/arm/neon/dequant_idct_neon.asm +--- a/media/libvpx/vp8/decoder/arm/neon/dequant_idct_neon.asm ++++ b/media/libvpx/vp8/decoder/arm/neon/dequant_idct_neon.asm +@@ -30,17 +30,17 @@ + ldr r1, [sp] ; pitch + vld1.32 {d14[0]}, [r2], r1 + vld1.32 {d14[1]}, [r2], r1 + vld1.32 {d15[0]}, [r2], r1 + vld1.32 {d15[1]}, [r2] + + ldr r1, [sp, #4] ; stride + +- ldr r12, _CONSTANTS_ ++ adr r12, _CONSTANTS_ + + vmul.i16 q1, q3, q5 ;input for short_idct4x4llm_neon + vmul.i16 q2, q4, q6 + + ;|short_idct4x4llm_neon| PROC + vld1.16 {d0}, [r12] + vswp d3, d4 ;q2(vp[4] vp[12]) + +@@ -118,13 +118,13 @@ + vst1.32 {d1[0]}, [r3], r1 + vst1.32 {d1[1]}, [r3] + + bx lr + + ENDP ; |vp8_dequant_idct_add_neon| + + ; Constant Pool +-_CONSTANTS_ DCD cospi8sqrt2minus1 ++_CONSTANTS_ EQU cospi8sqrt2minus1 + cospi8sqrt2minus1 DCD 0x4e7b4e7b + sinpi8sqrt2 DCD 0x8a8c8a8c + + END +diff --git a/media/libvpx/vp8/decoder/arm/neon/idct_dequant_dc_full_2x_neon.asm b/media/libvpx/vp8/decoder/arm/neon/idct_dequant_dc_full_2x_neon.asm +--- a/media/libvpx/vp8/decoder/arm/neon/idct_dequant_dc_full_2x_neon.asm ++++ b/media/libvpx/vp8/decoder/arm/neon/idct_dequant_dc_full_2x_neon.asm +@@ -36,17 +36,17 @@ + vld1.32 {d29[0]}, [r2], r1 + vld1.32 {d29[1]}, [r12], r1 + vld1.32 {d30[0]}, [r2], r1 + vld1.32 {d30[1]}, [r12], r1 + vld1.32 {d31[0]}, [r2] + ldr r1, [sp, #4] + vld1.32 {d31[1]}, [r12] + +- ldr r2, _CONSTANTS_ ++ adr r2, _CONSTANTS_ + + ldrh r12, [r1], #2 ; lo *dc + ldrh r1, [r1] ; hi *dc + + ; dequant: q[i] = q[i] * dq[i] + vmul.i16 q2, q2, q0 + vmul.i16 q3, q3, q1 + vmul.i16 q4, q4, q0 +@@ -193,14 +193,14 @@ + vst1.32 {d3[0]}, [r3] + vst1.32 {d3[1]}, [r2] + + bx lr + + ENDP ; |idct_dequant_dc_full_2x_neon| + + ; Constant Pool +-_CONSTANTS_ DCD cospi8sqrt2minus1 ++_CONSTANTS_ EQU cospi8sqrt2minus1 + cospi8sqrt2minus1 DCD 0x4e7b + ; because the lowest bit in 0x8a8c is 0, we can pre-shift this + sinpi8sqrt2 DCD 0x4546 + + END +diff --git a/media/libvpx/vp8/decoder/arm/neon/idct_dequant_full_2x_neon.asm b/media/libvpx/vp8/decoder/arm/neon/idct_dequant_full_2x_neon.asm +--- a/media/libvpx/vp8/decoder/arm/neon/idct_dequant_full_2x_neon.asm ++++ b/media/libvpx/vp8/decoder/arm/neon/idct_dequant_full_2x_neon.asm +@@ -35,17 +35,17 @@ + vld1.32 {d28[1]}, [r12], r1 ; r pre + vld1.32 {d29[0]}, [r2], r1 + vld1.32 {d29[1]}, [r12], r1 + vld1.32 {d30[0]}, [r2], r1 + vld1.32 {d30[1]}, [r12], r1 + vld1.32 {d31[0]}, [r2] + vld1.32 {d31[1]}, [r12] + +- ldr r2, _CONSTANTS_ ++ adr r2, _CONSTANTS_ + + ; dequant: q[i] = q[i] * dq[i] + vmul.i16 q2, q2, q0 + vmul.i16 q3, q3, q1 + vmul.i16 q4, q4, q0 + vmul.i16 q5, q5, q1 + + vld1.16 {d0}, [r2] +@@ -185,14 +185,14 @@ + vst1.32 {d3[0]}, [r3] + vst1.32 {d3[1]}, [r2] + + bx lr + + ENDP ; |idct_dequant_full_2x_neon| + + ; Constant Pool +-_CONSTANTS_ DCD cospi8sqrt2minus1 ++_CONSTANTS_ EQU cospi8sqrt2minus1 + cospi8sqrt2minus1 DCD 0x4e7b + ; because the lowest bit in 0x8a8c is 0, we can pre-shift this + sinpi8sqrt2 DCD 0x4546 + + END diff --git a/media/libvpx/update.sh b/media/libvpx/update.sh index 63bcea6b8a17..56748a7d7ca6 100755 --- a/media/libvpx/update.sh +++ b/media/libvpx/update.sh @@ -322,4 +322,7 @@ patch -p3 < solaris.patch patch -p1 < xcode4.patch # Patch to fix data race on global function pointers -patch -p1 < bug640935.patch +patch -p3 < bug640935.patch + +# Patch to avoid text relocations on ARM +patch -p3 < bug646815.patch diff --git a/media/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm b/media/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm index 8b9939484908..033df6c94a7f 100644 --- a/media/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm +++ b/media/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm @@ -32,7 +32,7 @@ beq skip_firstpass_filter ;first-pass filter - ldr r12, _filter8_coeff_ + adr r12, filter8_coeff sub r0, r0, r1, lsl #1 add r2, r12, r2, lsl #4 ;calculate filter location @@ -121,7 +121,7 @@ secondpass_filter cmp r3, #0 beq skip_secondpass_filter - ldr r12, _filter8_coeff_ + adr r12, filter8_coeff add lr, r12, r3, lsl #4 ;calculate filter location mov r2, #0x00080000 @@ -247,8 +247,6 @@ skip_secondpass_hloop ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_filter8_coeff_ - DCD filter8_coeff filter8_coeff DCD 0x00000000, 0x00000080, 0x00000000, 0x00000000 DCD 0xfffa0000, 0x000c007b, 0x0000ffff, 0x00000000 diff --git a/media/libvpx/vp8/common/arm/neon/bilinearpredict16x16_neon.asm b/media/libvpx/vp8/common/arm/neon/bilinearpredict16x16_neon.asm index bb72bad1f0ba..e8d4d66cb931 100644 --- a/media/libvpx/vp8/common/arm/neon/bilinearpredict16x16_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/bilinearpredict16x16_neon.asm @@ -25,7 +25,7 @@ |vp8_bilinear_predict16x16_neon| PROC push {r4-r5, lr} - ldr r12, _bifilter16_coeff_ + adr r12, bifilter16_coeff ldr r4, [sp, #12] ;load parameters from stack ldr r5, [sp, #16] ;load parameters from stack @@ -354,8 +354,6 @@ filt_blk2d_spo16x16_loop_neon ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_bifilter16_coeff_ - DCD bifilter16_coeff bifilter16_coeff DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 diff --git a/media/libvpx/vp8/common/arm/neon/bilinearpredict4x4_neon.asm b/media/libvpx/vp8/common/arm/neon/bilinearpredict4x4_neon.asm index 6d4820b7e6c9..7e961c321cee 100644 --- a/media/libvpx/vp8/common/arm/neon/bilinearpredict4x4_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/bilinearpredict4x4_neon.asm @@ -25,7 +25,7 @@ |vp8_bilinear_predict4x4_neon| PROC push {r4, lr} - ldr r12, _bifilter4_coeff_ + adr r12, bifilter4_coeff ldr r4, [sp, #8] ;load parameters from stack ldr lr, [sp, #12] ;load parameters from stack @@ -127,8 +127,6 @@ skip_secondpass_filter ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_bifilter4_coeff_ - DCD bifilter4_coeff bifilter4_coeff DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 diff --git a/media/libvpx/vp8/common/arm/neon/bilinearpredict8x4_neon.asm b/media/libvpx/vp8/common/arm/neon/bilinearpredict8x4_neon.asm index b9f3ce034af4..f57257a02c36 100644 --- a/media/libvpx/vp8/common/arm/neon/bilinearpredict8x4_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/bilinearpredict8x4_neon.asm @@ -25,7 +25,7 @@ |vp8_bilinear_predict8x4_neon| PROC push {r4, lr} - ldr r12, _bifilter8x4_coeff_ + adr r12, bifilter8x4_coeff ldr r4, [sp, #8] ;load parameters from stack ldr lr, [sp, #12] ;load parameters from stack @@ -132,8 +132,6 @@ skip_secondpass_filter ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_bifilter8x4_coeff_ - DCD bifilter8x4_coeff bifilter8x4_coeff DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 diff --git a/media/libvpx/vp8/common/arm/neon/bilinearpredict8x8_neon.asm b/media/libvpx/vp8/common/arm/neon/bilinearpredict8x8_neon.asm index f7a7d149664b..8345a53b2ae8 100644 --- a/media/libvpx/vp8/common/arm/neon/bilinearpredict8x8_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/bilinearpredict8x8_neon.asm @@ -25,7 +25,7 @@ |vp8_bilinear_predict8x8_neon| PROC push {r4, lr} - ldr r12, _bifilter8_coeff_ + adr r12, bifilter8_coeff ldr r4, [sp, #8] ;load parameters from stack ldr lr, [sp, #12] ;load parameters from stack @@ -180,8 +180,6 @@ skip_secondpass_filter ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_bifilter8_coeff_ - DCD bifilter8_coeff bifilter8_coeff DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 diff --git a/media/libvpx/vp8/common/arm/neon/loopfilter_neon.asm b/media/libvpx/vp8/common/arm/neon/loopfilter_neon.asm index bf0c35721c3d..9ef1a6aa4071 100644 --- a/media/libvpx/vp8/common/arm/neon/loopfilter_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/loopfilter_neon.asm @@ -308,7 +308,7 @@ ; q9 q2 ; q10 q3 |vp8_loop_filter_neon| PROC - ldr r12, _lf_coeff_ + adr r12, lf_coeff ; vp8_filter_mask vabd.u8 q11, q3, q4 ; abs(p3 - p2) @@ -398,8 +398,6 @@ ENDP ; |vp8_loop_filter_horizontal_edge_y_neon| AREA loopfilter_dat, DATA, READONLY -_lf_coeff_ - DCD lf_coeff lf_coeff DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 diff --git a/media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm b/media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm index 0b84dc750026..31e86ca4e87a 100644 --- a/media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm @@ -28,7 +28,7 @@ |vp8_loop_filter_simple_horizontal_edge_neon| PROC sub r0, r0, r1, lsl #1 ; move src pointer down by 2 lines - ldr r12, _lfhy_coeff_ + adr r12, lfhy_coeff vld1.u8 {q5}, [r0], r1 ; p1 vld1.s8 {d2[], d3[]}, [r2] ; flimit vld1.s8 {d26[], d27[]}, [r3] ; limit -> q13 @@ -108,8 +108,6 @@ ;Data section with name data_area is specified. DCD reserves space in memory for 16 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_lfhy_coeff_ - DCD lfhy_coeff lfhy_coeff DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 diff --git a/media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm b/media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm index a793d095a79a..558b331fad79 100644 --- a/media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm @@ -32,7 +32,7 @@ vld1.s8 {d2[], d3[]}, [r2] ; flimit vld1.s8 {d26[], d27[]}, [r3] ; limit -> q13 vld4.8 {d6[1], d7[1], d8[1], d9[1]}, [r0], r1 - ldr r12, _vlfy_coeff_ + adr r12, vlfy_coeff vld4.8 {d6[2], d7[2], d8[2], d9[2]}, [r0], r1 vld4.8 {d6[3], d7[3], d8[3], d9[3]}, [r0], r1 vld4.8 {d6[4], d7[4], d8[4], d9[4]}, [r0], r1 @@ -149,8 +149,6 @@ ;Data section with name data_area is specified. DCD reserves space in memory for 16 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_vlfy_coeff_ - DCD vlfy_coeff vlfy_coeff DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 diff --git a/media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.asm b/media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.asm index 255dd561925b..27256433cea4 100644 --- a/media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.asm @@ -372,7 +372,7 @@ ; q10 q3 |vp8_mbloop_filter_neon| PROC - ldr r12, _mblf_coeff_ + adr r12, mblf_coeff ; vp8_filter_mask vabd.u8 q11, q3, q4 ; abs(p3 - p2) @@ -506,8 +506,6 @@ ENDP ; |vp8_mbloop_filter_neon| AREA mbloopfilter_dat, DATA, READONLY -_mblf_coeff_ - DCD mblf_coeff mblf_coeff DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 diff --git a/media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.asm b/media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.asm index d77a2879e77f..cfdfc5984b72 100644 --- a/media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.asm @@ -31,7 +31,7 @@ ;result of the multiplication that is needed in IDCT. |vp8_short_idct4x4llm_neon| PROC - ldr r12, _idct_coeff_ + adr r12, idct_coeff vld1.16 {q1, q2}, [r0] vld1.16 {d0}, [r12] @@ -117,8 +117,6 @@ ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_idct_coeff_ - DCD idct_coeff idct_coeff DCD 0x4e7b4e7b, 0x8a8c8a8c diff --git a/media/libvpx/vp8/common/arm/neon/sixtappredict16x16_neon.asm b/media/libvpx/vp8/common/arm/neon/sixtappredict16x16_neon.asm index e434a709c43a..2ed9a9288a53 100644 --- a/media/libvpx/vp8/common/arm/neon/sixtappredict16x16_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/sixtappredict16x16_neon.asm @@ -33,7 +33,7 @@ |vp8_sixtap_predict16x16_neon| PROC push {r4-r5, lr} - ldr r12, _filter16_coeff_ + adrl r12, filter16_coeff ldr r4, [sp, #12] ;load parameters from stack ldr r5, [sp, #16] ;load parameters from stack @@ -480,8 +480,6 @@ secondpass_only_inner_loop_neon ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_filter16_coeff_ - DCD filter16_coeff filter16_coeff DCD 0, 0, 128, 0, 0, 0, 0, 0 DCD 0, -6, 123, 12, -1, 0, 0, 0 diff --git a/media/libvpx/vp8/common/arm/neon/sixtappredict4x4_neon.asm b/media/libvpx/vp8/common/arm/neon/sixtappredict4x4_neon.asm index 3d22d775aa29..f661452f9d3e 100644 --- a/media/libvpx/vp8/common/arm/neon/sixtappredict4x4_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/sixtappredict4x4_neon.asm @@ -25,7 +25,7 @@ |vp8_sixtap_predict_neon| PROC push {r4, lr} - ldr r12, _filter4_coeff_ + adrl r12, filter4_coeff ldr r4, [sp, #8] ;load parameters from stack ldr lr, [sp, #12] ;load parameters from stack @@ -411,8 +411,6 @@ secondpass_filter4x4_only ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_filter4_coeff_ - DCD filter4_coeff filter4_coeff DCD 0, 0, 128, 0, 0, 0, 0, 0 DCD 0, -6, 123, 12, -1, 0, 0, 0 diff --git a/media/libvpx/vp8/common/arm/neon/sixtappredict8x4_neon.asm b/media/libvpx/vp8/common/arm/neon/sixtappredict8x4_neon.asm index 1dd6b1b37097..b2c61e14da30 100644 --- a/media/libvpx/vp8/common/arm/neon/sixtappredict8x4_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/sixtappredict8x4_neon.asm @@ -25,7 +25,7 @@ |vp8_sixtap_predict8x4_neon| PROC push {r4-r5, lr} - ldr r12, _filter8_coeff_ + adrl r12, filter8_coeff ldr r4, [sp, #12] ;load parameters from stack ldr r5, [sp, #16] ;load parameters from stack @@ -462,8 +462,6 @@ secondpass_filter8x4_only ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_filter8_coeff_ - DCD filter8_coeff filter8_coeff DCD 0, 0, 128, 0, 0, 0, 0, 0 DCD 0, -6, 123, 12, -1, 0, 0, 0 diff --git a/media/libvpx/vp8/common/arm/neon/sixtappredict8x8_neon.asm b/media/libvpx/vp8/common/arm/neon/sixtappredict8x8_neon.asm index 37255c758f67..d4798ed5a604 100644 --- a/media/libvpx/vp8/common/arm/neon/sixtappredict8x8_neon.asm +++ b/media/libvpx/vp8/common/arm/neon/sixtappredict8x8_neon.asm @@ -25,7 +25,7 @@ |vp8_sixtap_predict8x8_neon| PROC push {r4-r5, lr} - ldr r12, _filter8_coeff_ + adrl r12, filter8_coeff ldr r4, [sp, #12] ;load parameters from stack ldr r5, [sp, #16] ;load parameters from stack @@ -513,8 +513,6 @@ filt_blk2d_spo8x8_loop_neon ;Data section with name data_area is specified. DCD reserves space in memory for 48 data. ;One word each is reserved. Label filter_coeff can be used to access the data. ;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... -_filter8_coeff_ - DCD filter8_coeff filter8_coeff DCD 0, 0, 128, 0, 0, 0, 0, 0 DCD 0, -6, 123, 12, -1, 0, 0, 0 diff --git a/media/libvpx/vp8/decoder/arm/neon/dequant_idct_neon.asm b/media/libvpx/vp8/decoder/arm/neon/dequant_idct_neon.asm index 1923be42a564..e8453b5b91a0 100644 --- a/media/libvpx/vp8/decoder/arm/neon/dequant_idct_neon.asm +++ b/media/libvpx/vp8/decoder/arm/neon/dequant_idct_neon.asm @@ -35,7 +35,7 @@ ldr r1, [sp, #4] ; stride - ldr r12, _CONSTANTS_ + adr r12, _CONSTANTS_ vmul.i16 q1, q3, q5 ;input for short_idct4x4llm_neon vmul.i16 q2, q4, q6 @@ -123,7 +123,7 @@ ENDP ; |vp8_dequant_idct_add_neon| ; Constant Pool -_CONSTANTS_ DCD cospi8sqrt2minus1 +_CONSTANTS_ EQU cospi8sqrt2minus1 cospi8sqrt2minus1 DCD 0x4e7b4e7b sinpi8sqrt2 DCD 0x8a8c8a8c diff --git a/media/libvpx/vp8/decoder/arm/neon/idct_dequant_dc_full_2x_neon.asm b/media/libvpx/vp8/decoder/arm/neon/idct_dequant_dc_full_2x_neon.asm index ad4364adc4eb..afd2c7f1ab6e 100644 --- a/media/libvpx/vp8/decoder/arm/neon/idct_dequant_dc_full_2x_neon.asm +++ b/media/libvpx/vp8/decoder/arm/neon/idct_dequant_dc_full_2x_neon.asm @@ -41,7 +41,7 @@ ldr r1, [sp, #4] vld1.32 {d31[1]}, [r12] - ldr r2, _CONSTANTS_ + adr r2, _CONSTANTS_ ldrh r12, [r1], #2 ; lo *dc ldrh r1, [r1] ; hi *dc @@ -198,7 +198,7 @@ ENDP ; |idct_dequant_dc_full_2x_neon| ; Constant Pool -_CONSTANTS_ DCD cospi8sqrt2minus1 +_CONSTANTS_ EQU cospi8sqrt2minus1 cospi8sqrt2minus1 DCD 0x4e7b ; because the lowest bit in 0x8a8c is 0, we can pre-shift this sinpi8sqrt2 DCD 0x4546 diff --git a/media/libvpx/vp8/decoder/arm/neon/idct_dequant_full_2x_neon.asm b/media/libvpx/vp8/decoder/arm/neon/idct_dequant_full_2x_neon.asm index 85fff11b3b17..e0b9219a565e 100644 --- a/media/libvpx/vp8/decoder/arm/neon/idct_dequant_full_2x_neon.asm +++ b/media/libvpx/vp8/decoder/arm/neon/idct_dequant_full_2x_neon.asm @@ -40,7 +40,7 @@ vld1.32 {d31[0]}, [r2] vld1.32 {d31[1]}, [r12] - ldr r2, _CONSTANTS_ + adr r2, _CONSTANTS_ ; dequant: q[i] = q[i] * dq[i] vmul.i16 q2, q2, q0 @@ -190,7 +190,7 @@ ENDP ; |idct_dequant_full_2x_neon| ; Constant Pool -_CONSTANTS_ DCD cospi8sqrt2minus1 +_CONSTANTS_ EQU cospi8sqrt2minus1 cospi8sqrt2minus1 DCD 0x4e7b ; because the lowest bit in 0x8a8c is 0, we can pre-shift this sinpi8sqrt2 DCD 0x4546 diff --git a/modules/libreg/Makefile.in b/modules/libreg/Makefile.in index 1fc7c20a57ac..6bda65d5324b 100644 --- a/modules/libreg/Makefile.in +++ b/modules/libreg/Makefile.in @@ -44,7 +44,7 @@ include $(DEPTH)/config/autoconf.mk MODULE = libreg -DIRS = include src standalone +DIRS = include src include $(topsrcdir)/config/rules.mk diff --git a/modules/libreg/standalone/Makefile.in b/modules/libreg/standalone/Makefile.in deleted file mode 100644 index d58010eb4e19..000000000000 --- a/modules/libreg/standalone/Makefile.in +++ /dev/null @@ -1,74 +0,0 @@ -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Samir Gehani -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** - -DEPTH = ../../.. -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk -include $(srcdir)/../src/objs.mk - -MODULE = libreg -LIBRARY_NAME = mozregsa_s - -ifeq ($(OS_ARCH),WINNT) -USE_STATIC_LIBS = 1 -endif - -CSRCS = $(MODULES_LIBREG_SRC_LCSRCS) - -FORCE_STATIC_LIB = 1 - -GARBAGE += $(MODULES_LIBREG_SRC_LCSRCS) $(wildcard *.$(OBJ_SUFFIX)) - -ifeq ($(OS_ARCH),WINNT) -GARBAGE += $(addprefix $(srcdir)/,$(MODULES_LIBREG_SRC_LCSRCS)) -endif - -SRCS_IN_OBJDIR = 1 - -include $(topsrcdir)/config/rules.mk - -DEFINES += -DSTANDALONE_REGISTRY - -LOCAL_INCLUDES = -I$(srcdir)/../src - -export:: $(MODULES_LIBREG_SRC_CSRCS) - $(INSTALL) $^ . - diff --git a/services/sync/SyncComponents.manifest b/services/sync/SyncComponents.manifest index 0d75db3fbb97..e6f9975853e8 100644 --- a/services/sync/SyncComponents.manifest +++ b/services/sync/SyncComponents.manifest @@ -4,8 +4,6 @@ contract @mozilla.org/weave/service;1 {74b89fb0-f200-4ae8-a3ec-dd164117f6de} category app-startup WeaveService service,@mozilla.org/weave/service;1 component {d28f8a0b-95da-48f4-b712-caf37097be41} Weave.js contract @mozilla.org/network/protocol/about;1?what=sync-log {d28f8a0b-95da-48f4-b712-caf37097be41} -component {a08ee179-df50-48e0-9c87-79e4dd5caeb1} Weave.js -contract @mozilla.org/network/protocol/about;1?what=sync-log.1 {a08ee179-df50-48e0-9c87-79e4dd5caeb1} # Register resource aliases resource services-sync resource:///modules/services-sync/ resource services-crypto resource:///modules/services-crypto/ diff --git a/services/sync/Weave.js b/services/sync/Weave.js index 42382a90d133..66f71cdaf2c4 100644 --- a/services/sync/Weave.js +++ b/services/sync/Weave.js @@ -19,6 +19,7 @@ * * Contributor(s): * Dan Mills + * Philipp von Weitershausen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -39,6 +40,8 @@ const Ci = Components.interfaces; const Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/FileUtils.jsm"); function WeaveService() { this.wrappedJSObject = this; @@ -84,53 +87,20 @@ AboutWeaveLog.prototype = { }, newChannel: function(aURI) { - let dir = Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties); - let file = dir.get("ProfD", Ci.nsILocalFile); - file.append("weave"); - file.append("logs"); - file.append("verbose-log.txt"); - let ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - let ch = ios.newChannel(ios.newFileURI(file).spec, null, null); - ch.originalURI = aURI; - return ch; + let dir = FileUtils.getDir("ProfD", ["weave", "logs"], true); + let uri = Services.io.newFileURI(dir); + let channel = Services.io.newChannelFromURI(uri); + channel.originalURI = aURI; + + // Ensure that the about page has the same privileges as a regular directory + // view. That way links to files can be opened. + let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] + .getService(Ci.nsIScriptSecurityManager); + let principal = ssm.getCodebasePrincipal(uri); + channel.owner = principal; + return channel; } }; -function AboutWeaveLog1() {} -AboutWeaveLog1.prototype = { - classID: Components.ID("{a08ee179-df50-48e0-9c87-79e4dd5caeb1}"), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule, - Ci.nsISupportsWeakReference]), - - getURIFlags: function(aURI) { - return 0; - }, - - newChannel: function(aURI) { - let dir = Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties); - let file = dir.get("ProfD", Ci.nsILocalFile); - file.append("weave"); - file.append("logs"); - file.append("verbose-log.txt.1"); - let ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - let ch = ios.newChannel(ios.newFileURI(file).spec, null, null); - ch.originalURI = aURI; - return ch; - } -}; - -let components = [WeaveService, AboutWeaveLog, AboutWeaveLog1]; - -// Gecko <2.0 -function NSGetModule(compMgr, fileSpec) { - return XPCOMUtils.generateModule(components); -} - -// Gecko >=2.0 -if (typeof XPCOMUtils.generateNSGetFactory == "function") - const NSGetFactory = XPCOMUtils.generateNSGetFactory(components); +const components = [WeaveService, AboutWeaveLog]; +const NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/services/sync/modules/async.js b/services/sync/modules/async.js index 156468ba1a8b..5a023a741388 100644 --- a/services/sync/modules/async.js +++ b/services/sync/modules/async.js @@ -255,7 +255,7 @@ let Async = { output(err); return; } - Utils.delay(function () { f(items[i], cb); }); + Utils.nextTick(function () { f(items[i], cb); }); } f(items[i], cb); }, diff --git a/services/sync/modules/engines.js b/services/sync/modules/engines.js index 1a3eb99d080b..c366d0fee753 100644 --- a/services/sync/modules/engines.js +++ b/services/sync/modules/engines.js @@ -72,7 +72,7 @@ function Tracker(name) { name = name || "Unnamed"; this.name = this.file = name.toLowerCase(); - this._log = Log4Moz.repository.getLogger("Tracker." + name); + this._log = Log4Moz.repository.getLogger("Sync.Tracker." + name); let level = Svc.Prefs.get("log.logger.engine." + this.name, "Debug"); this._log.level = Log4Moz.Level[level]; @@ -108,7 +108,7 @@ Tracker.prototype = { }, saveChangedIDs: function T_saveChangedIDs() { - Utils.delay(function() { + Utils.namedTimer(function() { Utils.jsonSave("changes/" + this.file, this, this.changedIDs); }, 1000, this, "_lazySave"); }, @@ -190,7 +190,7 @@ function Store(name) { name = name || "Unnamed"; this.name = name.toLowerCase(); - this._log = Log4Moz.repository.getLogger("Store." + name); + this._log = Log4Moz.repository.getLogger("Sync.Store." + name); let level = Svc.Prefs.get("log.logger.engine." + this.name, "Debug"); this._log.level = Log4Moz.Level[level]; @@ -202,8 +202,7 @@ Store.prototype = { _sleep: function _sleep(delay) { let cb = Async.makeSyncCallback(); - this._timer.initWithCallback({notify: cb}, delay, - Ci.nsITimer.TYPE_ONE_SHOT); + this._timer.initWithCallback(cb, delay, Ci.nsITimer.TYPE_ONE_SHOT); Async.waitForSyncCallback(cb); }, @@ -274,7 +273,7 @@ XPCOMUtils.defineLazyGetter(this, "Engines", function() { function EngineManagerSvc() { this._engines = {}; - this._log = Log4Moz.repository.getLogger("Service.Engines"); + this._log = Log4Moz.repository.getLogger("Sync.EngineManager"); this._log.level = Log4Moz.Level[Svc.Prefs.get( "log.logger.service.engines", "Debug")]; } @@ -351,7 +350,7 @@ function Engine(name) { this.name = name.toLowerCase(); this._notify = Utils.notify("weave:engine:"); - this._log = Log4Moz.repository.getLogger("Engine." + this.Name); + this._log = Log4Moz.repository.getLogger("Sync.Engine." + this.Name); let level = Svc.Prefs.get("log.logger.engine." + this.name, "Debug"); this._log.level = Log4Moz.Level[level]; @@ -490,7 +489,7 @@ SyncEngine.prototype = { return; } this._toFetch = val; - Utils.delay(function () { + Utils.namedTimer(function () { Utils.jsonSave("toFetch/" + this.name, this, val); }, 0, this, "_toFetchDelay"); }, @@ -512,7 +511,7 @@ SyncEngine.prototype = { return; } this._previousFailed = val; - Utils.delay(function () { + Utils.namedTimer(function () { Utils.jsonSave("failed/" + this.name, this, val); }, 0, this, "_previousFailedDelay"); }, diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index e0f44a081423..ae07f1f19196 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -109,7 +109,7 @@ PlacesItem.prototype = { }, __proto__: CryptoWrapper.prototype, - _logName: "Record.PlacesItem", + _logName: "Sync.Record.PlacesItem", }; Utils.deferGetSet(PlacesItem, "cleartext", ["hasDupe", "parentid", "parentName", @@ -120,7 +120,7 @@ function Bookmark(collection, id, type) { } Bookmark.prototype = { __proto__: PlacesItem.prototype, - _logName: "Record.Bookmark", + _logName: "Sync.Record.Bookmark", }; Utils.deferGetSet(Bookmark, "cleartext", ["title", "bmkUri", "description", @@ -131,7 +131,7 @@ function BookmarkQuery(collection, id) { } BookmarkQuery.prototype = { __proto__: Bookmark.prototype, - _logName: "Record.BookmarkQuery", + _logName: "Sync.Record.BookmarkQuery", }; Utils.deferGetSet(BookmarkQuery, "cleartext", ["folderName", @@ -142,7 +142,7 @@ function BookmarkFolder(collection, id, type) { } BookmarkFolder.prototype = { __proto__: PlacesItem.prototype, - _logName: "Record.Folder", + _logName: "Sync.Record.Folder", }; Utils.deferGetSet(BookmarkFolder, "cleartext", ["description", "title", @@ -153,7 +153,7 @@ function Livemark(collection, id) { } Livemark.prototype = { __proto__: BookmarkFolder.prototype, - _logName: "Record.Livemark", + _logName: "Sync.Record.Livemark", }; Utils.deferGetSet(Livemark, "cleartext", ["siteUri", "feedUri"]); @@ -163,7 +163,7 @@ function BookmarkSeparator(collection, id) { } BookmarkSeparator.prototype = { __proto__: PlacesItem.prototype, - _logName: "Record.Separator", + _logName: "Sync.Record.Separator", }; Utils.deferGetSet(BookmarkSeparator, "cleartext", "pos"); diff --git a/services/sync/modules/engines/clients.js b/services/sync/modules/engines/clients.js index e6a620603790..c897f9da3f00 100644 --- a/services/sync/modules/engines/clients.js +++ b/services/sync/modules/engines/clients.js @@ -56,7 +56,7 @@ function ClientsRec(collection, id) { } ClientsRec.prototype = { __proto__: CryptoWrapper.prototype, - _logName: "Record.Clients", + _logName: "Sync.Record.Clients", ttl: CLIENTS_TTL }; diff --git a/services/sync/modules/engines/forms.js b/services/sync/modules/engines/forms.js index d72d86618b1d..38a211f8817b 100644 --- a/services/sync/modules/engines/forms.js +++ b/services/sync/modules/engines/forms.js @@ -55,7 +55,7 @@ function FormRec(collection, id) { } FormRec.prototype = { __proto__: CryptoWrapper.prototype, - _logName: "Record.Form", + _logName: "Sync.Record.Form", ttl: FORMS_TTL }; @@ -63,7 +63,7 @@ Utils.deferGetSet(FormRec, "cleartext", ["name", "value"]); let FormWrapper = { - _log: Log4Moz.repository.getLogger('Engine.Forms'), + _log: Log4Moz.repository.getLogger("Sync.Engine.Forms"), getAllEntries: function getAllEntries() { // Sort by (lastUsed - minLast) / (maxLast - minLast) * timesUsed / maxTimes @@ -343,10 +343,10 @@ FormTracker.prototype = { } // Get the GUID on a delay so that it can be added to the DB first... - Utils.delay(function() { + Utils.nextTick(function() { this._log.trace("Logging form element: " + [name, el.value]); this.trackEntry(name, el.value); - }, 0, this); + }, this); } } }; diff --git a/services/sync/modules/engines/history.js b/services/sync/modules/engines/history.js index 8c1c916593ff..67eb91156f8e 100644 --- a/services/sync/modules/engines/history.js +++ b/services/sync/modules/engines/history.js @@ -60,7 +60,7 @@ function HistoryRec(collection, id) { } HistoryRec.prototype = { __proto__: CryptoWrapper.prototype, - _logName: "Record.History", + _logName: "Sync.Record.History", ttl: HISTORY_TTL }; diff --git a/services/sync/modules/engines/passwords.js b/services/sync/modules/engines/passwords.js index 8609250ab23c..7b254b4b950d 100644 --- a/services/sync/modules/engines/passwords.js +++ b/services/sync/modules/engines/passwords.js @@ -54,7 +54,7 @@ function LoginRec(collection, id) { } LoginRec.prototype = { __proto__: CryptoWrapper.prototype, - _logName: "Record.Login", + _logName: "Sync.Record.Login", }; Utils.deferGetSet(LoginRec, "cleartext", ["hostname", "formSubmitURL", diff --git a/services/sync/modules/engines/prefs.js b/services/sync/modules/engines/prefs.js index 3ddeea83d584..88e1ef42e78c 100644 --- a/services/sync/modules/engines/prefs.js +++ b/services/sync/modules/engines/prefs.js @@ -56,7 +56,7 @@ function PrefRec(collection, id) { } PrefRec.prototype = { __proto__: CryptoWrapper.prototype, - _logName: "Record.Pref", + _logName: "Sync.Record.Pref", }; Utils.deferGetSet(PrefRec, "cleartext", ["value"]); diff --git a/services/sync/modules/engines/tabs.js b/services/sync/modules/engines/tabs.js index b6a8774612f3..a2efe0a739ac 100644 --- a/services/sync/modules/engines/tabs.js +++ b/services/sync/modules/engines/tabs.js @@ -65,7 +65,7 @@ function TabSetRecord(collection, id) { } TabSetRecord.prototype = { __proto__: CryptoWrapper.prototype, - _logName: "Record.Tabs", + _logName: "Sync.Record.Tabs", ttl: TABS_TTL }; diff --git a/services/sync/modules/identity.js b/services/sync/modules/identity.js index 2c662a0b113d..042777ebcdd1 100644 --- a/services/sync/modules/identity.js +++ b/services/sync/modules/identity.js @@ -124,7 +124,7 @@ Identity.prototype = { } // No need to create the login after clearing out the other ones - let log = Log4Moz.repository.getLogger("Identity"); + let log = Log4Moz.repository.getLogger("Sync.Identity"); if (exists) { log.trace("Skipping persist: " + this.realm + " for " + this.username); return; diff --git a/services/sync/modules/jpakeclient.js b/services/sync/modules/jpakeclient.js index 28b8a1d2ac0a..178107a2c56c 100644 --- a/services/sync/modules/jpakeclient.js +++ b/services/sync/modules/jpakeclient.js @@ -124,7 +124,7 @@ const JPAKE_VERIFY_VALUE = "0123456789ABCDEF"; function JPAKEClient(observer) { this.observer = observer; - this._log = Log4Moz.repository.getLogger("Service.JPAKEClient"); + this._log = Log4Moz.repository.getLogger("Sync.JPAKEClient"); this._log.level = Log4Moz.Level[Svc.Prefs.get( "log.logger.service.jpakeclient", "Debug")]; @@ -211,8 +211,8 @@ JPAKEClient.prototype = { if (error == JPAKE_ERROR_CHANNEL || error == JPAKE_ERROR_NETWORK || error == JPAKE_ERROR_NODATA) { - Utils.delay(function() { this.observer.onAbort(error); }, 0, - this, "_timer_onAbort"); + Utils.namedTimer(function() { this.observer.onAbort(error); }, 0, + this, "_timer_onAbort"); } else { this._reportFailure(error, function() { self.observer.onAbort(error); }); } @@ -278,8 +278,8 @@ JPAKEClient.prototype = { // Don't block on UI code. let pin = this._secret + this._channel; - Utils.delay(function() { this.observer.displayPIN(pin); }, 0, - this, "_timer_displayPIN"); + Utils.namedTimer(function() { this.observer.displayPIN(pin); }, 0, + this, "_timer_displayPIN"); callback(); })); }, @@ -308,8 +308,8 @@ JPAKEClient.prototype = { // There's no point in returning early here since the next step will // always be a GET so let's pause for twice the poll interval. this._etag = response.headers["etag"]; - Utils.delay(function () { callback(); }, this._pollInterval * 2, this, - "_pollTimer"); + Utils.namedTimer(function () { callback(); }, this._pollInterval * 2, + this, "_pollTimer"); })); }, @@ -341,8 +341,8 @@ JPAKEClient.prototype = { return; } this._pollTries += 1; - Utils.delay(function() { this._getStep(callback); }, - this._pollInterval, this, "_pollTimer"); + Utils.namedTimer(function() { this._getStep(callback); }, + this._pollInterval, this, "_pollTimer"); return; } this._pollTries = 0; @@ -587,8 +587,8 @@ JPAKEClient.prototype = { _complete: function _complete() { this._log.debug("Exchange completed."); this._finished = true; - Utils.delay(function () { this.observer.onComplete(this._newData); }, - 0, this, "_timer_onComplete"); + Utils.namedTimer(function () { this.observer.onComplete(this._newData); }, + 0, this, "_timer_onComplete"); } }; diff --git a/services/sync/modules/log4moz.js b/services/sync/modules/log4moz.js index 7c1d421a181f..6217d0d8600b 100644 --- a/services/sync/modules/log4moz.js +++ b/services/sync/modules/log4moz.js @@ -11,16 +11,17 @@ * for the specific language governing rights and limitations under the * License. * - * The Original Code is log4moz + * The Original Code is log4moz. * * The Initial Developer of the Original Code is - * Michael Johnston + * the Mozilla Foundation. * Portions created by the Initial Developer are Copyright (C) 2006 * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Michael Johnston - * Dan Mills + * Michael Johnston (Original Author) + * Dan Mills + * Philipp von Weitershausen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -56,6 +57,12 @@ const ONE_BYTE = 1; const ONE_KILOBYTE = 1024 * ONE_BYTE; const ONE_MEGABYTE = 1024 * ONE_KILOBYTE; +const STREAM_SEGMENT_SIZE = 4096; +const PR_UINT32_MAX = 0xffffffff; + +Cu.import("resource://gre/modules/NetUtil.jsm"); +Cu.import("resource://gre/modules/FileUtils.jsm"); + let Log4Moz = { Level: { Fatal: 70, @@ -88,18 +95,22 @@ let Log4Moz = { Log4Moz.repository = value; }, - get LogMessage() { return LogMessage; }, - get Logger() { return Logger; }, - get LoggerRepository() { return LoggerRepository; }, + LogMessage: LogMessage, + Logger: Logger, + LoggerRepository: LoggerRepository, - get Formatter() { return Formatter; }, - get BasicFormatter() { return BasicFormatter; }, + Formatter: Formatter, + BasicFormatter: BasicFormatter, - get Appender() { return Appender; }, - get DumpAppender() { return DumpAppender; }, - get ConsoleAppender() { return ConsoleAppender; }, - get FileAppender() { return FileAppender; }, - get RotatingFileAppender() { return RotatingFileAppender; }, + Appender: Appender, + DumpAppender: DumpAppender, + ConsoleAppender: ConsoleAppender, + BlockingStreamAppender: BlockingStreamAppender, + StorageStreamAppender: StorageStreamAppender, + + // Discouraged due to blocking I/O. + FileAppender: FileAppender, + RotatingFileAppender: RotatingFileAppender, // Logging helper: // let logger = Log4Moz.repository.getLogger("foo"); @@ -406,7 +417,7 @@ Appender.prototype = { function DumpAppender(formatter) { this._name = "DumpAppender"; - this._formatter = formatter? formatter : new BasicFormatter(); + Appender.call(this, formatter); } DumpAppender.prototype = { __proto__: Appender.prototype, @@ -423,7 +434,7 @@ DumpAppender.prototype = { function ConsoleAppender(formatter) { this._name = "ConsoleAppender"; - this._formatter = formatter; + Appender.call(this, formatter); } ConsoleAppender.prototype = { __proto__: Appender.prototype, @@ -438,77 +449,159 @@ ConsoleAppender.prototype = { } }; -/* - * FileAppender - * Logs to a file +/** + * Base implementation for stream based appenders. + * + * Caution: This writes to the output stream synchronously, thus logging calls + * block as the data is written to the stream. This can have negligible impact + * for in-memory streams, but should be taken into account for I/O streams + * (files, network, etc.) */ - -function FileAppender(file, formatter) { - this._name = "FileAppender"; - this._file = file; // nsIFile - this._formatter = formatter? formatter : new BasicFormatter(); +function BlockingStreamAppender(formatter) { + this._name = "BlockingStreamAppender"; + Appender.call(this, formatter); } -FileAppender.prototype = { +BlockingStreamAppender.prototype = { __proto__: Appender.prototype, - __fos: null, - get _fos() { - if (!this.__fos) - this.openStream(); - return this.__fos; - }, - openStream: function FApp_openStream() { - try { - let __fos = Cc["@mozilla.org/network/file-output-stream;1"]. - createInstance(Ci.nsIFileOutputStream); - let flags = MODE_WRONLY | MODE_CREATE | MODE_APPEND; - __fos.init(this._file, flags, PERMS_FILE, 0); + _converterStream: null, // holds the nsIConverterOutputStream + _outputStream: null, // holds the underlying nsIOutputStream - this.__fos = Cc["@mozilla.org/intl/converter-output-stream;1"] - .createInstance(Ci.nsIConverterOutputStream); - this.__fos.init(__fos, "UTF-8", 4096, - Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); - } catch(e) { - dump("Error opening stream:\n" + e); + /** + * Output stream to write to. + * + * This will automatically open the stream if it doesn't exist yet by + * calling newOutputStream. The resulting raw stream is wrapped in a + * nsIConverterOutputStream to ensure text is written as UTF-8. + */ + get outputStream() { + if (!this._outputStream) { + // First create a raw stream. We can bail out early if that fails. + this._outputStream = this.newOutputStream(); + if (!this._outputStream) { + return null; + } + + // Wrap the raw stream in an nsIConverterOutputStream. We can reuse + // the instance if we already have one. + if (!this._converterStream) { + this._converterStream = Cc["@mozilla.org/intl/converter-output-stream;1"] + .createInstance(Ci.nsIConverterOutputStream); + } + this._converterStream.init( + this._outputStream, "UTF-8", STREAM_SEGMENT_SIZE, + Ci.nsIConverterOutputStream.DEFAULT_REPLACEMENT_CHARACTER); } + return this._converterStream; }, - closeStream: function FApp_closeStream() { - if (!this.__fos) + newOutputStream: function newOutputStream() { + throw "Stream-based appenders need to implement newOutputStream()!"; + }, + + reset: function reset() { + if (!this._outputStream) { return; - try { - this.__fos.close(); - this.__fos = null; - } catch(e) { - dump("Failed to close file output stream\n" + e); } + this.outputStream.close(); + this._outputStream = null; }, - doAppend: function FApp_doAppend(message) { - if (message === null || message.length <= 0) + doAppend: function doAppend(message) { + if (!message) { return; - try { - this._fos.writeString(message); - } catch(e) { - dump("Error writing file:\n" + e); } - }, - - clear: function FApp_clear() { - this.closeStream(); try { - this._file.remove(false); - } catch (e) { - // XXX do something? + this.outputStream.writeString(message); + } catch(ex) { + if (ex.result == Cr.NS_BASE_STREAM_CLOSED) { + // The underlying output stream is closed, so let's open a new one + // and try again. + this._outputStream = null; + try { + this.outputStream.writeString(message); + } catch (ex) { + // Ah well, we tried, but something seems to be hosed permanently. + } + } } } }; -/* - * RotatingFileAppender - * Similar to FileAppender, but rotates logs when they become too large +/** + * Append to an nsIStorageStream + * + * This writes logging output to an in-memory stream which can later be read + * back as an nsIInputStream. It can be used to avoid expensive I/O operations + * during logging. Instead, one can periodically consume the input stream and + * e.g. write it to disk asynchronously. */ +function StorageStreamAppender(formatter) { + this._name = "StorageStreamAppender"; + BlockingStreamAppender.call(this, formatter); +} +StorageStreamAppender.prototype = { + __proto__: BlockingStreamAppender.prototype, + _ss: null, + newOutputStream: function newOutputStream() { + let ss = this._ss = Cc["@mozilla.org/storagestream;1"] + .createInstance(Ci.nsIStorageStream); + ss.init(STREAM_SEGMENT_SIZE, PR_UINT32_MAX, null); + return ss.getOutputStream(0); + }, + + getInputStream: function getInputStream() { + if (!this._ss) { + return null; + } + return this._ss.newInputStream(0); + }, + + reset: function reset() { + BlockingStreamAppender.prototype.reset.call(this); + this._ss = null; + } +}; + +/** + * File appender (discouraged) + * + * Writes otuput to a file using a regular nsIFileOutputStream (as opposed + * to nsISafeFileOutputStream, since immediate durability is typically not + * needed for logs.) Note that I/O operations block the logging caller. + */ +function FileAppender(file, formatter) { + this._name = "FileAppender"; + this._file = file; // nsIFile + BlockingStreamAppender.call(this, formatter); +} +FileAppender.prototype = { + __proto__: BlockingStreamAppender.prototype, + + newOutputStream: function newOutputStream() { + try { + return FileUtils.openFileOutputStream(this._file); + } catch(e) { + return null; + } + }, + + reset: function reset() { + BlockingStreamAppender.prototype.reset.call(this); + try { + this._file.remove(false); + } catch (e) { + // File didn't exist in the first place, or we're on Windows. Meh. + } + } +}; + +/** + * Rotating file appender (discouraged) + * + * Similar to FileAppender, but rotates logs when they become too large. + */ function RotatingFileAppender(file, formatter, maxSize, maxBackups) { if (maxSize === undefined) maxSize = ONE_MEGABYTE * 2; @@ -517,42 +610,41 @@ function RotatingFileAppender(file, formatter, maxSize, maxBackups) { maxBackups = 0; this._name = "RotatingFileAppender"; - this._file = file; // nsIFile - this._formatter = formatter? formatter : new BasicFormatter(); + FileAppender.call(this, file, formatter); this._maxSize = maxSize; this._maxBackups = maxBackups; } RotatingFileAppender.prototype = { __proto__: FileAppender.prototype, - doAppend: function RFApp_doAppend(message) { - if (message === null || message.length <= 0) - return; + doAppend: function doAppend(message) { + FileAppender.prototype.doAppend.call(this, message); try { this.rotateLogs(); - FileAppender.prototype.doAppend.call(this, message); } catch(e) { dump("Error writing file:" + e + "\n"); } }, - rotateLogs: function RFApp_rotateLogs() { - if(this._file.exists() && - this._file.fileSize < this._maxSize) + rotateLogs: function rotateLogs() { + if (this._file.exists() && this._file.fileSize < this._maxSize) { return; + } - this.closeStream(); + BlockingStreamAppender.prototype.reset.call(this); - for (let i = this.maxBackups - 1; i > 0; i--){ + for (let i = this.maxBackups - 1; i > 0; i--) { let backup = this._file.parent.clone(); backup.append(this._file.leafName + "." + i); - if (backup.exists()) + if (backup.exists()) { backup.moveTo(this._file.parent, this._file.leafName + "." + (i + 1)); + } } let cur = this._file.clone(); - if (cur.exists()) + if (cur.exists()) { cur.moveTo(cur.parent, cur.leafName + ".1"); + } // Note: this._file still points to the same file } diff --git a/services/sync/modules/notifications.js b/services/sync/modules/notifications.js index e8e596ee42d4..e28fcd84fe35 100644 --- a/services/sync/modules/notifications.js +++ b/services/sync/modules/notifications.js @@ -145,7 +145,7 @@ function NotificationButton(label, accessKey, callback) { try { callback.apply(this, arguments); } catch (e) { - let logger = Log4Moz.repository.getLogger("Notifications"); + let logger = Log4Moz.repository.getLogger("Sync.Notifications"); logger.error("An exception occurred: " + Utils.exceptionStr(e)); logger.info(Utils.stackTrace(e)); throw e; diff --git a/services/sync/modules/record.js b/services/sync/modules/record.js index 12fc93ca5b23..906eb8801d25 100644 --- a/services/sync/modules/record.js +++ b/services/sync/modules/record.js @@ -62,7 +62,7 @@ function WBORecord(collection, id) { this.id = id; // Optional. } WBORecord.prototype = { - _logName: "Record.WBO", + _logName: "Sync.Record.WBO", get sortindex() { if (this.data.sortindex) @@ -133,7 +133,7 @@ function RecordManager() { } RecordManager.prototype = { _recordType: WBORecord, - _logName: "RecordMgr", + _logName: "Sync.RecordManager", import: function RecordMgr_import(url) { this._log.trace("Importing record: " + (url.spec ? url.spec : url)); @@ -192,7 +192,7 @@ function CryptoWrapper(collection, id) { } CryptoWrapper.prototype = { __proto__: WBORecord.prototype, - _logName: "Record.CryptoWrapper", + _logName: "Sync.Record.CryptoWrapper", ciphertextHMAC: function ciphertextHMAC(keyBundle) { let hasher = keyBundle.sha256HMACHasher; @@ -298,7 +298,7 @@ function CollectionKeyManager() { this._collections = {}; this._default = null; - this._log = Log4Moz.repository.getLogger("CollectionKeys"); + this._log = Log4Moz.repository.getLogger("Sync.CollectionKeys"); } // TODO: persist this locally as an Identity. Bug 610913. @@ -596,7 +596,7 @@ KeyBundle.prototype = { }; function BulkKeyBundle(realm, collectionName) { - let log = Log4Moz.repository.getLogger("BulkKeyBundle"); + let log = Log4Moz.repository.getLogger("Sync.BulkKeyBundle"); log.info("BulkKeyBundle being created for " + collectionName); KeyBundle.call(this, realm, collectionName); } @@ -635,7 +635,7 @@ BulkKeyBundle.prototype = { }; function SyncKeyBundle(realm, collectionName, syncKey) { - let log = Log4Moz.repository.getLogger("SyncKeyBundle"); + let log = Log4Moz.repository.getLogger("Sync.SyncKeyBundle"); log.info("SyncKeyBundle being created for " + collectionName); KeyBundle.call(this, realm, collectionName, syncKey); if (syncKey) @@ -731,7 +731,7 @@ function Collection(uri, recordObj) { } Collection.prototype = { __proto__: Resource.prototype, - _logName: "Collection", + _logName: "Sync.Collection", _rebuildURL: function Coll__rebuildURL() { // XXX should consider what happens if it's not a URL... diff --git a/services/sync/modules/resource.js b/services/sync/modules/resource.js index 0917bf5d19a3..ae3f9d3b93ed 100644 --- a/services/sync/modules/resource.js +++ b/services/sync/modules/resource.js @@ -143,7 +143,7 @@ function AsyncResource(uri) { this._onComplete = Utils.bind2(this, this._onComplete); } AsyncResource.prototype = { - _logName: "Net.Resource", + _logName: "Sync.AsyncResource", // ** {{{ AsyncResource.serverTime }}} ** // @@ -447,6 +447,8 @@ Resource.prototype = { __proto__: AsyncResource.prototype, + _logName: "Sync.Resource", + // ** {{{ Resource._request }}} ** // // Perform a particular HTTP request on the resource. This method @@ -599,7 +601,7 @@ ChannelListener.prototype = { * Create or push back the abort timer that kills this request */ delayAbort: function delayAbort() { - Utils.delay(this.abortRequest, this._timeout, this, "abortTimer"); + Utils.namedTimer(this.abortRequest, this._timeout, this, "abortTimer"); }, abortRequest: function abortRequest() { @@ -636,7 +638,7 @@ BadCertListener.prototype = { notifyCertProblem: function certProblem(socketInfo, sslStatus, targetHost) { // Silently ignore? - let log = Log4Moz.repository.getLogger("Service.CertListener"); + let log = Log4Moz.repository.getLogger("Sync.CertListener"); log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.network.resources")]; log.debug("Invalid HTTPS certificate encountered, ignoring!"); diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index 9876cada627b..4f0372c9691d 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -60,7 +60,6 @@ const KEYS_WBO = "keys"; const LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); Cu.import("resource://services-sync/record.js"); Cu.import("resource://services-sync/constants.js"); Cu.import("resource://services-sync/engines.js"); @@ -438,10 +437,10 @@ WeaveSvc.prototype = { // Send an event now that Weave service is ready. We don't do this // synchronously so that observers can import this module before // registering an observer. - Utils.delay(function() { + Utils.nextTick(function() { Status.ready = true; Svc.Obs.notify("weave:service:ready"); - }, 0); + }); }, _checkSetup: function WeaveSvc__checkSetup() { @@ -451,7 +450,18 @@ WeaveSvc.prototype = { }, _migratePrefs: function _migratePrefs() { - // No need to re-migrate + // Migrate old debugLog prefs. + let logLevel = Svc.Prefs.get("log.appender.debugLog"); + if (logLevel) { + Svc.Prefs.set("log.appender.file.level", logLevel); + Svc.Prefs.reset("log.appender.debugLog"); + } + if (Svc.Prefs.get("log.appender.debugLog.enabled")) { + Svc.Prefs.set("log.appender.file.logOnSuccess", true); + Svc.Prefs.reset("log.appender.debugLog.enabled"); + } + + // Migrate old extensions.weave.* prefs if we haven't already tried. if (Svc.Prefs.get("migrated", false)) return; @@ -473,14 +483,14 @@ WeaveSvc.prototype = { }, _initLogs: function WeaveSvc__initLogs() { - this._log = Log4Moz.repository.getLogger("Service.Main"); + this._log = Log4Moz.repository.getLogger("Sync.Service"); this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")]; - let formatter = new Log4Moz.BasicFormatter(); - let root = Log4Moz.repository.rootLogger; + let root = Log4Moz.repository.getLogger("Sync"); root.level = Log4Moz.Level[Svc.Prefs.get("log.rootLogger")]; + let formatter = new Log4Moz.BasicFormatter(); let capp = new Log4Moz.ConsoleAppender(formatter); capp.level = Log4Moz.Level[Svc.Prefs.get("log.appender.console")]; root.addAppender(capp); @@ -489,26 +499,28 @@ WeaveSvc.prototype = { dapp.level = Log4Moz.Level[Svc.Prefs.get("log.appender.dump")]; root.addAppender(dapp); - let enabled = Svc.Prefs.get("log.appender.debugLog.enabled", false); - if (enabled) { - let verbose = FileUtils.getFile( - "ProfD", ["weave", "logs", "verbose-log.txt"], true); - - if (Svc.Prefs.get("log.appender.debugLog.rotate", true)) { - let maxSize = Svc.Prefs.get("log.appender.debugLog.maxSize"); - this._debugApp = new Log4Moz.RotatingFileAppender(verbose, formatter, - maxSize); - } else { - this._debugApp = new Log4Moz.FileAppender(verbose, formatter); - } - this._debugApp.level = Log4Moz.Level[Svc.Prefs.get("log.appender.debugLog")]; - root.addAppender(this._debugApp); - } + let fapp = this._logAppender = new Log4Moz.StorageStreamAppender(formatter); + fapp.level = Log4Moz.Level[Svc.Prefs.get("log.appender.file.level")]; + root.addAppender(fapp); }, - clearLogs: function WeaveSvc_clearLogs() { - if (this._debugApp) - this._debugApp.clear(); + _resetFileLog: function resetFileLog(flushToFile) { + let inStream = this._logAppender.getInputStream(); + this._logAppender.reset(); + if (flushToFile && inStream) { + try { + let filename = Date.now() + ".log"; + let file = FileUtils.getFile("ProfD", ["weave", "logs", filename]); + let outStream = FileUtils.openFileOutputStream(file); + NetUtil.asyncCopy(inStream, outStream, function () { + Svc.Obs.notify("weave:service:reset-file-log"); + }); + } catch (ex) { + Svc.Obs.notify("weave:service:reset-file-log"); + } + } else { + Svc.Obs.notify("weave:service:reset-file-log"); + } }, /** @@ -548,6 +560,8 @@ WeaveSvc.prototype = { if (Status.login == LOGIN_FAILED_NETWORK_ERROR && !Services.io.offline) { this._ignorableErrorCount += 1; + } else { + this._resetFileLog(Svc.Prefs.get("log.appender.file.logOnError")); } break; case "weave:service:sync:error": @@ -561,9 +575,13 @@ WeaveSvc.prototype = { case CREDENTIALS_CHANGED: this.logout(); break; + default: + this._resetFileLog(Svc.Prefs.get("log.appender.file.logOnError")); + break; } break; case "weave:service:sync:finish": + this._resetFileLog(Svc.Prefs.get("log.appender.file.logOnSuccess")); this._scheduleNextSync(); this._syncErrors = 0; this._ignorableErrorCount = 0; @@ -591,7 +609,7 @@ WeaveSvc.prototype = { this._log.trace("Idle time hit, trying to sync"); Svc.Idle.removeIdleObserver(this, this._idleTime); this._idleTime = 0; - Utils.delay(function() this.sync(false), 0, this); + Utils.nextTick(this.sync, this); break; case "nsPref:changed": if (this._ignorePrefObserver) @@ -604,7 +622,8 @@ WeaveSvc.prototype = { _handleScoreUpdate: function WeaveSvc__handleScoreUpdate() { const SCORE_UPDATE_DELAY = 3000; - Utils.delay(this._calculateScore, SCORE_UPDATE_DELAY, this, "_scoreTimer"); + Utils.namedTimer(this._calculateScore, SCORE_UPDATE_DELAY, this, + "_scoreTimer"); }, _calculateScore: function WeaveSvc_calculateScoreAndDoStuff() { @@ -1045,11 +1064,21 @@ WeaveSvc.prototype = { CollectionKeys.clear(); /* Login and sync. This also generates new keys. */ - this.sync(true); + this.sync(); return true; }))(), startOver: function() { + Svc.Obs.notify("weave:engine:stop-tracking"); + + // We want let UI consumers of the following notification know as soon as + // possible, so let's fake for the CLIENT_NOT_CONFIGURED status for now + // by emptying the passphrase (we still need the password). + Service.passphrase = ""; + Status.login = LOGIN_FAILED_NO_PASSPHRASE; + this.logout(); + Svc.Obs.notify("weave:service:start-over"); + // Deletion doesn't make sense if we aren't set up yet! if (this.clusterURL != "") { // Clear client-specific data from the server, including disabled engines. @@ -1065,10 +1094,6 @@ WeaveSvc.prototype = { this._log.debug("Skipping client data removal: no cluster URL."); } - // Set a username error so the status message shows "set up..." - Status.login = LOGIN_FAILED_NO_USERNAME; - this.logout(); - // Reset all engines and clear keys. this.resetClient(); CollectionKeys.clear(); @@ -1085,8 +1110,6 @@ WeaveSvc.prototype = { Services.logins.findLogins({}, PWDMGR_HOST, "", "").map(function(login) { Services.logins.removeLogin(login); }); - Svc.Obs.notify("weave:service:start-over"); - Svc.Obs.notify("weave:engine:stop-tracking"); }, delayedAutoConnect: function delayedAutoConnect(delay) { @@ -1094,7 +1117,7 @@ WeaveSvc.prototype = { return; if (this._checkSetup() == STATUS_OK && Svc.Prefs.get("autoconnect")) { - Utils.delay(this._autoConnect, delay * 1000, this, "_autoTimer"); + Utils.namedTimer(this._autoConnect, delay * 1000, this, "_autoTimer"); } }, @@ -1131,7 +1154,7 @@ WeaveSvc.prototype = { let interval = this._calculateBackoff(++attempts, 60 * 1000); this._log.debug("Autoconnect failed: " + (reason || Status.login) + "; retry in " + Math.ceil(interval / 1000) + " sec."); - Utils.delay(function() this._autoConnect(), interval, this, "_autoTimer"); + Utils.namedTimer(this._autoConnect, interval, this, "_autoTimer"); }, persistLogin: function persistLogin() { @@ -1571,7 +1594,7 @@ WeaveSvc.prototype = { } this._log.trace("Next sync in " + Math.ceil(interval / 1000) + " sec."); - Utils.delay(function() this.syncOnIdle(), interval, this, "_syncTimer"); + Utils.namedTimer(this.syncOnIdle, interval, this, "_syncTimer"); // Save the next sync time in-case sync is disabled (logout/offline/etc.) this.nextSync = Date.now() + interval; @@ -1647,7 +1670,7 @@ WeaveSvc.prototype = { this._log.trace("Setting up heartbeat, next ping in " + Math.ceil(interval / 1000) + " sec."); - Utils.delay(function() this._doHeartbeat(), interval, this, "_heartbeatTimer"); + Utils.namedTimer(this._doHeartbeat, interval, this, "_heartbeatTimer"); }, /** diff --git a/services/sync/modules/util.js b/services/sync/modules/util.js index 5f5f9b9998df..423aaed931db 100644 --- a/services/sync/modules/util.js +++ b/services/sync/modules/util.js @@ -36,7 +36,7 @@ * ***** END LICENSE BLOCK ***** */ const EXPORTED_SYMBOLS = ["XPCOMUtils", "Services", "NetUtil", "PlacesUtils", - "Utils", "Svc", "Str"]; + "FileUtils", "Utils", "Svc", "Str"]; const Cc = Components.classes; const Ci = Components.interfaces; @@ -848,7 +848,7 @@ let Utils = { try { return Services.io.newURI(URIString, null, null); } catch (e) { - let log = Log4Moz.repository.getLogger("Service.Util"); + let log = Log4Moz.repository.getLogger("Sync.Utils"); log.debug("Could not create URI: " + Utils.exceptionStr(e)); return null; } @@ -933,17 +933,30 @@ let Utils = { }); }, + /** + * Execute a function on the next event loop tick. + * + * @param callback + * Function to invoke. + * @param thisObj [optional] + * Object to bind the callback to. + */ + nextTick: function nextTick(callback, thisObj) { + if (thisObj) { + callback = callback.bind(thisObj); + } + Services.tm.currentThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL); + }, + /** * Return a timer that is scheduled to call the callback after waiting the * provided time or as soon as possible. The timer will be set as a property * of the provided object with the given timer name. */ - delay: function delay(callback, wait, thisObj, name) { - // Default to running right away - wait = wait || 0; - - // Use a dummy object if one wasn't provided - thisObj = thisObj || {}; + namedTimer: function delay(callback, wait, thisObj, name) { + if (!thisObj || !name) { + throw "You must provide both an object and a property name for the timer!"; + } // Delay an existing timer if it exists if (name in thisObj && thisObj[name] instanceof Ci.nsITimer) { diff --git a/services/sync/services-sync.js b/services/sync/services-sync.js index a2f19adcdb0a..f7a4e2055b9e 100644 --- a/services/sync/services-sync.js +++ b/services/sync/services-sync.js @@ -24,10 +24,9 @@ pref("services.sync.jpake.maxTries", 10); pref("services.sync.log.appender.console", "Warn"); pref("services.sync.log.appender.dump", "Error"); -pref("services.sync.log.appender.debugLog", "Trace"); -pref("services.sync.log.appender.debugLog.enabled", false); -pref("services.sync.log.appender.debugLog.rotate", true); -pref("services.sync.log.appender.debugLog.maxSize", 1048576); +pref("services.sync.log.appender.file.level", "Trace"); +pref("services.sync.log.appender.file.logOnError", true); +pref("services.sync.log.appender.file.logOnSuccess", false); pref("services.sync.log.rootLogger", "Debug"); pref("services.sync.log.logger.service.main", "Debug"); pref("services.sync.log.logger.authenticator", "Debug"); diff --git a/services/sync/tests/Makefile.in b/services/sync/tests/Makefile.in index cd0f49858093..be2e6f787554 100644 --- a/services/sync/tests/Makefile.in +++ b/services/sync/tests/Makefile.in @@ -48,5 +48,12 @@ XPCSHELL_TESTS = unit include $(topsrcdir)/config/rules.mk +# Preprocessor.py won't recognize DEBUG as defined if you just pass -DDEBUG. +# See bug 664313. (Also, yay for consistency with DEBUG v. MOZ_DEBUG.) +SYNCDEFINES= +ifdef MOZ_DEBUG +SYNCDEFINES += -DDEBUG=1 +endif + libs:: unit/head_appinfo.js.in - $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $^ > $(DEPTH)/_tests/xpcshell/$(relativesrcdir)/unit/head_appinfo.js + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(SYNCDEFINES) $^ > $(DEPTH)/_tests/xpcshell/$(relativesrcdir)/unit/head_appinfo.js diff --git a/services/sync/tests/unit/head_appinfo.js.in b/services/sync/tests/unit/head_appinfo.js.in index 3eb1732090de..06f950b2f548 100644 --- a/services/sync/tests/unit/head_appinfo.js.in +++ b/services/sync/tests/unit/head_appinfo.js.in @@ -60,7 +60,7 @@ addResourceAlias(); // Some tests hang on OSX debug builds. See bug 604565. let DISABLE_TESTS_BUG_604565 = false; #ifdef XP_MACOSX -#ifdef MOZ_DEBUG_SYMBOLS +#ifdef DEBUG DISABLE_TESTS_BUG_604565 = true; #endif #endif @@ -70,3 +70,11 @@ let DISABLE_TESTS_BUG_618233 = false; #ifdef XP_WIN DISABLE_TESTS_BUG_618233 = true; #endif + +// test_service_login.js persistently fails on Windows opt builds +let DISABLE_TESTS_BUG_664090 = false; +#ifdef XP_WIN +#ifndef DEBUG +DISABLE_TESTS_BUG_664090 = true; +#endif +#endif diff --git a/services/sync/tests/unit/head_helpers.js b/services/sync/tests/unit/head_helpers.js index 68553a20392d..9e5b81ed6c88 100644 --- a/services/sync/tests/unit/head_helpers.js +++ b/services/sync/tests/unit/head_helpers.js @@ -1,5 +1,6 @@ Cu.import("resource://services-sync/util.js"); Cu.import("resource://services-sync/record.js"); +Cu.import("resource://services-sync/engines.js"); var btoa; let provider = { @@ -233,3 +234,91 @@ function do_check_throws(aFunc, aResult, aStack) } do_throw("Expected result " + aResult + ", none thrown.", aStack); } + +/* + * A fake engine implementation. + * This is used all over the place. + * + * Complete with record, store, and tracker implementations. + */ + +function RotaryRecord(collection, id) { + CryptoWrapper.call(this, collection, id); +} +RotaryRecord.prototype = { + __proto__: CryptoWrapper.prototype +}; +Utils.deferGetSet(RotaryRecord, "cleartext", ["denomination"]); + +function RotaryStore() { + Store.call(this, "Rotary"); + this.items = {}; +} +RotaryStore.prototype = { + __proto__: Store.prototype, + + create: function Store_create(record) { + this.items[record.id] = record.denomination; + }, + + remove: function Store_remove(record) { + delete this.items[record.id]; + }, + + update: function Store_update(record) { + this.items[record.id] = record.denomination; + }, + + itemExists: function Store_itemExists(id) { + return (id in this.items); + }, + + createRecord: function(id, collection) { + let record = new RotaryRecord(collection, id); + record.denomination = this.items[id] || "Data for new record: " + id; + return record; + }, + + changeItemID: function(oldID, newID) { + this.items[newID] = this.items[oldID]; + delete this.items[oldID]; + }, + + getAllIDs: function() { + let ids = {}; + for (let id in this.items) { + ids[id] = true; + } + return ids; + }, + + wipe: function() { + this.items = {}; + } +}; + +function RotaryTracker() { + Tracker.call(this, "Rotary"); +} +RotaryTracker.prototype = { + __proto__: Tracker.prototype +}; + + +function RotaryEngine() { + SyncEngine.call(this, "Rotary"); +} +RotaryEngine.prototype = { + __proto__: SyncEngine.prototype, + _storeObj: RotaryStore, + _trackerObj: RotaryTracker, + _recordObj: RotaryRecord, + + _findDupe: function(item) { + for (let [id, value] in Iterator(this._store.items)) { + if (item.denomination == value) { + return id; + } + } + } +}; diff --git a/services/sync/tests/unit/test_async_helpers.js b/services/sync/tests/unit/test_async_helpers.js index efe7d8af704b..4d86861b2d54 100644 --- a/services/sync/tests/unit/test_async_helpers.js +++ b/services/sync/tests/unit/test_async_helpers.js @@ -192,7 +192,7 @@ add_test(function test_countedCallback() { // If we call the counted callback again (once this output function is // done, that is), then the component callback is not invoked. - Utils.delay(function () { + Utils.nextTick(function () { _("Don't expect component callback."); c1("not", "running", "now"); do_check_eq(2, counter); @@ -200,7 +200,7 @@ add_test(function test_countedCallback() { do_check_eq(2, output); do_check_eq("b", context); run_next_test(); - }, 1, this); + }); }); c1(1, "foo", "a"); diff --git a/services/sync/tests/unit/test_async_querySpinningly.js b/services/sync/tests/unit/test_async_querySpinningly.js index 6955af31daed..25954952372e 100644 --- a/services/sync/tests/unit/test_async_querySpinningly.js +++ b/services/sync/tests/unit/test_async_querySpinningly.js @@ -11,7 +11,7 @@ function run_test() { _("Make sure the call is async and allows other events to process"); let isAsync = false; - Utils.delay(function() isAsync = true, 0); + Utils.nextTick(function() { isAsync = true; }); do_check_false(isAsync); _("Empty out the formhistory table"); diff --git a/services/sync/tests/unit/test_bookmark_engine.js b/services/sync/tests/unit/test_bookmark_engine.js index 798784696269..87b0114fbad3 100644 --- a/services/sync/tests/unit/test_bookmark_engine.js +++ b/services/sync/tests/unit/test_bookmark_engine.js @@ -387,7 +387,7 @@ add_test(function test_mismatched_types() { function run_test() { initTestLogging("Trace"); - Log4Moz.repository.getLogger("Engine.Bookmarks").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Engine.Bookmarks").level = Log4Moz.Level.Trace; generateNewKeys(); diff --git a/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js b/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js index 34f2bed9c1dc..1581d73fa6d2 100644 --- a/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js +++ b/services/sync/tests/unit/test_bookmark_legacy_microsummaries_support.js @@ -45,7 +45,7 @@ function run_test() { store.wipe(); initTestLogging("Trace"); - Log4Moz.repository.getLogger("Engine.Bookmarks").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Engine.Bookmarks").level = Log4Moz.Level.Trace; _("Create a microsummarized bookmark."); let id = newMicrosummary(TEST_URL, TEST_TITLE); diff --git a/services/sync/tests/unit/test_bookmark_livemarks.js b/services/sync/tests/unit/test_bookmark_livemarks.js index ae3af8106547..dabcf91af26f 100644 --- a/services/sync/tests/unit/test_bookmark_livemarks.js +++ b/services/sync/tests/unit/test_bookmark_livemarks.js @@ -67,8 +67,8 @@ function makeLivemark(p, mintGUID) { function run_test() { initTestLogging("Trace"); - Log4Moz.repository.getLogger("Engine.Bookmarks").level = Log4Moz.Level.Trace; - Log4Moz.repository.getLogger("Store.Bookmarks").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Engine.Bookmarks").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Store.Bookmarks").level = Log4Moz.Level.Trace; run_next_test(); } @@ -136,5 +136,5 @@ add_test(function test_livemark_invalid() { do_check_eq(-1, store.idForGUID(lmParentRec.id, true)); // Clear event loop. - Utils.delay(run_next_test, 0); + Utils.nextTick(run_next_test); }); diff --git a/services/sync/tests/unit/test_bookmark_places_query_rewriting.js b/services/sync/tests/unit/test_bookmark_places_query_rewriting.js index e040e1f212bd..fbcf85a7bfd5 100644 --- a/services/sync/tests/unit/test_bookmark_places_query_rewriting.js +++ b/services/sync/tests/unit/test_bookmark_places_query_rewriting.js @@ -7,8 +7,8 @@ let store = engine._store; function run_test() { initTestLogging("Trace"); - Log4Moz.repository.getLogger("Engine.Bookmarks").level = Log4Moz.Level.Trace; - Log4Moz.repository.getLogger("Store.Bookmarks").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Engine.Bookmarks").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Store.Bookmarks").level = Log4Moz.Level.Trace; let tagRecord = new BookmarkQuery("bookmarks", "abcdefabcdef"); let uri = "place:folder=499&type=7&queryType=1"; diff --git a/services/sync/tests/unit/test_bookmark_smart_bookmarks.js b/services/sync/tests/unit/test_bookmark_smart_bookmarks.js index cf7281423191..dc54080847e2 100644 --- a/services/sync/tests/unit/test_bookmark_smart_bookmarks.js +++ b/services/sync/tests/unit/test_bookmark_smart_bookmarks.js @@ -239,7 +239,7 @@ add_test(function test_smart_bookmarks_duped() { function run_test() { initTestLogging("Trace"); - Log4Moz.repository.getLogger("Engine.Bookmarks").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Engine.Bookmarks").level = Log4Moz.Level.Trace; generateNewKeys(); diff --git a/services/sync/tests/unit/test_bookmark_tracker.js b/services/sync/tests/unit/test_bookmark_tracker.js index e30f66ca6949..148807feaac3 100644 --- a/services/sync/tests/unit/test_bookmark_tracker.js +++ b/services/sync/tests/unit/test_bookmark_tracker.js @@ -144,9 +144,9 @@ function test_onItemMoved() { function run_test() { initTestLogging("Trace"); - Log4Moz.repository.getLogger("Engine.Bookmarks").level = Log4Moz.Level.Trace; - Log4Moz.repository.getLogger("Store.Bookmarks").level = Log4Moz.Level.Trace; - Log4Moz.repository.getLogger("Tracker.Bookmarks").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Engine.Bookmarks").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Store.Bookmarks").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Tracker.Bookmarks").level = Log4Moz.Level.Trace; test_tracking(); test_onItemChanged(); diff --git a/services/sync/tests/unit/test_clients_engine.js b/services/sync/tests/unit/test_clients_engine.js index 38f272296d83..4bafd5c72d3b 100644 --- a/services/sync/tests/unit/test_clients_engine.js +++ b/services/sync/tests/unit/test_clients_engine.js @@ -209,6 +209,6 @@ add_test(function test_sync() { function run_test() { initTestLogging("Trace"); - Log4Moz.repository.getLogger("Engine.Clients").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Engine.Clients").level = Log4Moz.Level.Trace; run_next_test(); } diff --git a/services/sync/tests/unit/test_history_store.js b/services/sync/tests/unit/test_history_store.js index 8eb142bd5429..2a54f017650c 100644 --- a/services/sync/tests/unit/test_history_store.js +++ b/services/sync/tests/unit/test_history_store.js @@ -35,7 +35,7 @@ function onNextTitleChanged(callback) { onPageChanged: function onPageChanged() {}, onTitleChanged: function onTitleChanged() { PlacesUtils.history.removeObserver(this); - Utils.delay(callback, 0, this); + Utils.nextTick(callback); }, onVisit: function onVisit() {}, onDeleteVisits: function onDeleteVisits() {}, diff --git a/services/sync/tests/unit/test_history_tracker.js b/services/sync/tests/unit/test_history_tracker.js index a6532ce73156..72f02c3e32f1 100644 --- a/services/sync/tests/unit/test_history_tracker.js +++ b/services/sync/tests/unit/test_history_tracker.js @@ -40,10 +40,10 @@ add_test(function test_empty() { add_test(function test_not_tracking(next) { _("Create history item. Won't show because we haven't started tracking yet"); addVisit(); - Utils.delay(function() { + Utils.nextTick(function() { do_check_eq([id for (id in tracker.changedIDs)].length, 0); run_next_test(); - }, 0); + }); }); add_test(function test_start_tracking() { @@ -85,20 +85,20 @@ add_test(function test_stop_tracking() { tracker.clearChangedIDs(); Svc.Obs.notify("weave:engine:stop-tracking"); addVisit(); - Utils.delay(function() { + Utils.nextTick(function() { do_check_eq([id for (id in tracker.changedIDs)].length, 0); run_next_test(); - }, 0); + }); }); add_test(function test_stop_tracking_twice() { _("Notifying twice won't do any harm."); Svc.Obs.notify("weave:engine:stop-tracking"); addVisit(); - Utils.delay(function() { + Utils.nextTick(function() { do_check_eq([id for (id in tracker.changedIDs)].length, 0); run_next_test(); - }, 0); + }); }); add_test(function cleanup() { diff --git a/services/sync/tests/unit/test_jpakeclient.js b/services/sync/tests/unit/test_jpakeclient.js index bbc5eedf26d9..23f0c2338b75 100644 --- a/services/sync/tests/unit/test_jpakeclient.js +++ b/services/sync/tests/unit/test_jpakeclient.js @@ -157,8 +157,7 @@ add_test(function test_success_receiveNoPIN() { displayPIN: function displayPIN(pin) { _("Received PIN " + pin + ". Entering it in the other computer..."); this.cid = pin.slice(JPAKE_LENGTH_SECRET); - Utils.delay(function() { snd.sendWithPIN(pin, DATA); }, 0, - this, "_timer"); + Utils.nextTick(function() { snd.sendWithPIN(pin, DATA); }); }, onAbort: function onAbort(error) { do_throw("Shouldn't have aborted! " + error); @@ -223,8 +222,7 @@ add_test(function test_wrongPIN() { let new_pin = secret + this.cid; _("Received PIN " + pin + ", but I'm entering " + new_pin); - Utils.delay(function() { snd.sendWithPIN(new_pin, DATA); }, 0, - this, "_timer"); + Utils.nextTick(function() { snd.sendWithPIN(new_pin, DATA); }); }, onAbort: function onAbort(error) { do_check_eq(error, JPAKE_ERROR_NODATA); @@ -258,8 +256,7 @@ add_test(function test_abort_receiver() { }, displayPIN: function displayPIN(pin) { this.cid = pin.slice(JPAKE_LENGTH_SECRET); - Utils.delay(function() { rec.abort(); }, - 0, this, "_timer"); + Utils.nextTick(function() { rec.abort(); }); } }); rec.receiveNoPIN(); @@ -298,10 +295,9 @@ add_test(function test_abort_sender() { displayPIN: function displayPIN(pin) { _("Received PIN " + pin + ". Entering it in the other computer..."); this.cid = pin.slice(JPAKE_LENGTH_SECRET); - Utils.delay(function() { snd.sendWithPIN(pin, DATA); }, 0, - this, "_timer"); - Utils.delay(function() { snd.abort(); }, - POLLINTERVAL, this, "_abortTimer"); + Utils.nextTick(function() { snd.sendWithPIN(pin, DATA); }); + Utils.namedTimer(function() { snd.abort(); }, + POLLINTERVAL, this, "_abortTimer"); } }); rec.receiveNoPIN(); diff --git a/services/sync/tests/unit/test_log4moz.js b/services/sync/tests/unit/test_log4moz.js index f48ee8b9f2fb..03a44fbe1bd1 100644 --- a/services/sync/tests/unit/test_log4moz.js +++ b/services/sync/tests/unit/test_log4moz.js @@ -1,19 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + Components.utils.import("resource://services-sync/log4moz.js"); +Components.utils.import("resource://gre/modules/FileUtils.jsm"); + +let testFormatter = { + format: function format(message) { + return message.loggerName + "\t" + message.levelDesc + "\t" + + message.message + "\n"; + } +}; function MockAppender(formatter) { - this._formatter = formatter; + Log4Moz.Appender.call(this, formatter); this.messages = []; } MockAppender.prototype = { + __proto__: Log4Moz.Appender.prototype, + doAppend: function DApp_doAppend(message) { this.messages.push(message); } }; -MockAppender.prototype.__proto__ = new Log4Moz.Appender(); function run_test() { - var log = Log4Moz.repository.rootLogger; - var appender = new MockAppender(new Log4Moz.BasicFormatter()); + run_next_test(); +} + +add_test(function test_Logger() { + let log = Log4Moz.repository.getLogger("test.logger"); + let appender = new MockAppender(new Log4Moz.BasicFormatter()); log.level = Log4Moz.Level.Debug; appender.level = Log4Moz.Level.Info; @@ -25,7 +41,11 @@ function run_test() { do_check_true(appender.messages[0].indexOf("info test") > 0); do_check_true(appender.messages[0].indexOf("INFO") > 0); - // Test - check whether parenting is correct + run_next_test(); +}); + +add_test(function test_Logger_parent() { + // Check whether parenting is correct let grandparentLog = Log4Moz.repository.getLogger("grandparent"); let childLog = Log4Moz.repository.getLogger("grandparent.parent.child"); do_check_eq(childLog.parent.name, "grandparent"); @@ -33,13 +53,86 @@ function run_test() { let parentLog = Log4Moz.repository.getLogger("grandparent.parent"); do_check_eq(childLog.parent.name, "grandparent.parent"); - // Test - check that appends are exactly in scope + // Check that appends are exactly in scope let gpAppender = new MockAppender(new Log4Moz.BasicFormatter()); gpAppender.level = Log4Moz.Level.Info; grandparentLog.addAppender(gpAppender); childLog.info("child info test"); - log.info("this shouldn't show up in gpAppender"); + Log4Moz.repository.rootLogger.info("this shouldn't show up in gpAppender"); do_check_eq(gpAppender.messages.length, 1); do_check_true(gpAppender.messages[0].indexOf("child info test") > 0); + + run_next_test(); +}); + +add_test(function test_StorageStreamAppender() { + let appender = new Log4Moz.StorageStreamAppender(testFormatter); + do_check_eq(appender.getInputStream(), null); + + // Log to the storage stream and verify the log was written and can be + // read back. + let logger = Log4Moz.repository.getLogger("test.StorageStreamAppender"); + logger.addAppender(appender); + logger.info("OHAI"); + let inputStream = appender.getInputStream(); + let data = NetUtil.readInputStreamToString(inputStream, + inputStream.available()); + do_check_eq(data, "test.StorageStreamAppender\tINFO\tOHAI\n"); + + // We can read it again even. + let sndInputStream = appender.getInputStream(); + let sameData = NetUtil.readInputStreamToString(sndInputStream, + sndInputStream.available()); + do_check_eq(data, sameData); + + // Reset the appender and log some more. + appender.reset(); + do_check_eq(appender.getInputStream(), null); + logger.debug("wut?!?"); + inputStream = appender.getInputStream(); + data = NetUtil.readInputStreamToString(inputStream, + inputStream.available()); + do_check_eq(data, "test.StorageStreamAppender\tDEBUG\twut?!?\n"); + + run_next_test(); +}); + +function readFile(file) { + let fstream = Cc["@mozilla.org/network/file-input-stream;1"] + .createInstance(Ci.nsIFileInputStream); + fstream.init(file, -1, 0, 0); + let data = NetUtil.readInputStreamToString(fstream, fstream.available()); + fstream.close(); + return data; } + +add_test(function test_FileAppender() { + // This directory does not exist yet + let dir = FileUtils.getFile("ProfD", ["test_log4moz"]); + do_check_false(dir.exists()); + + let file = dir.clone(); + file.append("test_FileAppender"); + let appender = new Log4Moz.FileAppender(file, testFormatter); + + // Logging against to a file that can't be created won't do harm. + let logger = Log4Moz.repository.getLogger("test.FileAppender"); + logger.addAppender(appender); + logger.info("OHAI"); + + // The file will be written Once the directory leading up to the file exists. + dir.create(Ci.nsILocalFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + logger.info("OHAI"); + do_check_true(file.exists()); + do_check_eq(readFile(file), "test.FileAppender\tINFO\tOHAI\n"); + + // Reset the appender and log some more. + appender.reset(); + do_check_false(file.exists()); + logger.debug("O RLY?!?"); + do_check_true(file.exists()); + do_check_eq(readFile(file), "test.FileAppender\tDEBUG\tO RLY?!?\n"); + + run_next_test(); +}); diff --git a/services/sync/tests/unit/test_password_store.js b/services/sync/tests/unit/test_password_store.js index dd585783b970..0f341ed41f75 100644 --- a/services/sync/tests/unit/test_password_store.js +++ b/services/sync/tests/unit/test_password_store.js @@ -3,8 +3,8 @@ Cu.import("resource://services-sync/util.js"); function run_test() { initTestLogging("Trace"); - Log4Moz.repository.getLogger("Engine.Passwords").level = Log4Moz.Level.Trace; - Log4Moz.repository.getLogger("Store.Passwords").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Engine.Passwords").level = Log4Moz.Level.Trace; + Log4Moz.repository.getLogger("Sync.Store.Passwords").level = Log4Moz.Level.Trace; const BOGUS_GUID_A = "zzzzzzzzzzzz"; const BOGUS_GUID_B = "yyyyyyyyyyyy"; diff --git a/services/sync/tests/unit/test_resource_async.js b/services/sync/tests/unit/test_resource_async.js index b26f8b04314a..cd35fd3cfade 100644 --- a/services/sync/tests/unit/test_resource_async.js +++ b/services/sync/tests/unit/test_resource_async.js @@ -134,13 +134,20 @@ function server_headers(metadata, response) { response.bodyOutputStream.write(body, body.length); } +let did401 = false; +Observers.add("weave:resource:status:401", function() { did401 = true; }); + +let quotaValue; +Observers.add("weave:service:quota:remaining", + function (subject) { quotaValue = subject; }); + +let server; function run_test() { logger = Log4Moz.repository.getLogger('Test'); Log4Moz.repository.rootLogger.addAppender(new Log4Moz.DumpAppender()); - do_test_pending(); - let server = httpd_setup({ + server = httpd_setup({ "/open": server_open, "/protected": server_protected, "/404": server_404, @@ -155,18 +162,11 @@ function run_test() { }); Svc.Prefs.set("network.numRetries", 1); // speed up test - - let did401 = false; - Observers.add("weave:resource:status:401", function() did401 = true); - - let quotaValue; - Observers.add("weave:service:quota:remaining", - function (subject) quotaValue = subject); + run_next_test(); +} - let res_upload = new AsyncResource("http://localhost:8080/upload"); - let res_headers = new AsyncResource("http://localhost:8080/headers"); - +add_test(function test_members() { _("Resource object memebers"); let res = new AsyncResource("http://localhost:8080/open"); do_check_true(res.uri instanceof Ci.nsIURI); @@ -178,532 +178,489 @@ function run_test() { // PUT/POST request yet. do_check_eq(res.data, null); - Utils.asyncChain(function (next) { + run_next_test(); +}); - _("GET a non-password-protected resource"); - do_test_pending(); - res.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "This path exists"); - do_check_eq(content.status, 200); - do_check_true(content.success); - // res.data has been updated with the result from the request - do_check_eq(res.data, content); +add_test(function test_get() { + _("GET a non-password-protected resource"); + let res = new AsyncResource("http://localhost:8080/open"); + res.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "This path exists"); + do_check_eq(content.status, 200); + do_check_true(content.success); + // res.data has been updated with the result from the request + do_check_eq(res.data, content); - // Since we didn't receive proper JSON data, accessing content.obj - // will result in a SyntaxError from JSON.parse - let didThrow = false; - try { - content.obj; - } catch (ex) { - didThrow = true; - } - do_check_true(didThrow); - - do_test_finished(); - next(); - })); - - }, function (next) { - - _("Test that the BasicAuthenticator doesn't screw up header case."); - let res1 = new AsyncResource("http://localhost:8080/foo"); - res1.setHeader("Authorization", "Basic foobar"); - res1.authenticator = new NoOpAuthenticator(); - do_check_eq(res1._headers["authorization"], "Basic foobar"); - do_check_eq(res1.headers["authorization"], "Basic foobar"); - let id = new Identity("secret", "guest", "guest"); - res1.authenticator = new BasicAuthenticator(id); - - // In other words... it correctly overwrites our downcased version - // when accessed through .headers. - do_check_eq(res1._headers["authorization"], "Basic foobar"); - do_check_eq(res1.headers["authorization"], "Basic Z3Vlc3Q6Z3Vlc3Q="); - do_check_eq(res1._headers["authorization"], "Basic Z3Vlc3Q6Z3Vlc3Q="); - do_check_true(!res1._headers["Authorization"]); - do_check_true(!res1.headers["Authorization"]); - next(); - - }, function (next) { - - _("GET a password protected resource (test that it'll fail w/o pass, no throw)"); - let res2 = new AsyncResource("http://localhost:8080/protected"); - do_test_pending(); - res2.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_true(did401); - do_check_eq(content, "This path exists and is protected - failed"); - do_check_eq(content.status, 401); - do_check_false(content.success); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("GET a password protected resource"); - let auth = new BasicAuthenticator(new Identity("secret", "guest", "guest")); - let res3 = new AsyncResource("http://localhost:8080/protected"); - res3.authenticator = auth; - do_check_eq(res3.authenticator, auth); - do_test_pending(); - res3.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "This path exists and is protected"); - do_check_eq(content.status, 200); - do_check_true(content.success); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("GET a non-existent resource (test that it'll fail, but not throw)"); - let res4 = new AsyncResource("http://localhost:8080/404"); - do_test_pending(); - res4.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "File not found"); - do_check_eq(content.status, 404); - do_check_false(content.success); - - // Check some headers of the 404 response - do_check_eq(content.headers.connection, "close"); - do_check_eq(content.headers.server, "httpd.js"); - do_check_eq(content.headers["content-length"], 14); - - do_test_finished(); - next(); - })); - - }, function (next) { - - _("PUT to a resource (string)"); - do_test_pending(); - res_upload.put(JSON.stringify(sample_data), ensureThrows(function(error, content) { - do_check_eq(error, null); - do_check_eq(content, "Valid data upload via PUT"); - do_check_eq(content.status, 200); - do_check_eq(res_upload.data, content); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("PUT to a resource (object)"); - do_test_pending(); - res_upload.put(sample_data, ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "Valid data upload via PUT"); - do_check_eq(content.status, 200); - do_check_eq(res_upload.data, content); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("PUT without data arg (uses resource.data) (string)"); - do_test_pending(); - res_upload.data = JSON.stringify(sample_data); - res_upload.put(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "Valid data upload via PUT"); - do_check_eq(content.status, 200); - do_check_eq(res_upload.data, content); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("PUT without data arg (uses resource.data) (object)"); - do_test_pending(); - res_upload.data = sample_data; - res_upload.put(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "Valid data upload via PUT"); - do_check_eq(content.status, 200); - do_check_eq(res_upload.data, content); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("POST to a resource (string)"); - do_test_pending(); - res_upload.post(JSON.stringify(sample_data), ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "Valid data upload via POST"); - do_check_eq(content.status, 200); - do_check_eq(res_upload.data, content); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("POST to a resource (object)"); - do_test_pending(); - res_upload.post(sample_data, ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "Valid data upload via POST"); - do_check_eq(content.status, 200); - do_check_eq(res_upload.data, content); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("POST without data arg (uses resource.data) (string)"); - do_test_pending(); - res_upload.data = JSON.stringify(sample_data); - res_upload.post(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "Valid data upload via POST"); - do_check_eq(content.status, 200); - do_check_eq(res_upload.data, content); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("POST without data arg (uses resource.data) (object)"); - do_test_pending(); - res_upload.data = sample_data; - res_upload.post(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "Valid data upload via POST"); - do_check_eq(content.status, 200); - do_check_eq(res_upload.data, content); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("DELETE a resource"); - do_test_pending(); - let res6 = new AsyncResource("http://localhost:8080/delete"); - res6.delete(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "This resource has been deleted"); - do_check_eq(content.status, 200); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("JSON conversion of response body"); - do_test_pending(); - let res7 = new AsyncResource("http://localhost:8080/json"); - res7.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, JSON.stringify(sample_data)); - do_check_eq(content.status, 200); - do_check_eq(JSON.stringify(content.obj), JSON.stringify(sample_data)); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("X-Weave-Timestamp header updates AsyncResource.serverTime"); - do_test_pending(); - // Before having received any response containing the - // X-Weave-Timestamp header, AsyncResource.serverTime is null. - do_check_eq(AsyncResource.serverTime, null); - let res8 = new AsyncResource("http://localhost:8080/timestamp"); - res8.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(AsyncResource.serverTime, TIMESTAMP); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("GET: no special request headers"); - do_test_pending(); - res_headers.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, '{}'); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("PUT: Content-Type defaults to text/plain"); - do_test_pending(); - res_headers.put('data', ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, JSON.stringify({"content-type": "text/plain"})); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("POST: Content-Type defaults to text/plain"); - do_test_pending(); - res_headers.post('data', ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, JSON.stringify({"content-type": "text/plain"})); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("setHeader(): setting simple header"); - do_test_pending(); - res_headers.setHeader('X-What-Is-Weave', 'awesome'); - do_check_eq(res_headers.headers['x-what-is-weave'], 'awesome'); - res_headers.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, JSON.stringify({"x-what-is-weave": "awesome"})); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("setHeader(): setting multiple headers, overwriting existing header"); - do_test_pending(); - res_headers.setHeader('X-WHAT-is-Weave', 'more awesomer'); - res_headers.setHeader('X-Another-Header', 'hello world'); - do_check_eq(res_headers.headers['x-what-is-weave'], 'more awesomer'); - do_check_eq(res_headers.headers['x-another-header'], 'hello world'); - res_headers.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, JSON.stringify({"x-another-header": "hello world", - "x-what-is-weave": "more awesomer"})); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("Setting headers object"); - do_test_pending(); - res_headers.headers = {}; - res_headers.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, "{}"); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("PUT: override default Content-Type"); - do_test_pending(); - res_headers.setHeader('Content-Type', 'application/foobar'); - do_check_eq(res_headers.headers['content-type'], 'application/foobar'); - res_headers.put('data', ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, JSON.stringify({"content-type": "application/foobar"})); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("POST: override default Content-Type"); - do_test_pending(); - res_headers.post('data', ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content, JSON.stringify({"content-type": "application/foobar"})); - do_test_finished(); - next(); - })); - - }, function (next) { - - _("X-Weave-Backoff header notifies observer"); - let backoffInterval; - function onBackoff(subject, data) { - backoffInterval = subject; + // Since we didn't receive proper JSON data, accessing content.obj + // will result in a SyntaxError from JSON.parse + let didThrow = false; + try { + content.obj; + } catch (ex) { + didThrow = true; } - Observers.add("weave:service:backoff:interval", onBackoff); + do_check_true(didThrow); - do_test_pending(); - let res10 = new AsyncResource("http://localhost:8080/backoff"); - res10.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(backoffInterval, 600); - do_test_finished(); - next(); - })); + run_next_test(); + }); +}); - }, function (next) { +add_test(function test_basicauth() { + _("Test that the BasicAuthenticator doesn't screw up header case."); + let res1 = new AsyncResource("http://localhost:8080/foo"); + res1.setHeader("Authorization", "Basic foobar"); + res1.authenticator = new NoOpAuthenticator(); + do_check_eq(res1._headers["authorization"], "Basic foobar"); + do_check_eq(res1.headers["authorization"], "Basic foobar"); + let id = new Identity("secret", "guest", "guest"); + res1.authenticator = new BasicAuthenticator(id); - _("X-Weave-Quota-Remaining header notifies observer on successful requests."); - do_test_pending(); - let res10 = new AsyncResource("http://localhost:8080/quota-error"); - res10.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content.status, 400); - do_check_eq(quotaValue, undefined); // HTTP 400, so no observer notification. - do_test_finished(); - next(); - })); + // In other words... it correctly overwrites our downcased version + // when accessed through .headers. + do_check_eq(res1._headers["authorization"], "Basic foobar"); + do_check_eq(res1.headers["authorization"], "Basic Z3Vlc3Q6Z3Vlc3Q="); + do_check_eq(res1._headers["authorization"], "Basic Z3Vlc3Q6Z3Vlc3Q="); + do_check_true(!res1._headers["Authorization"]); + do_check_true(!res1.headers["Authorization"]); - }, function (next) { + run_next_test(); +}); - do_test_pending(); - let res10 = new AsyncResource("http://localhost:8080/quota-notice"); - res10.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(content.status, 200); - do_check_eq(quotaValue, 1048576); - do_test_finished(); - next(); - })); +add_test(function test_get_protected_fail() { + _("GET a password protected resource (test that it'll fail w/o pass, no throw)"); + let res2 = new AsyncResource("http://localhost:8080/protected"); + res2.get(function (error, content) { + do_check_eq(error, null); + do_check_true(did401); + do_check_eq(content, "This path exists and is protected - failed"); + do_check_eq(content.status, 401); + do_check_false(content.success); + run_next_test(); + }); +}); - }, function (next) { +add_test(function test_get_protected_success() { + _("GET a password protected resource"); + let auth = new BasicAuthenticator(new Identity("secret", "guest", "guest")); + let res3 = new AsyncResource("http://localhost:8080/protected"); + res3.authenticator = auth; + do_check_eq(res3.authenticator, auth); + res3.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "This path exists and is protected"); + do_check_eq(content.status, 200); + do_check_true(content.success); + run_next_test(); + }); +}); - _("Error handling in ChannelListener etc. preserves exception information"); - do_test_pending(); - let res11 = new AsyncResource("http://localhost:12345/does/not/exist"); - res11.get(ensureThrows(function (error, content) { - do_check_neq(error, null); - do_check_eq(error.result, Cr.NS_ERROR_CONNECTION_REFUSED); - do_check_eq(error.message, "NS_ERROR_CONNECTION_REFUSED"); - do_test_finished(); - next(); - })); +add_test(function test_get_404() { + _("GET a non-existent resource (test that it'll fail, but not throw)"); + let res4 = new AsyncResource("http://localhost:8080/404"); + res4.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "File not found"); + do_check_eq(content.status, 404); + do_check_false(content.success); - }, function (next) { + // Check some headers of the 404 response + do_check_eq(content.headers.connection, "close"); + do_check_eq(content.headers.server, "httpd.js"); + do_check_eq(content.headers["content-length"], 14); - let redirRequest; - let redirToOpen = function(subject) { - subject.newUri = "http://localhost:8080/open"; - redirRequest = subject; - }; - Observers.add("weave:resource:status:401", redirToOpen); + run_next_test(); + }); +}); - _("Notification of 401 can redirect to another uri"); - did401 = false; - do_test_pending(); - let res12 = new AsyncResource("http://localhost:8080/protected"); - res12.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_eq(res12.spec, "http://localhost:8080/open"); - do_check_eq(content, "This path exists"); - do_check_eq(content.status, 200); - do_check_true(content.success); - do_check_eq(res.data, content); - do_check_true(did401); - do_check_eq(redirRequest.response, "This path exists and is protected - failed"); - do_check_eq(redirRequest.response.status, 401); - do_check_false(redirRequest.response.success); +add_test(function test_put_string() { + _("PUT to a resource (string)"); + let res_upload = new AsyncResource("http://localhost:8080/upload"); + res_upload.put(JSON.stringify(sample_data), function(error, content) { + do_check_eq(error, null); + do_check_eq(content, "Valid data upload via PUT"); + do_check_eq(content.status, 200); + do_check_eq(res_upload.data, content); + run_next_test(); + }); +}); - Observers.remove("weave:resource:status:401", redirToOpen); - do_test_finished(); - next(); - })); +add_test(function test_put_object() { + _("PUT to a resource (object)"); + let res_upload = new AsyncResource("http://localhost:8080/upload"); + res_upload.put(sample_data, function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "Valid data upload via PUT"); + do_check_eq(content.status, 200); + do_check_eq(res_upload.data, content); + run_next_test(); + }); +}); - }, function (next) { +add_test(function test_put_data_string() { + _("PUT without data arg (uses resource.data) (string)"); + let res_upload = new AsyncResource("http://localhost:8080/upload"); + res_upload.data = JSON.stringify(sample_data); + res_upload.put(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "Valid data upload via PUT"); + do_check_eq(content.status, 200); + do_check_eq(res_upload.data, content); + run_next_test(); + }); +}); - _("Removing the observer should result in the original 401"); - did401 = false; - do_test_pending(); - let res13 = new AsyncResource("http://localhost:8080/protected"); - res13.get(ensureThrows(function (error, content) { - do_check_eq(error, null); - do_check_true(did401); - do_check_eq(content, "This path exists and is protected - failed"); - do_check_eq(content.status, 401); - do_check_false(content.success); - do_test_finished(); - next(); - })); +add_test(function test_put_data_object() { + _("PUT without data arg (uses resource.data) (object)"); + let res_upload = new AsyncResource("http://localhost:8080/upload"); + res_upload.data = sample_data; + res_upload.put(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "Valid data upload via PUT"); + do_check_eq(content.status, 200); + do_check_eq(res_upload.data, content); + run_next_test(); + }); +}); - }, function (next) { +add_test(function test_post_string() { + _("POST to a resource (string)"); + let res_upload = new AsyncResource("http://localhost:8080/upload"); + res_upload.post(JSON.stringify(sample_data), function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "Valid data upload via POST"); + do_check_eq(content.status, 200); + do_check_eq(res_upload.data, content); + run_next_test(); + }); +}); - _("Exception handling inside fetches."); - do_test_pending(); - let res14 = new AsyncResource("http://localhost:8080/json"); - res14._onProgress = function(rec) { - // Provoke an XPC exception without a Javascript wrapper. - Services.io.newURI("::::::::", null, null); - }; - let warnings = []; - res14._log.warn = function(msg) { warnings.push(msg) }; +add_test(function test_post_object() { + _("POST to a resource (object)"); + let res_upload = new AsyncResource("http://localhost:8080/upload"); + res_upload.post(sample_data, function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "Valid data upload via POST"); + do_check_eq(content.status, 200); + do_check_eq(res_upload.data, content); + run_next_test(); + }); +}); - res14.get(ensureThrows(function (error, content) { - do_check_eq(error.result, Cr.NS_ERROR_MALFORMED_URI); - do_check_eq(error.message, "NS_ERROR_MALFORMED_URI"); - do_check_eq(content, null); - do_check_eq(warnings.pop(), - "Got exception calling onProgress handler during fetch of " + - "http://localhost:8080/json"); +add_test(function test_post_data_string() { + _("POST without data arg (uses resource.data) (string)"); + let res_upload = new AsyncResource("http://localhost:8080/upload"); + res_upload.data = JSON.stringify(sample_data); + res_upload.post(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "Valid data upload via POST"); + do_check_eq(content.status, 200); + do_check_eq(res_upload.data, content); + run_next_test(); + }); +}); + +add_test(function test_post_data_object() { + _("POST without data arg (uses resource.data) (object)"); + let res_upload = new AsyncResource("http://localhost:8080/upload"); + res_upload.data = sample_data; + res_upload.post(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "Valid data upload via POST"); + do_check_eq(content.status, 200); + do_check_eq(res_upload.data, content); + run_next_test(); + }); +}); + +add_test(function test_delete() { + _("DELETE a resource"); + let res6 = new AsyncResource("http://localhost:8080/delete"); + res6.delete(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "This resource has been deleted"); + do_check_eq(content.status, 200); + run_next_test(); + }); +}); + +add_test(function test_json_body() { + _("JSON conversion of response body"); + let res7 = new AsyncResource("http://localhost:8080/json"); + res7.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, JSON.stringify(sample_data)); + do_check_eq(content.status, 200); + do_check_eq(JSON.stringify(content.obj), JSON.stringify(sample_data)); + run_next_test(); + }); +}); + +add_test(function test_weave_timestamp() { + _("X-Weave-Timestamp header updates AsyncResource.serverTime"); + // Before having received any response containing the + // X-Weave-Timestamp header, AsyncResource.serverTime is null. + do_check_eq(AsyncResource.serverTime, null); + let res8 = new AsyncResource("http://localhost:8080/timestamp"); + res8.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(AsyncResource.serverTime, TIMESTAMP); + run_next_test(); + }); +}); + +add_test(function test_get_no_headers() { + _("GET: no special request headers"); + let res_headers = new AsyncResource("http://localhost:8080/headers"); + res_headers.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, '{}'); + run_next_test(); + }); +}); + +add_test(function test_put_default_content_type() { + _("PUT: Content-Type defaults to text/plain"); + let res_headers = new AsyncResource("http://localhost:8080/headers"); + res_headers.put('data', function (error, content) { + do_check_eq(error, null); + do_check_eq(content, JSON.stringify({"content-type": "text/plain"})); + run_next_test(); + }); +}); + +add_test(function test_post_default_content_type() { + _("POST: Content-Type defaults to text/plain"); + let res_headers = new AsyncResource("http://localhost:8080/headers"); + res_headers.post('data', function (error, content) { + do_check_eq(error, null); + do_check_eq(content, JSON.stringify({"content-type": "text/plain"})); + run_next_test(); + }); +}); + +add_test(function test_setHeader() { + _("setHeader(): setting simple header"); + let res_headers = new AsyncResource("http://localhost:8080/headers"); + res_headers.setHeader('X-What-Is-Weave', 'awesome'); + do_check_eq(res_headers.headers['x-what-is-weave'], 'awesome'); + res_headers.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, JSON.stringify({"x-what-is-weave": "awesome"})); + run_next_test(); + }); +}); + +add_test(function test_setHeader_overwrite() { + _("setHeader(): setting multiple headers, overwriting existing header"); + let res_headers = new AsyncResource("http://localhost:8080/headers"); + res_headers.setHeader('X-WHAT-is-Weave', 'more awesomer'); + res_headers.setHeader('X-Another-Header', 'hello world'); + do_check_eq(res_headers.headers['x-what-is-weave'], 'more awesomer'); + do_check_eq(res_headers.headers['x-another-header'], 'hello world'); + res_headers.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, JSON.stringify({"x-another-header": "hello world", + "x-what-is-weave": "more awesomer"})); + + run_next_test(); + }); +}); + +add_test(function test_headers_object() { + _("Setting headers object"); + let res_headers = new AsyncResource("http://localhost:8080/headers"); + res_headers.headers = {}; + res_headers.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(content, "{}"); + run_next_test(); + }); +}); + +add_test(function test_put_override_content_type() { + _("PUT: override default Content-Type"); + let res_headers = new AsyncResource("http://localhost:8080/headers"); + res_headers.setHeader('Content-Type', 'application/foobar'); + do_check_eq(res_headers.headers['content-type'], 'application/foobar'); + res_headers.put('data', function (error, content) { + do_check_eq(error, null); + do_check_eq(content, JSON.stringify({"content-type": "application/foobar"})); + run_next_test(); + }); +}); + +add_test(function test_post_override_content_type() { + _("POST: override default Content-Type"); + let res_headers = new AsyncResource("http://localhost:8080/headers"); + res_headers.setHeader('Content-Type', 'application/foobar'); + res_headers.post('data', function (error, content) { + do_check_eq(error, null); + do_check_eq(content, JSON.stringify({"content-type": "application/foobar"})); + run_next_test(); + }); +}); + +add_test(function test_weave_backoff() { + _("X-Weave-Backoff header notifies observer"); + let backoffInterval; + function onBackoff(subject, data) { + backoffInterval = subject; + } + Observers.add("weave:service:backoff:interval", onBackoff); + + let res10 = new AsyncResource("http://localhost:8080/backoff"); + res10.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(backoffInterval, 600); + run_next_test(); + }); +}); + +add_test(function test_quota_error() { + _("X-Weave-Quota-Remaining header notifies observer on successful requests."); + let res10 = new AsyncResource("http://localhost:8080/quota-error"); + res10.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(content.status, 400); + do_check_eq(quotaValue, undefined); // HTTP 400, so no observer notification. + run_next_test(); + }); +}); + +add_test(function test_quota_notice() { + let res10 = new AsyncResource("http://localhost:8080/quota-notice"); + res10.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(content.status, 200); + do_check_eq(quotaValue, 1048576); + run_next_test(); + }); +}); + +add_test(function test_preserve_exceptions() { + _("Error handling in ChannelListener etc. preserves exception information"); + let res11 = new AsyncResource("http://localhost:12345/does/not/exist"); + res11.get(function (error, content) { + do_check_neq(error, null); + do_check_eq(error.result, Cr.NS_ERROR_CONNECTION_REFUSED); + do_check_eq(error.message, "NS_ERROR_CONNECTION_REFUSED"); + run_next_test(); + }); +}); + +add_test(function test_401_redirect() { + let redirRequest; + let redirToOpen = function(subject) { + subject.newUri = "http://localhost:8080/open"; + redirRequest = subject; + }; + Observers.add("weave:resource:status:401", redirToOpen); + + _("Notification of 401 can redirect to another uri"); + did401 = false; + let res12 = new AsyncResource("http://localhost:8080/protected"); + res12.get(function (error, content) { + do_check_eq(error, null); + do_check_eq(res12.spec, "http://localhost:8080/open"); + do_check_eq(content, "This path exists"); + do_check_eq(content.status, 200); + do_check_true(content.success); + do_check_eq(res12.data, content); + do_check_true(did401); + do_check_eq(redirRequest.response, "This path exists and is protected - failed"); + do_check_eq(redirRequest.response.status, 401); + do_check_false(redirRequest.response.success); + + Observers.remove("weave:resource:status:401", redirToOpen); + run_next_test(); + }); +}); + +add_test(function test_401_no_redirect() { + _("Removing the observer should result in the original 401"); + did401 = false; + let res13 = new AsyncResource("http://localhost:8080/protected"); + res13.get(function (error, content) { + do_check_eq(error, null); + do_check_true(did401); + do_check_eq(content, "This path exists and is protected - failed"); + do_check_eq(content.status, 401); + do_check_false(content.success); + run_next_test(); + }); +}); + +add_test(function test_xpc_exception_handling() { + _("Exception handling inside fetches."); + let res14 = new AsyncResource("http://localhost:8080/json"); + res14._onProgress = function(rec) { + // Provoke an XPC exception without a Javascript wrapper. + Services.io.newURI("::::::::", null, null); + }; + let warnings = []; + res14._log.warn = function(msg) { warnings.push(msg); }; + + res14.get(function (error, content) { + do_check_eq(error.result, Cr.NS_ERROR_MALFORMED_URI); + do_check_eq(error.message, "NS_ERROR_MALFORMED_URI"); + do_check_eq(content, null); + do_check_eq(warnings.pop(), + "Got exception calling onProgress handler during fetch of " + + "http://localhost:8080/json"); + + run_next_test(); + }); +}); + +add_test(function test_js_exception_handling() { + _("JS exception handling inside fetches."); + let res15 = new AsyncResource("http://localhost:8080/json"); + res15._onProgress = function(rec) { + throw "BOO!"; + }; + let warnings = []; + res15._log.warn = function(msg) { warnings.push(msg); }; + + res15.get(function (error, content) { + do_check_eq(error.result, Cr.NS_ERROR_XPC_JS_THREW_STRING); + do_check_eq(error.message, "NS_ERROR_XPC_JS_THREW_STRING"); + do_check_eq(content, null); + do_check_eq(warnings.pop(), + "Got exception calling onProgress handler during fetch of " + + "http://localhost:8080/json"); - do_test_finished(); - next(); - })); + run_next_test(); + }); +}); - }, function (next) { +add_test(function test_timeout() { + _("Ensure channel timeouts are thrown appropriately."); + let res19 = new AsyncResource("http://localhost:8080/json"); + res19.ABORT_TIMEOUT = 0; + res19.get(function (error, content) { + do_check_eq(error.result, Cr.NS_ERROR_NET_TIMEOUT); + run_next_test(); + }); +}); - _("JS exception handling inside fetches."); - do_test_pending(); - let res15 = new AsyncResource("http://localhost:8080/json"); - res15._onProgress = function(rec) { - throw "BOO!"; - }; - let warnings = []; - res15._log.warn = function(msg) { warnings.push(msg) }; +add_test(function test_uri_construction() { + _("Testing URI construction."); + let args = []; + args.push("newer=" + 1234); + args.push("limit=" + 1234); + args.push("sort=" + 1234); - res15.get(ensureThrows(function (error, content) { - do_check_eq(error.result, Cr.NS_ERROR_XPC_JS_THREW_STRING); - do_check_eq(error.message, "NS_ERROR_XPC_JS_THREW_STRING"); - do_check_eq(content, null); - do_check_eq(warnings.pop(), - "Got exception calling onProgress handler during fetch of " + - "http://localhost:8080/json"); - - do_test_finished(); - next(); - })); + let query = "?" + args.join("&"); - }, function (next) { + let uri1 = Utils.makeURL("http://foo/" + query); + let uri2 = Utils.makeURL("http://foo/"); + uri2.query = query; + do_check_eq(uri1.query, uri2.query); - _("Ensure channel timeouts are thrown appropriately."); - let res19 = new AsyncResource("http://localhost:8080/json"); - res19.ABORT_TIMEOUT = 0; - res19.get(ensureThrows(function (error, content) { - do_check_eq(error.result, Cr.NS_ERROR_NET_TIMEOUT); - next(); - })); + run_next_test(); +}); - }, function (next) { - - _("Testing URI construction."); - let args = []; - args.push("newer=" + 1234); - args.push("limit=" + 1234); - args.push("sort=" + 1234); - - let query = "?" + args.join("&"); - - let uri1 = Utils.makeURL("http://foo/" + query); - let uri2 = Utils.makeURL("http://foo/"); - uri2.query = query; - do_check_eq(uri1.query, uri2.query); - next(); - - }, function (next) { - - // Don't quit test harness before server shuts down. - server.stop(do_test_finished); - - })(); - -} +add_test(function tear_down() { + server.stop(run_next_test); +}); diff --git a/services/sync/tests/unit/test_service_filelog.js b/services/sync/tests/unit/test_service_filelog.js new file mode 100644 index 000000000000..6a762d4ec11a --- /dev/null +++ b/services/sync/tests/unit/test_service_filelog.js @@ -0,0 +1,159 @@ +/* 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://services-sync/log4moz.js"); + +const logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true); + +function run_test() { + if (DISABLE_TESTS_BUG_664090) { + return; + } + + run_next_test(); +} + +add_test(function test_noOutput() { + // Clear log output from startup. + Svc.Prefs.set("log.appender.file.logOnSuccess", false); + Svc.Obs.notify("weave:service:sync:finish"); + + // Clear again without having issued any output. + Svc.Prefs.set("log.appender.file.logOnSuccess", true); + + Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() { + Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog); + + Svc.Prefs.resetBranch(""); + run_next_test(); + }); + + // Fake a successful sync. + Svc.Obs.notify("weave:service:sync:finish"); +}); + +add_test(function test_logOnSuccess_false() { + Svc.Prefs.set("log.appender.file.logOnSuccess", false); + + let log = Log4Moz.repository.getLogger("Sync.Test.FileLog"); + log.info("this won't show up"); + + Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() { + Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog); + // No log file was written. + do_check_false(logsdir.directoryEntries.hasMoreElements()); + + Svc.Prefs.resetBranch(""); + run_next_test(); + }); + + // Fake a successful sync. + Svc.Obs.notify("weave:service:sync:finish"); +}); + +function readFile(file, callback) { + NetUtil.asyncFetch(file, function (inputStream, statusCode, request) { + let data = NetUtil.readInputStreamToString(inputStream, + inputStream.available()); + callback(statusCode, data); + }); +} + +add_test(function test_logOnSuccess_true() { + Svc.Prefs.set("log.appender.file.logOnSuccess", true); + + let log = Log4Moz.repository.getLogger("Sync.Test.FileLog"); + const MESSAGE = "this WILL show up"; + log.info(MESSAGE); + + Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() { + Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog); + + // Exactly one log file was written. + let entries = logsdir.directoryEntries; + do_check_true(entries.hasMoreElements()); + let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile); + do_check_eq(logfile.leafName.slice(-4), ".log"); + do_check_false(entries.hasMoreElements()); + + // Ensure the log message was actually written to file. + readFile(logfile, function (error, data) { + do_check_true(Components.isSuccessCode(error)); + do_check_neq(data.indexOf(MESSAGE), -1); + + // Clean up. + try { + logfile.remove(false); + } catch(ex) { + dump("Couldn't delete file: " + ex + "\n"); + // Stupid Windows box. + } + + Svc.Prefs.resetBranch(""); + run_next_test(); + }); + }); + + // Fake a successful sync. + Svc.Obs.notify("weave:service:sync:finish"); +}); + +add_test(function test_logOnError_false() { + Svc.Prefs.set("log.appender.file.logOnError", false); + + let log = Log4Moz.repository.getLogger("Sync.Test.FileLog"); + log.info("this won't show up"); + + Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() { + Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog); + // No log file was written. + do_check_false(logsdir.directoryEntries.hasMoreElements()); + + Svc.Prefs.resetBranch(""); + run_next_test(); + }); + + // Fake an unsuccessful sync. + Svc.Obs.notify("weave:service:sync:error"); +}); + +add_test(function test_logOnError_true() { + Svc.Prefs.set("log.appender.file.logOnError", true); + + let log = Log4Moz.repository.getLogger("Sync.Test.FileLog"); + const MESSAGE = "this WILL show up"; + log.info(MESSAGE); + + Svc.Obs.add("weave:service:reset-file-log", function onResetFileLog() { + Svc.Obs.remove("weave:service:reset-file-log", onResetFileLog); + + // Exactly one log file was written. + let entries = logsdir.directoryEntries; + do_check_true(entries.hasMoreElements()); + let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile); + do_check_eq(logfile.leafName.slice(-4), ".log"); + do_check_false(entries.hasMoreElements()); + + // Ensure the log message was actually written to file. + readFile(logfile, function (error, data) { + do_check_true(Components.isSuccessCode(error)); + do_check_neq(data.indexOf(MESSAGE), -1); + + // Clean up. + try { + logfile.remove(false); + } catch(ex) { + dump("Couldn't delete file: " + ex + "\n"); + // Stupid Windows box. + } + + Svc.Prefs.resetBranch(""); + run_next_test(); + }); + }); + + // Fake an unsuccessful sync. + Svc.Obs.notify("weave:service:sync:error"); +}); diff --git a/services/sync/tests/unit/test_service_migratePrefs.js b/services/sync/tests/unit/test_service_migratePrefs.js index d9340c30f21a..d403faff7592 100644 --- a/services/sync/tests/unit/test_service_migratePrefs.js +++ b/services/sync/tests/unit/test_service_migratePrefs.js @@ -1,5 +1,21 @@ Cu.import("resource://services-sync/ext/Preferences.js"); +function test_migrate_logging() { + _("Testing log pref migration."); + Svc.Prefs.set("log.appender.debugLog", "Warn"); + Svc.Prefs.set("log.appender.debugLog.enabled", true); + do_check_true(Svc.Prefs.get("log.appender.debugLog.enabled")); + do_check_eq(Svc.Prefs.get("log.appender.file.level"), "Trace"); + do_check_eq(Svc.Prefs.get("log.appender.file.logOnSuccess"), false); + + Service._migratePrefs(); + + do_check_eq("Warn", Svc.Prefs.get("log.appender.file.level")); + do_check_true(Svc.Prefs.get("log.appender.file.logOnSuccess")); + do_check_eq(Svc.Prefs.get("log.appender.debugLog"), undefined); + do_check_eq(Svc.Prefs.get("log.appender.debugLog.enabled"), undefined); +}; + function run_test() { _("Set some prefs on the old branch"); let globalPref = new Preferences(""); @@ -45,4 +61,6 @@ function run_test() { _("Clearing out pref changes for other tests"); globalPref.resetBranch("extensions.weave."); globalPref.resetBranch("services.sync."); + + test_migrate_logging(); } diff --git a/services/sync/tests/unit/test_syncengine_sync.js b/services/sync/tests/unit/test_syncengine_sync.js index bec19515ca02..545f89ec366e 100644 --- a/services/sync/tests/unit/test_syncengine_sync.js +++ b/services/sync/tests/unit/test_syncengine_sync.js @@ -5,96 +5,8 @@ Cu.import("resource://services-sync/identity.js"); Cu.import("resource://services-sync/resource.js"); Cu.import("resource://services-sync/util.js"); -/* - * A fake engine implementation. - * - * Complete with record, store, and tracker implementations. - */ - -function SteamRecord(collection, id) { - CryptoWrapper.call(this, collection, id); -} -SteamRecord.prototype = { - __proto__: CryptoWrapper.prototype -}; -Utils.deferGetSet(SteamRecord, "cleartext", ["denomination"]); - -function SteamStore() { - Store.call(this, "Steam"); - this.items = {}; -} -SteamStore.prototype = { - __proto__: Store.prototype, - - create: function Store_create(record) { - this.items[record.id] = record.denomination; - }, - - remove: function Store_remove(record) { - delete this.items[record.id]; - }, - - update: function Store_update(record) { - this.items[record.id] = record.denomination; - }, - - itemExists: function Store_itemExists(id) { - return (id in this.items); - }, - - createRecord: function(id, collection) { - var record = new SteamRecord(collection, id); - record.denomination = this.items[id] || "Data for new record: " + id; - return record; - }, - - changeItemID: function(oldID, newID) { - this.items[newID] = this.items[oldID]; - delete this.items[oldID]; - }, - - getAllIDs: function() { - let ids = {}; - for (var id in this.items) { - ids[id] = true; - } - return ids; - }, - - wipe: function() { - this.items = {}; - } -}; - -function SteamTracker() { - Tracker.call(this, "Steam"); -} -SteamTracker.prototype = { - __proto__: Tracker.prototype -}; - - -function SteamEngine() { - SyncEngine.call(this, "Steam"); -} -SteamEngine.prototype = { - __proto__: SyncEngine.prototype, - _storeObj: SteamStore, - _trackerObj: SteamTracker, - _recordObj: SteamRecord, - - _findDupe: function(item) { - for (let [id, value] in Iterator(this._store.items)) { - if (item.denomination == value) { - return id; - } - } - } -}; - - -function makeSteamEngine() { - return new SteamEngine(); +function makeRotaryEngine() { + return new RotaryEngine(); } /* @@ -128,11 +40,11 @@ function test_syncStartup_emptyOrOutdatedGlobalsResetsSync() { denomination: "Flying Scotsman"})); let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine._store.items = {rekolok: "Rekonstruktionslokomotive"}; try { @@ -151,7 +63,7 @@ function test_syncStartup_emptyOrOutdatedGlobalsResetsSync() { engine._syncStartup(); // The meta/global WBO has been filled with data about the engine - let engineData = metaGlobal.payload.engines["steam"]; + let engineData = metaGlobal.payload.engines["rotary"]; do_check_eq(engineData.version, engine.version); do_check_eq(engineData.syncID, engine.syncID); @@ -173,13 +85,13 @@ function test_syncStartup_serverHasNewerVersion() { let syncTesting = new SyncTestingInfrastructure(); Svc.Prefs.set("clusterURL", "http://localhost:8080/"); Svc.Prefs.set("username", "foo"); - let global = new ServerWBO('global', {engines: {steam: {version: 23456}}}); + let global = new ServerWBO('global', {engines: {rotary: {version: 23456}}}); let server = httpd_setup({ "/1.1/foo/storage/meta/global": global.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); try { // The server has a newer version of the data and our engine can @@ -210,9 +122,9 @@ function test_syncStartup_syncIDMismatchResetsClient() { do_test_pending(); // global record with a different syncID than our engine has - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); let global = new ServerWBO('global', - {engines: {steam: {version: engine.version, + {engines: {rotary: {version: engine.version, syncID: 'foobar'}}}); server.registerPathHandler("/1.1/foo/storage/meta/global", global.handler()); @@ -249,11 +161,11 @@ function test_processIncoming_emptyServer() { let collection = new ServerCollection(); let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); try { // Merely ensure that this code path is run without any errors @@ -292,15 +204,15 @@ function test_processIncoming_createFromServer() { denomination: "Pathological Case"})); let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler(), - "/1.1/foo/storage/steam/flying": collection.wbos.flying.handler(), - "/1.1/foo/storage/steam/scotsman": collection.wbos.scotsman.handler() + "/1.1/foo/storage/rotary": collection.handler(), + "/1.1/foo/storage/rotary/flying": collection.wbos.flying.handler(), + "/1.1/foo/storage/rotary/scotsman": collection.wbos.scotsman.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; try { @@ -386,11 +298,11 @@ function test_processIncoming_reconcile() { deleted: true})); let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine._store.items = {newerserver: "New data, but not as new as server!", olderidentical: "Older but identical", updateclient: "Got data?", @@ -403,7 +315,7 @@ function test_processIncoming_reconcile() { engine._tracker.addChangedID('olderidentical', Date.now()/1000); let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; try { @@ -482,13 +394,13 @@ function test_processIncoming_mobile_batchSize() { } let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; try { @@ -555,14 +467,14 @@ function test_processIncoming_store_toFetch() { collection.wbos[id] = wbo; } - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.enabled = true; let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); @@ -629,16 +541,16 @@ function test_processIncoming_resume_toFetch() { collection.wbos.rekolok.modified = LASTSYNC + 10; // Time travel 10 seconds into the future but still download the above WBOs. - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.lastSync = LASTSYNC; engine.toFetch = ["flying", "scotsman"]; engine.previousFailed = ["failed0", "failed1", "failed2"]; let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); @@ -676,7 +588,7 @@ function test_processIncoming_applyIncomingBatchSize_smaller() { // Engine that doesn't like the first and last record it's given. const APPLY_BATCH_SIZE = 10; - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.applyIncomingBatchSize = APPLY_BATCH_SIZE; engine._store._applyIncomingBatch = engine._store.applyIncomingBatch; engine._store.applyIncomingBatch = function (records) { @@ -695,10 +607,10 @@ function test_processIncoming_applyIncomingBatchSize_smaller() { } let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); @@ -735,7 +647,7 @@ function test_processIncoming_applyIncomingBatchSize_multiple() { const APPLY_BATCH_SIZE = 10; // Engine that applies records in batches. - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.applyIncomingBatchSize = APPLY_BATCH_SIZE; let batchCalls = 0; engine._store._applyIncomingBatch = engine._store.applyIncomingBatch; @@ -754,10 +666,10 @@ function test_processIncoming_applyIncomingBatchSize_multiple() { } let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); @@ -792,7 +704,7 @@ function test_processIncoming_failed_items_reported_once() { const NUMBER_OF_RECORDS = 15; // Engine that fails the first record. - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.applyIncomingBatchSize = APPLY_BATCH_SIZE; engine._store._applyIncomingBatch = engine._store.applyIncomingBatch; engine._store.applyIncomingBatch = function (records) { @@ -809,10 +721,10 @@ function test_processIncoming_failed_items_reported_once() { } let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); @@ -881,7 +793,7 @@ function test_processIncoming_previousFailed() { const NUMBER_OF_RECORDS = 14; // Engine that fails the first 2 records. - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.mobileGUIDFetchBatchSize = engine.applyIncomingBatchSize = APPLY_BATCH_SIZE; engine._store._applyIncomingBatch = engine._store.applyIncomingBatch; engine._store.applyIncomingBatch = function (records) { @@ -898,10 +810,10 @@ function test_processIncoming_previousFailed() { } let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); @@ -986,7 +898,7 @@ function test_processIncoming_failed_records() { "record-no-" + (23 + MOBILE_BATCH_SIZE * 2), "record-no-" + (2 + MOBILE_BATCH_SIZE * 3), "record-no-" + (1 + MOBILE_BATCH_SIZE * 3)]; - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.applyIncomingBatchSize = MOBILE_BATCH_SIZE; engine.__reconcile = engine._reconcile; @@ -1005,7 +917,7 @@ function test_processIncoming_failed_records() { }; let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; // Keep track of requests made of a collection. @@ -1020,7 +932,7 @@ function test_processIncoming_failed_records() { }; } let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": recording_handler(collection) + "/1.1/foo/storage/rotary": recording_handler(collection) }); do_test_pending(); @@ -1090,7 +1002,7 @@ function test_processIncoming_failed_records() { server.stop(do_test_finished); Svc.Prefs.resetBranch(""); Records.clearCache(); - syncTesting = new SyncTestingInfrastructure(makeSteamEngine); + syncTesting = new SyncTestingInfrastructure(makeRotaryEngine); } } @@ -1124,16 +1036,16 @@ function test_processIncoming_decrypt_failed() { }; // Some broken records also exist locally. - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.enabled = true; engine._store.items = {nojson: "Valid JSON", nodecrypt: "Valid ciphertext"}; let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); @@ -1185,14 +1097,14 @@ function test_uploadOutgoing_toEmptyServer() { collection.wbos.scotsman = new ServerWBO('scotsman'); let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler(), - "/1.1/foo/storage/steam/flying": collection.wbos.flying.handler(), - "/1.1/foo/storage/steam/scotsman": collection.wbos.scotsman.handler() + "/1.1/foo/storage/rotary": collection.handler(), + "/1.1/foo/storage/rotary/flying": collection.wbos.flying.handler(), + "/1.1/foo/storage/rotary/scotsman": collection.wbos.scotsman.handler() }); do_test_pending(); generateNewKeys(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.lastSync = 123; // needs to be non-zero so that tracker is queried engine._store.items = {flying: "LNER Class A3 4472", scotsman: "Flying Scotsman"}; @@ -1200,7 +1112,7 @@ function test_uploadOutgoing_toEmptyServer() { engine._tracker.addChangedID('scotsman', 0); let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; try { @@ -1247,11 +1159,11 @@ function test_uploadOutgoing_failed() { collection.wbos.flying = new ServerWBO('flying'); let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.lastSync = 123; // needs to be non-zero so that tracker is queried engine._store.items = {flying: "LNER Class A3 4472", scotsman: "Flying Scotsman", @@ -1265,7 +1177,7 @@ function test_uploadOutgoing_failed() { engine._tracker.addChangedID('peppercorn', PEPPERCORN_CHANGED); let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; try { @@ -1296,7 +1208,7 @@ function test_uploadOutgoing_failed() { server.stop(do_test_finished); Svc.Prefs.resetBranch(""); Records.clearCache(); - syncTesting = new SyncTestingInfrastructure(makeSteamEngine); + syncTesting = new SyncTestingInfrastructure(makeRotaryEngine); } } @@ -1319,7 +1231,7 @@ function test_uploadOutgoing_MAX_UPLOAD_RECORDS() { }(collection.post)); // Create a bunch of records (and server side handlers) - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); for (var i = 0; i < 234; i++) { let id = 'record-no-' + i; engine._store.items[id] = "Record No. " + i; @@ -1328,11 +1240,11 @@ function test_uploadOutgoing_MAX_UPLOAD_RECORDS() { } let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); @@ -1356,14 +1268,14 @@ function test_uploadOutgoing_MAX_UPLOAD_RECORDS() { server.stop(do_test_finished); Svc.Prefs.resetBranch(""); Records.clearCache(); - syncTesting = new SyncTestingInfrastructure(makeSteamEngine); + syncTesting = new SyncTestingInfrastructure(makeRotaryEngine); } } function test_syncFinish_noDelete() { _("SyncEngine._syncFinish resets tracker's score"); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine._delete = {}; // Nothing to delete engine._tracker.score = 100; @@ -1391,11 +1303,11 @@ function test_syncFinish_deleteByIds() { denomination: "Rekonstruktionslokomotive"})); let server = httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); try { engine._delete = {ids: ['flying', 'rekolok']}; engine._syncFinish(); @@ -1445,11 +1357,11 @@ function test_syncFinish_deleteLotsInBatches() { } let server = httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); try { // Confirm initial environment @@ -1500,12 +1412,12 @@ function test_sync_partialUpload() { let collection = new ServerCollection(); let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); generateNewKeys(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); engine.lastSync = 123; // needs to be non-zero so that tracker is queried engine.lastSyncLocal = 456; @@ -1531,7 +1443,7 @@ function test_sync_partialUpload() { } let meta_global = Records.set(engine.metaURL, new WBORecord(engine.metaURL)); - meta_global.payload.engines = {steam: {version: engine.version, + meta_global.payload.engines = {rotary: {version: engine.version, syncID: engine.syncID}}; try { @@ -1582,11 +1494,11 @@ function test_canDecrypt_noCryptoKeys() { denomination: "LNER Class A3 4472"})); let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); try { do_check_false(engine.canDecrypt()); @@ -1613,11 +1525,11 @@ function test_canDecrypt_true() { denomination: "LNER Class A3 4472"})); let server = sync_httpd_setup({ - "/1.1/foo/storage/steam": collection.handler() + "/1.1/foo/storage/rotary": collection.handler() }); do_test_pending(); - let engine = makeSteamEngine(); + let engine = makeRotaryEngine(); try { do_check_true(engine.canDecrypt()); diff --git a/services/sync/tests/unit/test_utils_namedTimer.js b/services/sync/tests/unit/test_utils_namedTimer.js new file mode 100644 index 000000000000..34601360f7a9 --- /dev/null +++ b/services/sync/tests/unit/test_utils_namedTimer.js @@ -0,0 +1,69 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +Cu.import("resource://services-sync/util.js"); + +function run_test() { + run_next_test(); +} + +add_test(function test_required_args() { + try { + Utils.namedTimer(function callback() { + do_throw("Shouldn't fire."); + }, 0); + do_throw("Should have thrown!"); + } catch(ex) { + run_next_test(); + } +}); + +add_test(function test_simple() { + _("Test basic properties of Utils.namedTimer."); + + const delay = 200; + let that = {}; + let t0 = Date.now(); + Utils.namedTimer(function callback(timer) { + do_check_eq(this, that); + do_check_eq(this._zetimer, null); + do_check_true(timer instanceof Ci.nsITimer); + // Difference should be ~delay, but hard to predict on all platforms, + // particularly Windows XP. + do_check_true(Date.now() > t0); + run_next_test(); + }, delay, that, "_zetimer"); +}); + +add_test(function test_delay() { + _("Test delaying a timer that hasn't fired yet."); + + const delay = 100; + let that = {}; + let t0 = Date.now(); + function callback(timer) { + // Difference should be ~2*delay, but hard to predict on all platforms, + // particularly Windows XP. + do_check_true((Date.now() - t0) > delay); + run_next_test(); + } + Utils.namedTimer(callback, delay, that, "_zetimer"); + Utils.namedTimer(callback, 2 * delay, that, "_zetimer"); + run_next_test(); +}); + +add_test(function test_clear() { + _("Test clearing a timer that hasn't fired yet."); + + const delay = 0; + let that = {}; + Utils.namedTimer(function callback(timer) { + do_throw("Shouldn't fire!"); + }, delay, that, "_zetimer"); + + that._zetimer.clear(); + do_check_eq(that._zetimer, null); + Utils.nextTick(run_next_test); + + run_next_test(); +}); diff --git a/services/sync/tests/unit/xpcshell.ini b/services/sync/tests/unit/xpcshell.ini index 92cb6c47304e..26d72627cd5b 100644 --- a/services/sync/tests/unit/xpcshell.ini +++ b/services/sync/tests/unit/xpcshell.ini @@ -50,6 +50,7 @@ tail = [test_service_cluster.js] [test_service_createAccount.js] [test_service_detect_upgrade.js] +[test_service_filelog.js] [test_service_login.js] [test_service_migratePrefs.js] [test_service_passwordUTF8.js] @@ -92,6 +93,7 @@ tail = [test_utils_lock.js] [test_utils_makeGUID.js] [test_utils_makeURI.js] +[test_utils_namedTimer.js] [test_utils_notify.js] [test_utils_passphrase.js] [test_utils_pbkdf2.js] diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index 4af2f6f96f87..59766805d7ac 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -119,13 +119,17 @@ ifeq ($(MOZ_PKG_FORMAT),SFX7Z) PKG_SUFFIX = .exe INNER_MAKE_PACKAGE = rm -f app.7z && \ mv $(MOZ_PKG_DIR) core && \ + (if [ -f ../optional_file_list.txt ]; then mkdir optional; xargs -I {} -a ../optional_file_list.txt mv -t optional/ core/{}; fi;) && \ $(CYGWIN_WRAPPER) 7z a -r -t7z app.7z -mx -m0=BCJ2 -m1=LZMA:d24 \ -m2=LZMA:d19 -m3=LZMA:d19 -mb0:1 -mb0s1:2 -mb0s2:3 && \ mv core $(MOZ_PKG_DIR) && \ + (if [ -d optional ]; then mv optional/* $(MOZ_PKG_DIR); rm -rf optional; fi;) && \ cat $(SFX_HEADER) app.7z > $(PACKAGE) && \ chmod 0755 $(PACKAGE) INNER_UNMAKE_PACKAGE = $(CYGWIN_WRAPPER) 7z x $(UNPACKAGE) core && \ - mv core $(MOZ_PKG_DIR) + rm -f ../optional_file_list.txt && \ + mv core $(MOZ_PKG_DIR) && \ + (if [ -d optional ]; then ls -1 optional > ../optional_file_list.txt; cp -rp optional/* $(MOZ_PKG_DIR); rm -rf optional; fi;) endif #Create an RPM file diff --git a/toolkit/mozapps/plugins/tests/browser_bug435788.js b/toolkit/mozapps/plugins/tests/browser_bug435788.js index 0efd70f246e7..d796401b6bef 100644 --- a/toolkit/mozapps/plugins/tests/browser_bug435788.js +++ b/toolkit/mozapps/plugins/tests/browser_bug435788.js @@ -1,24 +1,17 @@ -const Cc = Components.classes; -const Ci = Components.interfaces; - const TEST_ROOT = "http://example.com/browser/toolkit/mozapps/plugins/tests/"; Components.utils.import("resource://gre/modules/AddonManager.jsm"); -var gPrefs, gPFS, gDS, gSeenAvailable; +var gPFS; function test() { waitForExplicitFinish(); - gPrefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - gDS = Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties); prepare_test_1(); } -function finishTest(e) { - gPrefs.clearUserPref("pfs.datasource.url"); +function finishTest() { + Services.prefs.clearUserPref("pfs.datasource.url"); finish(); } @@ -104,10 +97,70 @@ function pfs_loaded() { page_shown(); } +function startTest(num, missingPluginsArray) { + info("Test " + num); + + gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", + "PFSWindow", "chrome,centerscreen,resizable=yes", + {plugins: missingPluginsArray}); + + var testScope = this; + + gPFS.addEventListener("load", function () { + gPFS.removeEventListener("load", arguments.callee, false); + + pfs_loaded(); + + var seenAvailable = false; + var expectAvailable = typeof testScope["test_" + num + "_available"] == "function"; + + function availableListener() { + seenAvailable = true; + + if (expectAvailable) { + executeSoon(function () { + testScope["test_" + num + "_available"](); + gPFS.document.documentElement.getButton("next").click(); + }); + } else { + ok(false, "Should not have found plugins to install"); + } + } + + function completeListener() { + if (expectAvailable) + ok(seenAvailable, "Should have seen the list of available plugins"); + + executeSoon(testScope["test_" + num + "_complete"]); + } + + gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", availableListener); + gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", completeListener); + + gPFS.addEventListener("unload", function () { + gPFS.removeEventListener("unload", arguments.callee, false); + gPFS.document.documentElement.wizardPages[1].removeEventListener("pageshow", availableListener, false); + gPFS.document.documentElement.wizardPages[4].removeEventListener("pageshow", completeListener, false); + + num++; + if (typeof testScope["prepare_test_" + num] == "function") + testScope["prepare_test_" + num](); + else + finishTest(); + }); + }); +} + +function clickFinish() { + var finish = gPFS.document.documentElement.getButton("finish"); + ok(!finish.hidden, "Finish button should not be hidden"); + ok(!finish.disabled, "Finish button should not be disabled"); + finish.click(); +} + // Test a working installer function prepare_test_1() { - ok(true, "Test 1"); - gPrefs.setCharPref("pfs.datasource.url", TEST_ROOT + "pfs_bug435788_1.rdf"); + Services.prefs.setCharPref("pfs.datasource.url", TEST_ROOT + "pfs_bug435788_1.rdf"); var missingPluginsArray = { "application/x-working-plugin": { @@ -116,56 +169,25 @@ function prepare_test_1() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_1_start, false); -} - -function test_1_start() { - gPFS.removeEventListener("load", test_1_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - prepare_test_2(); - }, false); - gSeenAvailable = false; - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_1_available); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_1_complete); - }, false); + startTest(1, missingPluginsArray); } function test_1_available() { - gSeenAvailable = true; is(getListCount(), 1, "Should have found 1 plugin to install"); ok(hasListItem("Test plugin 1", null), "Should have seen the right plugin name"); - - gPFS.document.documentElement.getButton("next").click(); } function test_1_complete() { - ok(gSeenAvailable, "Should have seen the list of available plugins"); is(getResultCount(), 1, "Should have attempted to install 1 plugin"); var item = getResultItem("Test plugin 1", null); ok(item, "Should have seen the installed item"); is(item.status, "Installed", "Should have been a successful install"); - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); + clickFinish(); } // Test a broken installer (returns exit code 1) function prepare_test_2() { - ok(true, "Test 2"); var missingPluginsArray = { "application/x-broken-installer": { mimetype: "application/x-broken-installer", @@ -173,56 +195,25 @@ function prepare_test_2() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_2_start, false); -} - -function test_2_start() { - gPFS.removeEventListener("load", test_2_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - prepare_test_3(); - }, false); - gSeenAvailable = false; - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_2_available); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_2_complete); - }, false); + startTest(2, missingPluginsArray); } function test_2_available() { - gSeenAvailable = true; is(getListCount(), 1, "Should have found 1 plugin to install"); ok(hasListItem("Test plugin 2", null), "Should have seen the right plugin name"); - - gPFS.document.documentElement.getButton("next").click(); } function test_2_complete() { - ok(gSeenAvailable, "Should have seen the list of available plugins"); is(getResultCount(), 1, "Should have attempted to install 1 plugin"); var item = getResultItem("Test plugin 2", null); ok(item, "Should have seen the installed item"); is(item.status, "Failed", "Should have been a failed install"); - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); + clickFinish(); } // Test both working and broken together function prepare_test_3() { - ok(true, "Test 3"); var missingPluginsArray = { "application/x-working-plugin": { mimetype: "application/x-working-plugin", @@ -234,43 +225,16 @@ function prepare_test_3() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_3_start, false); -} - -function test_3_start() { - gPFS.removeEventListener("load", test_3_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - prepare_test_4(); - }, false); - gSeenAvailable = false; - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_3_available); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_3_complete); - }, false); + startTest(3, missingPluginsArray); } function test_3_available() { - gSeenAvailable = true; is(getListCount(), 2, "Should have found 2 plugins to install"); ok(hasListItem("Test plugin 1", null), "Should have seen the right plugin name"); ok(hasListItem("Test plugin 2", null), "Should have seen the right plugin name"); - - gPFS.document.documentElement.getButton("next").click(); } function test_3_complete() { - ok(gSeenAvailable, "Should have seen the list of available plugins"); is(getResultCount(), 2, "Should have attempted to install 2 plugins"); var item = getResultItem("Test plugin 1", null); ok(item, "Should have seen the installed item"); @@ -279,15 +243,11 @@ function test_3_complete() { ok(item, "Should have seen the installed item"); is(item.status, "Failed", "Should have been a failed install"); - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); + clickFinish(); } // Test an installer with a bad hash function prepare_test_4() { - ok(true, "Test 4"); var missingPluginsArray = { "application/x-broken-plugin-hash": { mimetype: "application/x-broken-plugin-hash", @@ -295,57 +255,25 @@ function prepare_test_4() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_4_start, false); -} - -function test_4_start() { - gPFS.removeEventListener("load", test_4_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - prepare_test_5(); - }, false); - gSeenAvailable = false; - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_4_available); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_4_complete); - }, false); + startTest(4, missingPluginsArray); } function test_4_available() { - gSeenAvailable = true; is(getListCount(), 1, "Should have found 1 plugin to install"); ok(hasListItem("Test plugin 3", null), "Should have seen the right plugin name"); - - gPFS.document.documentElement.getButton("next").click(); } function test_4_complete() { - ok(gSeenAvailable, "Should have seen the list of available plugins"); is(getResultCount(), 1, "Should have attempted to install 1 plugin"); var item = getResultItem("Test plugin 3", null); ok(item, "Should have seen the installed item"); is(item.status, "Failed", "Should have not been a successful install"); - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); + clickFinish(); } // Test a working xpi function prepare_test_5() { - ok(true, "Test 5"); - var missingPluginsArray = { "application/x-working-extension": { mimetype: "application/x-working-extension", @@ -353,42 +281,15 @@ function prepare_test_5() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_5_start, false); -} - -function test_5_start() { - gPFS.removeEventListener("load", test_5_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - prepare_test_6(); - }, false); - gSeenAvailable = false; - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_5_available); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_5_complete); - }, false); + startTest(5, missingPluginsArray); } function test_5_available() { - gSeenAvailable = true; is(getListCount(), 1, "Should have found 1 plugin to install"); ok(hasListItem("Test extension 1", null), "Should have seen the right plugin name"); - - gPFS.document.documentElement.getButton("next").click(); } function test_5_complete() { - ok(gSeenAvailable, "Should have seen the list of available plugins"); is(getResultCount(), 1, "Should have attempted to install 1 plugin"); var item = getResultItem("Test extension 1", null); ok(item, "Should have seen the installed item"); @@ -400,16 +301,12 @@ function test_5_complete() { is(installs[0].addon.id, "bug435788_1@tests.mozilla.org", "Should have installed the extension"); installs[0].cancel(); - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); + clickFinish(); }); } // Test a broke xpi (no install.rdf) function prepare_test_6() { - ok(true, "Test 6"); var missingPluginsArray = { "application/x-broken-extension": { mimetype: "application/x-broken-extension", @@ -417,56 +314,25 @@ function prepare_test_6() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_6_start, false); -} - -function test_6_start() { - gPFS.removeEventListener("load", test_6_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - prepare_test_7(); - }, false); - gSeenAvailable = false; - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_6_available); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_6_complete); - }, false); + startTest(6, missingPluginsArray); } function test_6_available() { - gSeenAvailable = true; is(getListCount(), 1, "Should have found 1 plugin to install"); ok(hasListItem("Test extension 2", null), "Should have seen the right plugin name"); - - gPFS.document.documentElement.getButton("next").click(); } function test_6_complete() { - ok(gSeenAvailable, "Should have seen the list of available plugins"); is(getResultCount(), 1, "Should have attempted to install 1 plugin"); var item = getResultItem("Test extension 2", null); ok(item, "Should have seen the installed item"); is(item.status, "Failed", "Should have been a failed install"); - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); + clickFinish(); } // Test both working and broken xpi function prepare_test_7() { - ok(true, "Test 7"); var missingPluginsArray = { "application/x-working-extension": { mimetype: "application/x-working-extension", @@ -478,43 +344,16 @@ function prepare_test_7() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_7_start, false); -} - -function test_7_start() { - gPFS.removeEventListener("load", test_7_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - prepare_test_8(); - }, false); - gSeenAvailable = false; - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_7_available); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_7_complete); - }, false); + startTest(7, missingPluginsArray); } function test_7_available() { - gSeenAvailable = true; is(getListCount(), 2, "Should have found 2 plugins to install"); ok(hasListItem("Test extension 1", null), "Should have seen the right plugin name"); ok(hasListItem("Test extension 2", null), "Should have seen the right plugin name"); - - gPFS.document.documentElement.getButton("next").click(); } function test_7_complete() { - ok(gSeenAvailable, "Should have seen the list of available plugins"); is(getResultCount(), 2, "Should have attempted to install 2 plugins"); var item = getResultItem("Test extension 1", null); ok(item, "Should have seen the installed item"); @@ -527,18 +366,12 @@ function test_7_complete() { is(installs.length, 1, "Should be one active installs"); installs[0].cancel(); - gPFS.document.documentElement.getButton("finish").click(); + clickFinish(); }); - - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); } // Test an xpi with a bad hash function prepare_test_8() { - ok(true, "Test 8"); var missingPluginsArray = { "application/x-broken-extension-hash": { mimetype: "application/x-broken-extension-hash", @@ -546,42 +379,15 @@ function prepare_test_8() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_8_start, false); -} - -function test_8_start() { - gPFS.removeEventListener("load", test_8_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - prepare_test_9(); - }, false); - gSeenAvailable = false; - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_8_available); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_8_complete); - }, false); + startTest(8, missingPluginsArray); } function test_8_available() { - gSeenAvailable = true; is(getListCount(), 1, "Should have found 1 plugin to install"); ok(hasListItem("Test extension 3", null), "Should have seen the right plugin name"); - - gPFS.document.documentElement.getButton("next").click(); } function test_8_complete() { - ok(gSeenAvailable, "Should have seen the list of available plugins"); is(getResultCount(), 1, "Should have attempted to install 1 plugin"); var item = getResultItem("Test extension 3", null); ok(item, "Should have seen the installed item"); @@ -590,18 +396,12 @@ function test_8_complete() { AddonManager.getAllInstalls(function(installs) { is(installs.length, 0, "Should not be any installs"); - gPFS.document.documentElement.getButton("finish").click(); + clickFinish(); }); - - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); } // Test when no plugin exists in the datasource function prepare_test_9() { - ok(true, "Test 9"); var missingPluginsArray = { "application/x-unknown-plugin": { mimetype: "application/x-unknown-plugin", @@ -609,44 +409,18 @@ function prepare_test_9() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_9_start, false); -} - -function test_9_start() { - gPFS.removeEventListener("load", test_9_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - prepare_test_10(); - }, false); - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - ok(false, "Should not have found plugins to install"); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_9_complete); - }, false); + startTest(9, missingPluginsArray); } function test_9_complete() { is(getResultCount(), 0, "Should have found no plugins"); - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); + clickFinish(); } // Test when the datasource is invalid xml function prepare_test_10() { - ok(true, "Test 10"); - gPrefs.setCharPref("pfs.datasource.url", TEST_ROOT + "pfs_bug435788_2.rdf"); + Services.prefs.setCharPref("pfs.datasource.url", TEST_ROOT + "pfs_bug435788_2.rdf"); var missingPluginsArray = { "application/x-broken-xml": { @@ -655,44 +429,18 @@ function prepare_test_10() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_10_start, false); -} - -function test_10_start() { - gPFS.removeEventListener("load", test_10_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - prepare_test_11(); - }, false); - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - ok(false, "Should not have found plugins to install"); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_10_complete); - }, false); + startTest(10, missingPluginsArray); } function test_10_complete() { is(getResultCount(), 0, "Should have found no plugins"); - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); + clickFinish(); } // Test when no datasource is returned function prepare_test_11() { - ok(true, "Test 11"); - gPrefs.setCharPref("pfs.datasource.url", TEST_ROOT + "pfs_bug435788_foo.rdf"); + Services.prefs.setCharPref("pfs.datasource.url", TEST_ROOT + "pfs_bug435788_foo.rdf"); var missingPluginsArray = { "application/x-missing-xml": { @@ -701,36 +449,11 @@ function prepare_test_11() { } }; - gPFS = window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", - "PFSWindow", "chrome,centerscreen,resizable=yes", - {plugins: missingPluginsArray}); - gPFS.addEventListener("load", test_11_start, false); -} - -function test_11_start() { - gPFS.removeEventListener("load", test_11_start, false); - - pfs_loaded(); - gPFS.addEventListener("unload", function () { - gPFS.removeEventListener("unload", arguments.callee, false); - finishTest(); - }, false); - - gPFS.document.documentElement.wizardPages[1].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - ok(false, "Should not have found plugins to install"); - }, false); - gPFS.document.documentElement.wizardPages[4].addEventListener("pageshow", function(e) { - e.currentTarget.removeEventListener(e.type, arguments.callee, false); - executeSoon(test_11_complete); - }, false); + startTest(11, missingPluginsArray); } function test_11_complete() { is(getResultCount(), 0, "Should have found no plugins"); - var finish = gPFS.document.documentElement.getButton("finish"); - ok(!finish.hidden, "Finish button should not be hidden"); - ok(!finish.disabled, "Finish button should not be disabled"); - finish.click(); + clickFinish(); } diff --git a/toolkit/mozapps/shared/FileUtils.jsm b/toolkit/mozapps/shared/FileUtils.jsm index 2f7f5bcf59f8..27f3bd6e4170 100644 --- a/toolkit/mozapps/shared/FileUtils.jsm +++ b/toolkit/mozapps/shared/FileUtils.jsm @@ -21,6 +21,7 @@ # # Contributor(s): # Robert Strong +# Philipp von Weitershausen # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or @@ -103,6 +104,22 @@ var FileUtils = { return dir; }, + /** + * Opens a file output stream for writing. + * @param file + * The file to write to. + * @param modeFlags + * (optional) File open flags. Can be undefined. + * @returns nsIFileOutputStream to write to. + * @note The stream is initialized with the DEFER_OPEN behavior flag. + * See nsIFileOutputStream. + */ + openFileOutputStream: function FileUtils_openFileOutputStream(file, modeFlags) { + var fos = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + return this._initFileOutputStream(fos, file, modeFlags); + }, + /** * Opens a safe file output stream for writing. * @param file @@ -116,6 +133,10 @@ var FileUtils = { openSafeFileOutputStream: function FileUtils_openSafeFileOutputStream(file, modeFlags) { var fos = Cc["@mozilla.org/network/safe-file-output-stream;1"]. createInstance(Ci.nsIFileOutputStream); + return this._initFileOutputStream(fos, file, modeFlags); + }, + + _initFileOutputStream: function FileUtils__initFileOutputStream(fos, file, modeFlags) { if (modeFlags === undefined) modeFlags = this.MODE_WRONLY | this.MODE_CREATE | this.MODE_TRUNCATE; fos.init(file, modeFlags, this.PERMS_FILE, fos.DEFER_OPEN); diff --git a/toolkit/mozapps/shared/test/unit/test_FileUtils.js b/toolkit/mozapps/shared/test/unit/test_FileUtils.js index 3e7bf8b67598..832ed84e305d 100644 --- a/toolkit/mozapps/shared/test/unit/test_FileUtils.js +++ b/toolkit/mozapps/shared/test/unit/test_FileUtils.js @@ -91,6 +91,44 @@ add_test(function test_getDir_shouldCreate() { run_next_test(); }); +add_test(function test_openFileOutputStream_defaultFlags() { + let file = FileUtils.getFile("ProfD", ["george"]); + let fos = FileUtils.openFileOutputStream(file); + do_check_true(fos instanceof Components.interfaces.nsIFileOutputStream); + + // FileUtils.openFileOutputStream() opens the stream with DEFER_OPEN + // which means the file will not be open until we write to it. + do_check_false(file.exists()); + + let data = "imagine"; + fos.write(data, data.length); + do_check_true(file.exists()); + + // No nsIXULRuntime in xpcshell, so use this trick to determine whether we're + // on Windows. + if ("@mozilla.org/windows-registry-key;1" in Components.classes) { + do_check_eq(file.permissions, 0666); + } else { + do_check_eq(file.permissions, FileUtils.PERMS_FILE); + } + + run_next_test(); +}); + +// openFileOutputStream will uses MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE +// as the default mode flags, but we can pass in our own if we want to. +add_test(function test_openFileOutputStream_modeFlags() { + let file = FileUtils.getFile("ProfD", ["ringo"]); + let fos = FileUtils.openFileOutputStream(file, FileUtils.MODE_WRONLY); + let data = "yesterday"; + do_check_throws(function () { + fos.write(data, data.length); + }, Components.results.NS_ERROR_FILE_NOT_FOUND); + do_check_false(file.exists()); + + run_next_test(); +}); + add_test(function test_openSafeFileOutputStream_defaultFlags() { let file = FileUtils.getFile("ProfD", ["john"]); let fos = FileUtils.openSafeFileOutputStream(file); diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index 07d9df9efd1d..0713273c5012 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -311,7 +311,6 @@ MAKEFILES_libreg=" modules/libreg/Makefile modules/libreg/include/Makefile modules/libreg/src/Makefile - modules/libreg/standalone/Makefile " MAKEFILES_libpref=" diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 3e2897b4c3bf..317ef6f7b8ad 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -1047,12 +1047,12 @@ struct nsCycleCollector nsICycleCollectorListener *aListener); // Prepare for and cleanup after one or more collection(s). - PRBool PrepareForCollection(nsTPtrArray *aWhiteNodes); + PRBool PrepareForCollection(nsTPtrArray *aWhiteNodes, + PRBool aForceGC); void CleanupAfterCollection(); // Start and finish an individual collection. - PRBool BeginCollection(PRBool aForceGC, - nsICycleCollectorListener *aListener); + PRBool BeginCollection(nsICycleCollectorListener *aListener); PRBool FinishCollection(); PRUint32 SuspectedCount(); @@ -2499,8 +2499,12 @@ nsCycleCollector::Freed(void *n) #endif PRBool -nsCycleCollector::PrepareForCollection(nsTPtrArray *aWhiteNodes) +nsCycleCollector::PrepareForCollection(nsTPtrArray *aWhiteNodes, + PRBool aForceGC) { + NS_ASSERTION(NS_IsMainThread(), + "PrepareForCollection must be called on the main thread."); + #if defined(DEBUG_CC) && !defined(__MINGW32__) if (!mParams.mDoNothing && mParams.mHookMalloc) InitMemHook(); @@ -2529,6 +2533,29 @@ nsCycleCollector::PrepareForCollection(nsTPtrArray *aWhiteNodes) mWhiteNodes = aWhiteNodes; + // The cycle collector uses the mark bitmap to discover what JS objects + // were reachable only from XPConnect roots that might participate in + // cycles. We ask the JS runtime whether we need to force a GC before + // this CC. It returns true on startup (before the mark bits have been set), + // and also when UnmarkGray has run out of stack. + if (mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]) { + nsCycleCollectionJSRuntime* rt = + static_cast + (mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]); + if (rt->NeedCollect() || aForceGC) { +#ifdef COLLECT_TIME_DEBUG + PRTime start = PR_Now(); +#endif + // rt->Collect() must be called from the main thread, + // because it invokes XPCJSRuntime::GCCallback(cx, JSGC_BEGIN) + // which returns false if not in the main thread. + rt->Collect(); +#ifdef COLLECT_TIME_DEBUG + printf("cc: GC() took %lldms\n", (PR_Now() - start) / PR_USEC_PER_MSEC); +#endif + } + } + return PR_TRUE; } @@ -2563,13 +2590,13 @@ nsCycleCollector::Collect(PRUint32 aTryCollections, { nsAutoTPtrArray whiteNodes; - if (!PrepareForCollection(&whiteNodes)) + if (!PrepareForCollection(&whiteNodes, PR_TRUE)) return 0; PRUint32 totalCollections = 0; while (aTryCollections > totalCollections) { // Synchronous cycle collection. Always force a JS GC as well. - if (!(BeginCollection(PR_TRUE, aListener) && FinishCollection())) + if (!(BeginCollection(aListener) && FinishCollection())) break; ++totalCollections; @@ -2581,32 +2608,11 @@ nsCycleCollector::Collect(PRUint32 aTryCollections, } PRBool -nsCycleCollector::BeginCollection(PRBool aForceGC, - nsICycleCollectorListener *aListener) +nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener) { if (mParams.mDoNothing) return PR_FALSE; - // The cycle collector uses the mark bitmap to discover what JS objects - // were reachable only from XPConnect roots that might participate in - // cycles. We ask the JS runtime whether we need to force a GC before - // this CC. It returns true on startup (before the mark bits have been set), - // and also when UnmarkGray has run out of stack. - if (mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]) { - nsCycleCollectionJSRuntime* rt = - static_cast - (mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]); - if (rt->NeedCollect() || aForceGC) { -#ifdef COLLECT_TIME_DEBUG - PRTime start = PR_Now(); -#endif - rt->Collect(); -#ifdef COLLECT_TIME_DEBUG - printf("cc: GC() took %lldms\n", (PR_Now() - start) / PR_USEC_PER_MSEC); -#endif - } - } - if (aListener && NS_FAILED(aListener->Begin())) { aListener = nsnull; } @@ -3358,7 +3364,7 @@ public: return NS_OK; } - mCollected = mCollector->BeginCollection(PR_FALSE, mListener); + mCollected = mCollector->BeginCollection(mListener); mReply.Notify(); } @@ -3389,7 +3395,7 @@ public: return 0; nsAutoTPtrArray whiteNodes; - if (!mCollector->PrepareForCollection(&whiteNodes)) + if (!mCollector->PrepareForCollection(&whiteNodes, PR_FALSE)) return 0; NS_ASSERTION(!mListener, "Should have cleared this already!"); diff --git a/xulrunner/installer/Makefile.in b/xulrunner/installer/Makefile.in index 688d401cf966..77caf533d0b3 100644 --- a/xulrunner/installer/Makefile.in +++ b/xulrunner/installer/Makefile.in @@ -90,7 +90,7 @@ FULL_NSPR_LIBS=$(subst $(prefix),\$${sdkdir},$(shell $(DEPTH)/nsprpub/config/nsp NSPR_VERSION=$(shell $(DEPTH)/nsprpub/config/nspr-config --version) endif -MOZ_XUL_LINK = -lxpcomglue_s -lxul -lxpcom +MOZ_XUL_LINK = -lxpcomglue_s -lxul -lxpcom -lmozalloc ifdef JS_SHARED_LIBRARY MOZ_JS_LINK = -lmozjs else