diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 1084b556b8..2372dff9af 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -324,7 +324,9 @@ @RESPATH@/components/toolkit_finalizationwitness.xpt @RESPATH@/components/toolkit_formautofill.xpt @RESPATH@/components/toolkit_osfile.xpt +#ifdef NIGHTLY_BUILD @RESPATH@/components/toolkit_perfmonitoring.xpt +#endif @RESPATH@/components/toolkit_xulstore.xpt @RESPATH@/components/toolkitprofile.xpt #ifdef MOZ_ENABLE_XREMOTE diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 6ebfe85f37..d5548217bb 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -1158,7 +1158,12 @@ nsContextMenu.prototype = { // set up a channel to do the saving var ioService = Cc["@mozilla.org/network/io-service;1"]. getService(Ci.nsIIOService); - var channel = ioService.newChannelFromURI(makeURI(linkURL)); + var channel = ioService.newChannelFromURI2(makeURI(linkURL), + doc, + null, // aLoadingPrincipal + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); if (linkDownload) channel.contentDispositionFilename = linkDownload; if (channel instanceof Ci.nsIPrivateBrowsingChannel) { diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index cca3357bbe..6b4e9d7f46 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -9,11 +9,6 @@ %tabBrowserDTD; ]> -# MAKE_E10S_WORK surrounds code needed to have the front-end try to be smart -# about using non-remote browsers for loading certain URIs when remote tabs -# (browser.tabs.remote) are enabled. -#define MAKE_E10S_WORK 1 - + + (Components.utils.import("resource://gre/modules/AppConstants.jsm", {})).AppConstants; + document.getAnonymousElementByAttribute(this, "anonid", "tabbox"); @@ -118,11 +116,7 @@ new Map(); -#ifdef XP_MACOSX - true -#else - false -#endif + this.AppConstants.platform == "macosx"; @@ -1387,7 +1381,6 @@ ]]> -#ifdef MAKE_E10S_WORK @@ -1454,7 +1447,6 @@ ]]> -#endif @@ -1502,11 +1494,11 @@ t.setAttribute("validate", "never"); //PMed t.setAttribute("onerror", "this.removeAttribute('image');"); t.className = "tabbrowser-tab"; -#ifdef MAKE_E10S_WORK - let remote = this._shouldBrowserBeRemote(aURI); -#else - let remote = gMultiProcessBrowser; -#endif + if (this.AppConstants.E10S_TESTING_ONLY) { + let remote = this._shouldBrowserBeRemote(aURI); + } else { + let remote = gMultiProcessBrowser; + } if (remote) t.setAttribute("remote", "true"); @@ -2755,17 +2747,17 @@ @@ -2779,17 +2771,17 @@ @@ -3017,30 +3009,30 @@ } } -#ifdef XP_MACOSX - if (!aEvent.metaKey) - return; + if (this.AppConstants.platform == "macosx") { + if (!aEvent.metaKey) + return; - var offset = 1; - switch (aEvent.charCode) { - case '}'.charCodeAt(0): - offset = -1; - case '{'.charCodeAt(0): - if (window.getComputedStyle(this, null).direction == "ltr") - offset *= -1; - this.tabContainer.advanceSelectedTab(offset, true); + var offset = 1; + switch (aEvent.charCode) { + case '}'.charCodeAt(0): + offset = -1; + case '{'.charCodeAt(0): + if (window.getComputedStyle(this, null).direction == "ltr") + offset *= -1; + this.tabContainer.advanceSelectedTab(offset, true); + aEvent.stopPropagation(); + aEvent.preventDefault(); + } + } else { + if (aEvent.ctrlKey && !aEvent.shiftKey && !aEvent.metaKey && + aEvent.keyCode == KeyEvent.DOM_VK_F4 && + !this.mCurrentTab.pinned) { + this.removeCurrentTab({animate: true}); aEvent.stopPropagation(); aEvent.preventDefault(); + } } -#else - if (aEvent.ctrlKey && !aEvent.shiftKey && !aEvent.metaKey && - aEvent.keyCode == KeyEvent.DOM_VK_F4 && - !this.mCurrentTab.pinned) { - this.removeCurrentTab({animate: true}); - aEvent.stopPropagation(); - aEvent.preventDefault(); - } -#endif ]]> @@ -3409,15 +3401,16 @@ -# This is a hack to circumvent bug 472020, otherwise the tabs show up on the -# right of the newtab button. + -# This is to ensure anything extensions put here will go before the newtab -# button, necessary due to the previous hack. + diff --git a/browser/base/jar.mn b/browser/base/jar.mn index fb2207ac08..35943c3c0a 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -102,13 +102,13 @@ browser.jar: content/browser/openLocation.xul (content/openLocation.xul) content/browser/safeMode.css (content/safeMode.css) content/browser/safeMode.js (content/safeMode.js) -* content/browser/safeMode.xul (content/safeMode.xul) + content/browser/safeMode.xul (content/safeMode.xul) * content/browser/sanitize.js (content/sanitize.js) * content/browser/sanitize.xul (content/sanitize.xul) * content/browser/sanitizeDialog.js (content/sanitizeDialog.js) content/browser/sanitizeDialog.css (content/sanitizeDialog.css) content/browser/tabbrowser.css (content/tabbrowser.css) -* content/browser/tabbrowser.xml (content/tabbrowser.xml) + content/browser/tabbrowser.xml (content/tabbrowser.xml) * content/browser/urlbarBindings.xml (content/urlbarBindings.xml) * content/browser/utilityOverlay.js (content/utilityOverlay.js) content/browser/web-panels.js (content/web-panels.js) diff --git a/browser/components/migration/ChromeProfileMigrator.js b/browser/components/migration/ChromeProfileMigrator.js index 61955fbb49..2c6b6aebca 100644 --- a/browser/components/migration/ChromeProfileMigrator.js +++ b/browser/components/migration/ChromeProfileMigrator.js @@ -201,7 +201,7 @@ function GetBookmarksResource(aProfileFolder) { type: MigrationUtils.resourceTypes.BOOKMARKS, migrate: function(aCallback) { - NetUtil.asyncFetch(bookmarksFile, MigrationUtils.wrapMigrateFunction( + NetUtil.asyncFetch2(bookmarksFile, MigrationUtils.wrapMigrateFunction( function(aInputStream, aResultCode) { if (!Components.isSuccessCode(aResultCode)) throw new Error("Could not read Bookmarks file"); @@ -237,7 +237,12 @@ function GetBookmarksResource(aProfileFolder) { } } }, null); - }, aCallback)); + }, aCallback), + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); } }; } diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index 28dd85fef4..e0b4ebf04c 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -521,7 +521,9 @@ BrowserGlue.prototype = { Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); +#ifdef NIGHTLY_BUILD AddonWatcher.init(this._notifySlowAddon); +#endif }, _setUpUserAgentOverrides: function BG__setUpUserAgentOverrides() { @@ -625,7 +627,9 @@ BrowserGlue.prototype = { UserAgentOverrides.uninit(); webrtcUI.uninit(); FormValidationHandler.uninit(); +#ifdef NIGHTLY_BUILD AddonWatcher.uninit(); +#endif this._dispose(); }, diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index e1d506fb3b..134c0d25e0 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -339,7 +339,9 @@ @RESPATH@/components/toolkit_finalizationwitness.xpt @RESPATH@/components/toolkit_formautofill.xpt @RESPATH@/components/toolkit_osfile.xpt +#ifdef NIGHTLY_BUILD @RESPATH@/components/toolkit_perfmonitoring.xpt +#endif @RESPATH@/components/toolkit_xulstore.xpt @RESPATH@/components/toolkitprofile.xpt #ifdef MOZ_ENABLE_XREMOTE diff --git a/browser/modules/WindowsPreviewPerTab.jsm b/browser/modules/WindowsPreviewPerTab.jsm index 41b38f0cf9..51667b5805 100644 --- a/browser/modules/WindowsPreviewPerTab.jsm +++ b/browser/modules/WindowsPreviewPerTab.jsm @@ -73,15 +73,20 @@ XPCOMUtils.defineLazyServiceGetter(this, "faviconSvc", "nsIFaviconService"); // nsIURI -> imgIContainer -function _imageFromURI(uri, privateMode, callback) { - let channel = ioSvc.newChannelFromURI(uri); +function _imageFromURI(doc, uri, privateMode, callback) { + let channel = ioSvc.newChannelFromURI2(uri, + doc, + null, // aLoadingPrincipal + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_IMAGE); try { channel.QueryInterface(Ci.nsIPrivateBrowsingChannel); channel.setPrivate(privateMode); } catch (e) { // Ignore channels which do not support nsIPrivateBrowsingChannel } - NetUtil.asyncFetch(channel, function(inputStream, resultCode) { + NetUtil.asyncFetch2(channel, function(inputStream, resultCode) { if (!Components.isSuccessCode(resultCode)) return; try { @@ -93,17 +98,17 @@ function _imageFromURI(uri, privateMode, callback) { // favicon). let defaultURI = faviconSvc.defaultFavicon; if (!defaultURI.equals(uri)) - _imageFromURI(defaultURI, callback); + _imageFromURI(doc, defaultURI, privateMode, callback); } }); } // string? -> imgIContainer -function getFaviconAsImage(iconurl, privateMode, callback) { +function getFaviconAsImage(doc, iconurl, privateMode, callback) { if (iconurl) - _imageFromURI(NetUtil.newURI(iconurl), privateMode, callback); + _imageFromURI(doc, NetUtil.newURI(iconurl), privateMode, callback); else - _imageFromURI(faviconSvc.defaultFavicon, privateMode, callback); + _imageFromURI(doc, faviconSvc.defaultFavicon, privateMode, callback); } // Snaps the given rectangle to be pixel-aligned at the given scale @@ -460,13 +465,16 @@ TabWindow.prototype = { preview.visible = AeroPeek.enabled; preview.active = this.tabbrowser.selectedTab == controller.tab; // Grab the default favicon - getFaviconAsImage(null, PrivateBrowsingUtils.isWindowPrivate(this.win), function (img) { - // It is possible that we've already gotten the real favicon, so make sure - // we have not set one before setting this default one. - if (!preview.icon) - preview.icon = img; - }); - + getFaviconAsImage( + controller.linkedBrowser.contentWindow.document, + null, + PrivateBrowsingUtils.isWindowPrivate(this.win), + function (img) { + // It is possible that we've already gotten the real favicon, so make sure + // we have not set one before setting this default one. + if (!preview.icon) + preview.icon = img; + }); return preview; }, @@ -545,14 +553,17 @@ TabWindow.prototype = { //// Browser progress listener onLinkIconAvailable: function (aBrowser, aIconURL) { let self = this; - getFaviconAsImage(aIconURL, PrivateBrowsingUtils.isWindowPrivate(this.win), function (img) { - let index = self.tabbrowser.browsers.indexOf(aBrowser); - // Only add it if we've found the index. The tab could have closed! - if (index != -1) { - let tab = self.tabbrowser.tabs[index]; - self.previews.get(tab).icon = img; - } - }); + getFaviconAsImage( + aBrowser.contentWindow.document, + aIconURL,PrivateBrowsingUtils.isWindowPrivate(this.win), + function (img) { + let index = self.tabbrowser.browsers.indexOf(aBrowser); + // Only add it if we've found the index. The tab could have closed! + if (index != -1) { + let tab = self.tabbrowser.tabs[index]; + self.previews.get(tab).icon = img; + } + }); } } diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 623338889f..ebf210eaf6 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -114,6 +114,7 @@ #include "nsSVGLength2.h" #include "nsDeviceContext.h" #include "nsFontMetrics.h" +#include "Units.h" #undef free // apparently defined by some windows header, clashing with a free() // method in SkTypes.h @@ -4570,7 +4571,8 @@ CanvasRenderingContext2D::DrawDirectlyToCanvas( // FLAG_CLAMP is added for increased performance, since we never tile here. uint32_t modifiedFlags = image.mDrawingFlags | imgIContainer::FLAG_CLAMP; - SVGImageContext svgContext(scaledImageSize, Nothing(), CurrentState().globalAlpha); + CSSIntSize sz(scaledImageSize.width, scaledImageSize.height); // XXX hmm is scaledImageSize really in CSS pixels? + SVGImageContext svgContext(sz, Nothing(), CurrentState().globalAlpha); auto result = image.mImgContainer-> Draw(context, scaledImageSize, diff --git a/image/ClippedImage.cpp b/image/ClippedImage.cpp index dbf256597b..5416fee957 100644 --- a/image/ClippedImage.cpp +++ b/image/ClippedImage.cpp @@ -346,7 +346,7 @@ UnclipViewport(const SVGImageContext& aOldContext, // Map the viewport to the inner image. (Note that we don't take the aSize // parameter of Draw into account, just the clipping region.) - nsIntSize vSize(aOldContext.GetViewportSize()); + CSSIntSize vSize(aOldContext.GetViewportSize()); vSize.width = ceil(vSize.width * double(innerSize.width) / clipSize.width); vSize.height = ceil(vSize.height * double(innerSize.height) / clipSize.height); diff --git a/image/OrientedImage.cpp b/image/OrientedImage.cpp index 8ab1df20d2..15ead36dcd 100644 --- a/image/OrientedImage.cpp +++ b/image/OrientedImage.cpp @@ -241,7 +241,7 @@ static SVGImageContext OrientViewport(const SVGImageContext& aOldContext, const Orientation& aOrientation) { - nsIntSize viewportSize(aOldContext.GetViewportSize()); + CSSIntSize viewportSize(aOldContext.GetViewportSize()); if (aOrientation.SwapsWidthAndHeight()) { swap(viewportSize.width, viewportSize.height); } diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index 069e6f7f5e..111add5852 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -104,7 +104,7 @@ protected: if (!mInObserverList) { nsSVGEffects::AddRenderingObserver(elem, this); mInObserverList = true; - } + } } // Private data @@ -179,9 +179,12 @@ public: MOZ_ASSERT(mDocument, "Need an SVG document"); MOZ_ASSERT(mImage, "Need an image"); - mDocument->AddEventListener(NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"), this, true, false); - mDocument->AddEventListener(NS_LITERAL_STRING("SVGAbort"), this, true, false); - mDocument->AddEventListener(NS_LITERAL_STRING("SVGError"), this, true, false); + mDocument->AddEventListener(NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"), + this, true, false); + mDocument->AddEventListener(NS_LITERAL_STRING("SVGAbort"), this, true, + false); + mDocument->AddEventListener(NS_LITERAL_STRING("SVGError"), this, true, + false); } private: @@ -224,7 +227,9 @@ public: { MOZ_ASSERT(mDocument, "Duplicate call to Cancel"); if (mDocument) { - mDocument->RemoveEventListener(NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"), this, true); + mDocument + ->RemoveEventListener(NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"), + this, true); mDocument->RemoveEventListener(NS_LITERAL_STRING("SVGAbort"), this, true); mDocument->RemoveEventListener(NS_LITERAL_STRING("SVGError"), this, true); mDocument = nullptr; @@ -249,7 +254,7 @@ public: , mViewport(aViewport) , mSize(aSize) , mImageFlags(aImageFlags) - {} + { } virtual bool operator()(gfxContext* aContext, const gfxRect& aFillRect, const GraphicsFilter& aFilter, @@ -350,8 +355,9 @@ VectorImage::Init(const char* aMimeType, uint32_t aFlags) { // We don't support re-initialization - if (mIsInitialized) + if (mIsInitialized) { return NS_ERROR_ILLEGAL_VALUE; + } MOZ_ASSERT(!mIsFullyLoaded && !mHaveAnimations && !mError, "Flags unexpectedly set before initialization"); @@ -410,8 +416,9 @@ VectorImage::OnImageDataComplete(nsIRequest* aRequest, nsresult finalStatus = OnStopRequest(aRequest, aContext, aStatus); // Give precedence to Necko failure codes. - if (NS_FAILED(aStatus)) + if (NS_FAILED(aStatus)) { finalStatus = aStatus; + } // Actually fire OnStopRequest. if (mProgressTracker) { @@ -435,8 +442,9 @@ VectorImage::OnImageDataAvailable(nsIRequest* aRequest, nsresult VectorImage::StartAnimation() { - if (mError) + if (mError) { return NS_ERROR_FAILURE; + } MOZ_ASSERT(ShouldAnimate(), "Should not animate!"); @@ -563,19 +571,23 @@ VectorImage::GetHeight(int32_t* aHeight) NS_IMETHODIMP VectorImage::GetIntrinsicSize(nsSize* aSize) { - if (mError || !mIsFullyLoaded) + if (mError || !mIsFullyLoaded) { return NS_ERROR_FAILURE; + } nsIFrame* rootFrame = mSVGDocumentWrapper->GetRootLayoutFrame(); - if (!rootFrame) + if (!rootFrame) { return NS_ERROR_FAILURE; + } *aSize = nsSize(-1, -1); IntrinsicSize rfSize = rootFrame->GetIntrinsicSize(); - if (rfSize.width.GetUnit() == eStyleUnit_Coord) + if (rfSize.width.GetUnit() == eStyleUnit_Coord) { aSize->width = rfSize.width.GetCoordValue(); - if (rfSize.height.GetUnit() == eStyleUnit_Coord) + } + if (rfSize.height.GetUnit() == eStyleUnit_Coord) { aSize->height = rfSize.height.GetCoordValue(); + } return NS_OK; } @@ -585,12 +597,14 @@ VectorImage::GetIntrinsicSize(nsSize* aSize) NS_IMETHODIMP VectorImage::GetIntrinsicRatio(nsSize* aRatio) { - if (mError || !mIsFullyLoaded) + if (mError || !mIsFullyLoaded) { return NS_ERROR_FAILURE; + } nsIFrame* rootFrame = mSVGDocumentWrapper->GetRootLayoutFrame(); - if (!rootFrame) + if (!rootFrame) { return NS_ERROR_FAILURE; + } *aRatio = rootFrame->GetIntrinsicRatio(); return NS_OK; @@ -618,8 +632,9 @@ VectorImage::GetType(uint16_t* aType) NS_IMETHODIMP VectorImage::GetAnimated(bool* aAnimated) { - if (mError || !mIsFullyLoaded) + if (mError || !mIsFullyLoaded) { return NS_ERROR_FAILURE; + } *aAnimated = mSVGDocumentWrapper->IsAnimated(); return NS_OK; @@ -630,11 +645,13 @@ VectorImage::GetAnimated(bool* aAnimated) int32_t VectorImage::GetFirstFrameDelay() { - if (mError) + if (mError) { return -1; + } - if (!mSVGDocumentWrapper->IsAnimated()) + if (!mSVGDocumentWrapper->IsAnimated()) { return -1; + } // We don't really have a frame delay, so just pretend that we constantly // need updates. @@ -656,11 +673,13 @@ VectorImage::GetFrame(uint32_t aWhichFrame, { MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE); - if (aWhichFrame > FRAME_MAX_VALUE) + if (aWhichFrame > FRAME_MAX_VALUE) { return nullptr; + } - if (mError || !mIsFullyLoaded) + if (mError || !mIsFullyLoaded) { return nullptr; + } // Look up height & width // ---------------------- @@ -669,7 +688,7 @@ VectorImage::GetFrame(uint32_t aWhichFrame, "loading without errors"); nsIntSize imageIntSize(svgElem->GetIntrinsicWidth(), svgElem->GetIntrinsicHeight()); - + if (imageIntSize.IsEmpty()) { // We'll get here if our SVG doc has a percent-valued or negative width or // height. @@ -720,11 +739,16 @@ struct SVGDrawingParameters , region(aRegion) , filter(aFilter) , svgContext(aSVGContext) - , viewportSize(aSVGContext ? aSVGContext->GetViewportSize() : aSize) + , viewportSize(aSize) , animationTime(aAnimationTime) , flags(aFlags) , opacity(aSVGContext ? aSVGContext->GetGlobalOpacity() : 1.0) - { } + { + if (aSVGContext) { + CSSIntSize sz = aSVGContext->GetViewportSize(); + viewportSize = nsIntSize(sz.width, sz.height); // XXX losing unit + } + } gfxContext* context; IntSize size; @@ -783,8 +807,9 @@ VectorImage::Draw(gfxContext* aContext, AutoRestore autoRestoreIsDrawing(mIsDrawing); mIsDrawing = true; - float animTime = (aWhichFrame == FRAME_FIRST) ? 0.0f - : mSVGDocumentWrapper->GetCurrentTime(); + float animTime = + (aWhichFrame == FRAME_FIRST) ? 0.0f + : mSVGDocumentWrapper->GetCurrentTime(); AutoSVGRenderingState autoSVGState(aSVGContext, animTime, mSVGDocumentWrapper->GetRootSVGElem()); @@ -863,8 +888,9 @@ VectorImage::CreateSurfaceAndShow(const SVGDrawingParameters& aParams) bypassCache = (aParams.size.width * aParams.size.height * 4) > maxCacheElemSize; } - if (bypassCache) + if (bypassCache) { return Show(svgDrawable, aParams); + } // We're about to rerasterize, which may mean that some of the previous // surfaces we've rasterized aren't useful anymore. We can allow them to @@ -885,14 +911,16 @@ VectorImage::CreateSurfaceAndShow(const SVGDrawingParameters& aParams) // If we couldn't create the frame, it was probably because it would end // up way too big. Generally it also wouldn't fit in the cache, but the prefs // could be set such that the cache isn't the limiting factor. - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return Show(svgDrawable, aParams); + } // Take a strong reference to the frame's surface and make sure it hasn't // already been purged by the operating system. RefPtr surface = frame->GetSurface(); - if (!surface) + if (!surface) { return Show(svgDrawable, aParams); + } // Attempt to cache the frame. SurfaceCache::Insert(frame, ImageKey(this), @@ -1038,8 +1066,9 @@ VectorImage::OnSurfaceDiscarded() NS_IMETHODIMP VectorImage::ResetAnimation() { - if (mError) + if (mError) { return NS_ERROR_FAILURE; + } if (!mIsFullyLoaded || !mHaveAnimations) { return NS_OK; // There are no animations to be reset. @@ -1106,8 +1135,9 @@ NS_IMETHODIMP VectorImage::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt, nsresult aStatus) { - if (mError) + if (mError) { return NS_ERROR_FAILURE; + } return mSVGDocumentWrapper->OnStopRequest(aRequest, aCtxt, aStatus); } @@ -1122,7 +1152,8 @@ VectorImage::OnSVGDocumentParsed() // This is an invalid SVG document. It may have failed to parse, or it may // be missing the root element, or the root element may not // declare the correct namespace. In any of these cases, we'll never be - // notified that the SVG finished loading, so we need to treat this as an error. + // notified that the SVG finished loading, so we need to treat this as an + // error. OnSVGDocumentError(); } } @@ -1203,8 +1234,9 @@ VectorImage::OnDataAvailable(nsIRequest* aRequest, nsISupports* aCtxt, nsIInputStream* aInStr, uint64_t aSourceOffset, uint32_t aCount) { - if (mError) + if (mError) { return NS_ERROR_FAILURE; + } return mSVGDocumentWrapper->OnDataAvailable(aRequest, aCtxt, aInStr, aSourceOffset, aCount); @@ -1224,7 +1256,10 @@ VectorImage::InvalidateObserversOnNextRefreshDriverTick() } nsIntSize -VectorImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame, GraphicsFilter aFilter, uint32_t aFlags) +VectorImage::OptimalImageSizeForDest(const gfxSize& aDest, + uint32_t aWhichFrame, + GraphicsFilter aFilter, + uint32_t aFlags) { MOZ_ASSERT(aDest.width >= 0 || ceil(aDest.width) <= INT32_MAX || aDest.height >= 0 || ceil(aDest.height) <= INT32_MAX, diff --git a/image/VectorImage.h b/image/VectorImage.h index 083d77f2d4..053e5d7678 100644 --- a/image/VectorImage.h +++ b/image/VectorImage.h @@ -37,7 +37,8 @@ public: nsresult Init(const char* aMimeType, uint32_t aFlags) override; - virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const override; + virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) + const override; virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation, MallocSizeOf aMallocSizeOf) const override; @@ -101,9 +102,10 @@ private: /// Count of locks on this image (roughly correlated to visible instances). uint32_t mLockCount; - bool mIsInitialized; // Have we been initalized? + bool mIsInitialized; // Have we been initialized? bool mDiscardable; // Are we discardable? - bool mIsFullyLoaded; // Has the SVG document finished loading? + bool mIsFullyLoaded; // Has the SVG document finished + // loading? bool mIsDrawing; // Are we currently drawing? bool mHaveAnimations; // Is our SVG content SMIL-animated? // (Only set after mIsFullyLoaded.) @@ -116,7 +118,7 @@ private: friend class ImageFactory; }; -inline NS_IMETHODIMP VectorImage::GetAnimationMode(uint16_t *aAnimationMode) { +inline NS_IMETHODIMP VectorImage::GetAnimationMode(uint16_t* aAnimationMode) { return GetAnimationModeInternal(aAnimationMode); } diff --git a/layout/base/Units.h b/layout/base/Units.h index 6a61ced8df..6fe5f7029a 100644 --- a/layout/base/Units.h +++ b/layout/base/Units.h @@ -208,6 +208,11 @@ struct CSSPixel { NSToCoordRoundWithClamp(float(aPoint.y) * float(AppUnitsPerCSSPixel()))); } + static nsSize ToAppUnits(const CSSIntSize& aSize) { + return nsSize(NSToCoordRoundWithClamp(float(aSize.width) * float(AppUnitsPerCSSPixel())), + NSToCoordRoundWithClamp(float(aSize.height) * float(AppUnitsPerCSSPixel()))); + } + static nsRect ToAppUnits(const CSSRect& aRect) { return nsRect(NSToCoordRoundWithClamp(aRect.x * float(AppUnitsPerCSSPixel())), NSToCoordRoundWithClamp(aRect.y * float(AppUnitsPerCSSPixel())), @@ -277,6 +282,11 @@ struct LayoutDevicePixel { aSize.height * aAppUnitsPerDevPixel); } + static nsSize ToAppUnits(const LayoutDeviceSize& aSize, nscoord aAppUnitsPerDevPixel) { + return nsSize(NSFloatPixelsToAppUnits(aSize.width, aAppUnitsPerDevPixel), + NSFloatPixelsToAppUnits(aSize.height, aAppUnitsPerDevPixel)); + } + static nsRect ToAppUnits(const LayoutDeviceRect& aRect, nscoord aAppUnitsPerDevPixel) { return nsRect(NSFloatPixelsToAppUnits(aRect.x, aAppUnitsPerDevPixel), NSFloatPixelsToAppUnits(aRect.y, aAppUnitsPerDevPixel), diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 061220d561..f2ba304911 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -4787,7 +4787,7 @@ nsImageRenderer::ComputeIntrinsicSize() case eStyleImageType_Image: { bool haveWidth, haveHeight; - nsIntSize imageIntSize; + CSSIntSize imageIntSize; nsLayoutUtils::ComputeSizeForDrawing(mImageContainer, imageIntSize, result.mRatio, haveWidth, haveHeight); if (haveWidth) { @@ -4996,8 +4996,8 @@ nsImageRenderer::Draw(nsPresContext* aPresContext, switch (mType) { case eStyleImageType_Image: { - nsIntSize imageSize(nsPresContext::AppUnitsToIntCSSPixels(mSize.width), - nsPresContext::AppUnitsToIntCSSPixels(mSize.height)); + CSSIntSize imageSize(nsPresContext::AppUnitsToIntCSSPixels(mSize.width), + nsPresContext::AppUnitsToIntCSSPixels(mSize.height)); return nsLayoutUtils::DrawBackgroundImage(*aRenderingContext.ThebesContext(), aPresContext, diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 4935689604..46206539b9 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -5743,7 +5743,7 @@ struct SnappedImageDrawingParameters { // one has been explicitly specified. This is the same as |size| except that // it does not take into account any transformation on the gfxContext we're // drawing to - for example, CSS transforms are not taken into account. - nsIntSize svgViewportSize; + CSSIntSize svgViewportSize; // Whether there's anything to draw at all. bool shouldDraw; @@ -5755,7 +5755,7 @@ struct SnappedImageDrawingParameters { SnappedImageDrawingParameters(const gfxMatrix& aImageSpaceToDeviceSpace, const nsIntSize& aSize, const ImageRegion& aRegion, - const nsIntSize& aSVGViewportSize) + const CSSIntSize& aSVGViewportSize) : imageSpaceToDeviceSpace(aImageSpaceToDeviceSpace) , size(aSize) , region(aRegion) @@ -5881,10 +5881,10 @@ ComputeSnappedImageDrawingParameters(gfxContext* aCtx, aGraphicsFilter, aImageFlags); gfxSize imageSize(intImageSize.width, intImageSize.height); - nsIntSize svgViewportSize = currentMatrix.IsIdentity() - ? intImageSize - : nsIntSize(NSAppUnitsToIntPixels(dest.width, aAppUnitsPerDevPixel), - NSAppUnitsToIntPixels(dest.height, aAppUnitsPerDevPixel)); + CSSIntSize svgViewportSize = currentMatrix.IsIdentity() + ? CSSIntSize(intImageSize.width, intImageSize.height) + : CSSIntSize(NSAppUnitsToIntPixels(dest.width, aAppUnitsPerDevPixel), //XXX BUG! + NSAppUnitsToIntPixels(dest.height, aAppUnitsPerDevPixel)); //XXX BUG! // Compute the set of pixels that would be sampled by an ideal rendering gfxPoint subimageTopLeft = @@ -6083,7 +6083,7 @@ nsLayoutUtils::DrawSingleImage(gfxContext& aContext, const nsRect* aSourceArea) { nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel(); - nsIntSize pixelImageSize(ComputeSizeForDrawingWithFallback(aImage, aDest.Size())); + CSSIntSize pixelImageSize(ComputeSizeForDrawingWithFallback(aImage, aDest.Size())); if (pixelImageSize.width < 1 || pixelImageSize.height < 1) { NS_ASSERTION(pixelImageSize.width >= 0 && pixelImageSize.height >= 0, "Image width or height is negative"); @@ -6127,7 +6127,7 @@ nsLayoutUtils::DrawSingleImage(gfxContext& aContext, /* static */ void nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage, - nsIntSize& aImageSize, /*outparam*/ + CSSIntSize& aImageSize, /*outparam*/ nsSize& aIntrinsicRatio, /*outparam*/ bool& aGotWidth, /*outparam*/ bool& aGotHeight /*outparam*/) @@ -6140,16 +6140,16 @@ nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage, // We hit an error (say, because the image failed to load or couldn't be // decoded) and should return zero size. aGotWidth = aGotHeight = true; - aImageSize = nsIntSize(0, 0); + aImageSize = CSSIntSize(0, 0); aIntrinsicRatio = nsSize(0, 0); } } -/* static */ nsIntSize +/* static */ CSSIntSize nsLayoutUtils::ComputeSizeForDrawingWithFallback(imgIContainer* aImage, const nsSize& aFallbackSize) { - nsIntSize imageSize; + CSSIntSize imageSize; nsSize imageRatio; bool gotHeight, gotWidth; ComputeSizeForDrawing(aImage, imageSize, imageRatio, gotWidth, gotHeight); @@ -6192,7 +6192,7 @@ nsLayoutUtils::ComputeSizeForDrawingWithFallback(imgIContainer* aImage, nsLayoutUtils::DrawBackgroundImage(gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage, - const nsIntSize& aImageSize, + const CSSIntSize& aImageSize, GraphicsFilter aGraphicsFilter, const nsRect& aDest, const nsRect& aFill, @@ -6266,18 +6266,6 @@ nsLayoutUtils::GetWholeImageDestination(const nsSize& aWholeImageSize, nsSize(wholeSizeX, wholeSizeY)); } -/* static */ nsRect -nsLayoutUtils::GetWholeImageDestination(const nsIntSize& aWholeImageSize, - const nsRect& aImageSourceArea, - const nsRect& aDestArea) -{ - nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel(); - return GetWholeImageDestination(nsSize(aWholeImageSize.width * appUnitsPerCSSPixel, - aWholeImageSize.height * appUnitsPerCSSPixel), - aImageSourceArea, - aDestArea); -} - /* static */ already_AddRefed nsLayoutUtils::OrientImage(imgIContainer* aContainer, const nsStyleImageOrientation& aOrientation) diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index d1bfce6e0e..88f3e2e206 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -135,6 +135,7 @@ public: typedef FrameMetrics::ViewID ViewID; typedef mozilla::CSSPoint CSSPoint; typedef mozilla::CSSSize CSSSize; + typedef mozilla::CSSIntSize CSSIntSize; typedef mozilla::ScreenMargin ScreenMargin; typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize; @@ -1671,7 +1672,7 @@ public: static DrawResult DrawBackgroundImage(gfxContext& aContext, nsPresContext* aPresContext, imgIContainer* aImage, - const nsIntSize& aImageSize, + const CSSIntSize& aImageSize, GraphicsFilter aGraphicsFilter, const nsRect& aDest, const nsRect& aFill, @@ -1808,7 +1809,7 @@ public: * have less information about the frame tree. */ static void ComputeSizeForDrawing(imgIContainer* aImage, - nsIntSize& aImageSize, + CSSIntSize& aImageSize, nsSize& aIntrinsicRatio, bool& aGotWidth, bool& aGotHeight); @@ -1821,8 +1822,9 @@ public: * after trying all these methods, no value is available for one or both * dimensions, the corresponding dimension of aFallbackSize is used instead. */ - static nsIntSize ComputeSizeForDrawingWithFallback(imgIContainer* aImage, - const nsSize& aFallbackSize); + static CSSIntSize + ComputeSizeForDrawingWithFallback(imgIContainer* aImage, + const nsSize& aFallbackSize); /** * Given a source area of an image (in appunits) and a destination area @@ -1831,10 +1833,6 @@ public: * the aDest parameter of DrawImage, when we want to draw a subimage * of an overall image. */ - static nsRect GetWholeImageDestination(const nsIntSize& aWholeImageSize, - const nsRect& aImageSourceArea, - const nsRect& aDestArea); - static nsRect GetWholeImageDestination(const nsSize& aWholeImageSize, const nsRect& aImageSourceArea, const nsRect& aDestArea); diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 510c5561b2..fdf09ce5a8 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2485,7 +2485,7 @@ nsStyleBackground::Size::DependsOnPositioningAreaSize(const nsStyleImage& aImage nsCOMPtr imgContainer; aImage.GetImageData()->GetImage(getter_AddRefs(imgContainer)); if (imgContainer) { - nsIntSize imageSize; + CSSIntSize imageSize; nsSize imageRatio; bool hasWidth, hasHeight; nsLayoutUtils::ComputeSizeForDrawing(imgContainer, imageSize, imageRatio, diff --git a/layout/svg/SVGImageContext.h b/layout/svg/SVGImageContext.h index c6265e0bc2..d285666651 100644 --- a/layout/svg/SVGImageContext.h +++ b/layout/svg/SVGImageContext.h @@ -8,6 +8,7 @@ #include "mozilla/Maybe.h" #include "SVGPreserveAspectRatio.h" +#include "Units.h" namespace mozilla { @@ -23,7 +24,7 @@ public: : mGlobalOpacity(1.0) { } - SVGImageContext(nsIntSize aViewportSize, + SVGImageContext(CSSIntSize aViewportSize, Maybe aPreserveAspectRatio, gfxFloat aOpacity = 1.0) : mViewportSize(aViewportSize) @@ -31,7 +32,7 @@ public: , mGlobalOpacity(aOpacity) { } - const nsIntSize& GetViewportSize() const { + const CSSIntSize& GetViewportSize() const { return mViewportSize; } @@ -65,7 +66,7 @@ private: return aPAR.Hash(); } - nsIntSize mViewportSize; + CSSIntSize mViewportSize; Maybe mPreserveAspectRatio; gfxFloat mGlobalOpacity; }; diff --git a/layout/svg/nsSVGImageFrame.cpp b/layout/svg/nsSVGImageFrame.cpp index 1071f9c904..fb48f4388c 100644 --- a/layout/svg/nsSVGImageFrame.cpp +++ b/layout/svg/nsSVGImageFrame.cpp @@ -365,13 +365,20 @@ nsSVGImageFrame::PaintSVG(gfxContext& aContext, if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) { // Package up the attributes of this image element which can override the - // attributes of mImageContainer's internal SVG document. - SVGImageContext context(nsIntSize(width, height), + // attributes of mImageContainer's internal SVG document. The 'width' & + // 'height' values we're passing in here are in CSS units (though they + // come from width/height *attributes* in SVG). They influence the region + // of the SVG image's internal document that is visible, in combination + // with preserveAspectRatio and viewBox. + SVGImageContext context(CSSIntSize(width, height), Some(imgElem->mPreserveAspectRatio.GetAnimValue())); - nsRect destRect(0, 0, - appUnitsPerDevPx * width, - appUnitsPerDevPx * height); + // For the actual draw operation to draw crisply (and at the right size), + // our destination rect needs to be |width|x|height|, *in dev pixels*. + LayoutDeviceSize devPxSize(width, height); + nsRect destRect(nsPoint(), + LayoutDevicePixel::ToAppUnits(devPxSize, + appUnitsPerDevPx)); // Note: Can't use DrawSingleUnscaledImage for the TYPE_VECTOR case. // That method needs our image to have a fixed native width & height, diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp index e3a5122838..f068b547b0 100644 --- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -3552,9 +3552,10 @@ nsTreeBodyFrame::PaintImage(int32_t aRowIndex, // Essentially, we are scaling the image as dictated by the CSS destination // height and width, and we are then clipping the scaled image by the cell // width and height. - nsIntSize rawImageSize; - image->GetWidth(&rawImageSize.width); - image->GetHeight(&rawImageSize.height); + CSSIntSize rawImageCSSIntSize; + image->GetWidth(&rawImageCSSIntSize.width); + image->GetHeight(&rawImageCSSIntSize.height); + nsSize rawImageSize(CSSPixel::ToAppUnits(rawImageCSSIntSize)); nsRect wholeImageDest = nsLayoutUtils::GetWholeImageDestination(rawImageSize, sourceRect, nsRect(destRect.TopLeft(), imageDestSize)); diff --git a/services/common/tests/unit/test_load_modules.js b/services/common/tests/unit/test_load_modules.js index ca3b4922c7..1e159dfebc 100644 --- a/services/common/tests/unit/test_load_modules.js +++ b/services/common/tests/unit/test_load_modules.js @@ -1,31 +1,83 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -const modules = [ +Components.utils.import("resource://gre/modules/AppConstants.jsm"); + +const MODULE_BASE = "resource://services-common/"; +const shared_modules = [ "async.js", - "bagheeraclient.js", "logmanager.js", "rest.js", - "storageservice.js", "stringbundle.js", - "tokenserverclient.js", "utils.js", ]; -const test_modules = [ - "bagheeraserver.js", +const non_android_modules = [ + "tokenserverclient.js", +]; + +const non_android_healthreport_modules = [ + "bagheeraclient.js", +]; + +const TEST_BASE = "resource://testing-common/services/common/"; +const shared_test_modules = [ "logging.js", +]; + +const non_android_test_modules = [ "storageserver.js", ]; -function run_test() { - for each (let m in modules) { - let resource = "resource://services-common/" + m; - Components.utils.import(resource, {}); - } +const non_android_healthreport_test_modules = [ + "bagheeraserver.js", +]; - for each (let m in test_modules) { - let resource = "resource://testing-common/services/common/" + m; - Components.utils.import(resource, {}); +function expectImportsToSucceed(mm, base=MODULE_BASE) { + for each (let m in mm) { + let resource = base + m; + let succeeded = false; + try { + Components.utils.import(resource, {}); + succeeded = true; + } catch (e) {} + + if (!succeeded) { + throw "Importing " + resource + " should have succeeded!"; + } + } +} + +function expectImportsToFail(mm, base=MODULE_BASE) { + for each (let m in mm) { + let resource = base + m; + let succeeded = false; + try { + Components.utils.import(resource, {}); + succeeded = true; + } catch (e) {} + + if (succeeded) { + throw "Importing " + resource + " should have failed!"; + } + } +} + +function run_test() { + expectImportsToSucceed(shared_modules); + expectImportsToSucceed(shared_test_modules, TEST_BASE); + + if (AppConstants.platform != "android") { + expectImportsToSucceed(non_android_modules); + expectImportsToSucceed(non_android_test_modules, TEST_BASE); + if (AppConstants.MOZ_SERVICES_HEALTHREPORT) { + expectImportsToSucceed(non_android_healthreport_modules); + expectImportsToSucceed(non_android_healthreport_test_modules, TEST_BASE); + } + } else { + expectImportsToFail(non_android_modules); + expectImportsToFail(non_android_test_modules, TEST_BASE); + expectImportsToFail(non_android_healthreport_modules); + expectImportsToFail(non_android_healthreport_test_modules, TEST_BASE); } } diff --git a/testing/mochitest/browser-test.js b/testing/mochitest/browser-test.js index df211f41f3..8d0c974df8 100644 --- a/testing/mochitest/browser-test.js +++ b/testing/mochitest/browser-test.js @@ -15,6 +15,7 @@ if (Cu === undefined) { Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Task.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); @@ -542,20 +543,29 @@ Tester.prototype = { // frames and browser intentionally kept alive until shutdown to // eliminate false positives. if (gConfig.testRoot == "browser") { - // Replace the document currently loaded in the browser's sidebar. - // This will prevent false positives for tests that were the last - // to touch the sidebar. They will thus not be blamed for leaking - // a document. - let sidebar = document.getElementById("sidebar"); - sidebar.setAttribute("src", "data:text/html;charset=utf-8,"); - sidebar.docShell.createAboutBlankContentViewer(null); - sidebar.setAttribute("src", "about:blank"); + //Skip if SeaMonkey + if (AppConstants.MOZ_APP_NAME != "seamonkey") { + // Replace the document currently loaded in the browser's sidebar. + // This will prevent false positives for tests that were the last + // to touch the sidebar. They will thus not be blamed for leaking + // a document. + let sidebar = document.getElementById("sidebar"); + sidebar.setAttribute("src", "data:text/html;charset=utf-8,"); + sidebar.docShell.createAboutBlankContentViewer(null); + sidebar.setAttribute("src", "about:blank"); - // Do the same for the social sidebar. - let socialSidebar = document.getElementById("social-sidebar-browser"); - socialSidebar.setAttribute("src", "data:text/html;charset=utf-8,"); - socialSidebar.docShell.createAboutBlankContentViewer(null); - socialSidebar.setAttribute("src", "about:blank"); + // Do the same for the social sidebar. + let socialSidebar = document.getElementById("social-sidebar-browser"); + socialSidebar.setAttribute("src", "data:text/html;charset=utf-8,"); + socialSidebar.docShell.createAboutBlankContentViewer(null); + socialSidebar.setAttribute("src", "about:blank"); + + SelfSupportBackend.uninit(); + CustomizationTabPreloader.uninit(); + SocialFlyout.unload(); + SocialShare.uninit(); + TabView.uninit(); + } // Destroy BackgroundPageThumbs resources. let {BackgroundPageThumbs} = @@ -570,10 +580,6 @@ Tester.prototype = { } SelfSupportBackend.uninit(); - CustomizationTabPreloader.uninit(); - SocialFlyout.unload(); - SocialShare.uninit(); - TabView.uninit(); } // Schedule GC and CC runs before finishing in order to detect diff --git a/toolkit/components/build/nsToolkitCompsModule.cpp b/toolkit/components/build/nsToolkitCompsModule.cpp index 7182718dd7..966f41a9e4 100644 --- a/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/toolkit/components/build/nsToolkitCompsModule.cpp @@ -43,7 +43,13 @@ #include "nsTerminator.h" #endif +#if defined(NIGHTLY_BUILD) +#define MOZ_HAS_PERFSTATS +#endif // defined(NIGHTLY_BUILD) + +#if defined(MOZ_HAS_PERFSTATS) #include "nsPerformanceStats.h" +#endif // defined (MOZ_HAS_PERFSTATS) using namespace mozilla; @@ -51,7 +57,9 @@ using namespace mozilla; NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAppStartup, Init) +#if defined(MOZ_HAS_PERFSTATS) NS_GENERIC_FACTORY_CONSTRUCTOR(nsPerformanceStatsService) +#endif // defined (MOZ_HAS_PERFSTATS) #if defined(MOZ_HAS_TERMINATOR) NS_GENERIC_FACTORY_CONSTRUCTOR(nsTerminator) @@ -84,7 +92,10 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NativeFileWatcherService, Init) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonPathService, AddonPathService::GetInstance) NS_DEFINE_NAMED_CID(NS_TOOLKIT_APPSTARTUP_CID); +#if defined(MOZ_HAS_PERFSTATS) NS_DEFINE_NAMED_CID(NS_TOOLKIT_PERFORMANCESTATSSERVICE_CID); +#endif // defined (MOZ_HAS_PERFSTATS) + #if defined(MOZ_HAS_TERMINATOR) NS_DEFINE_NAMED_CID(NS_TOOLKIT_TERMINATOR_CID); #endif @@ -112,7 +123,9 @@ static const Module::CIDEntry kToolkitCIDs[] = { #if defined(MOZ_HAS_TERMINATOR) { &kNS_TOOLKIT_TERMINATOR_CID, false, nullptr, nsTerminatorConstructor }, #endif +#if defined(MOZ_HAS_PERFSTATS) { &kNS_TOOLKIT_PERFORMANCESTATSSERVICE_CID, false, nullptr, nsPerformanceStatsServiceConstructor }, +#endif // defined (MOZ_HAS_PERFSTATS) { &kNS_USERINFO_CID, false, nullptr, nsUserInfoConstructor }, { &kNS_ALERTSSERVICE_CID, false, nullptr, nsAlertsServiceConstructor }, #if !defined(MOZ_DISABLE_PARENTAL_CONTROLS) @@ -139,7 +152,9 @@ static const Module::ContractIDEntry kToolkitContracts[] = { #if defined(MOZ_HAS_TERMINATOR) { NS_TOOLKIT_TERMINATOR_CONTRACTID, &kNS_TOOLKIT_TERMINATOR_CID }, #endif +#if defined(MOZ_HAS_PERFSTATS) { NS_TOOLKIT_PERFORMANCESTATSSERVICE_CONTRACTID, &kNS_TOOLKIT_PERFORMANCESTATSSERVICE_CID }, +#endif // defined (MOZ_HAS_PERFSTATS) { NS_USERINFO_CONTRACTID, &kNS_USERINFO_CID }, { NS_ALERTSERVICE_CONTRACTID, &kNS_ALERTSSERVICE_CID }, #if !defined(MOZ_DISABLE_PARENTAL_CONTROLS) diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build index e25c9c62f1..d274cd571f 100644 --- a/toolkit/components/moz.build +++ b/toolkit/components/moz.build @@ -11,7 +11,6 @@ if CONFIG['MOZ_ENABLE_XREMOTE']: DIRS += [ 'aboutcache', 'aboutmemory', - 'aboutperformance', 'addoncompat', 'alerts', 'apppicker', @@ -84,6 +83,11 @@ if CONFIG['MOZ_CAPTIVEDETECT']: if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk" and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android': DIRS += ['terminator'] +if CONFIG['NIGHTLY_BUILD']: # Bug 1136927 - Performance Monitoring is not ready for prime-time yet + DIRS += [ + 'aboutperformance', + ] + DIRS += ['build'] EXTRA_COMPONENTS += [ diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 69b86dfcf8..db2080e1c5 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -3373,105 +3373,267 @@ "n_buckets" : 10, "description": "PLACES: Days from last maintenance" }, - "UPDATER_BACKGROUND_CHECK_CODE_EXTERNAL": { - "expires_in_version": "default", - "kind": "enumerated", - "n_values": 50, - "description": "Updater: externally initiated (typically by the application) background update check result code (see PING_BGUC_* constants defined in /toolkit/mozapps/update/nsUpdateService.js)" + "UPDATE_CHECK_NO_UPDATE_EXTERNAL" : { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of no updates were found for a background update check (externally initiated)" }, - "UPDATER_BACKGROUND_CHECK_CODE_NOTIFY": { - "expires_in_version": "40", - "kind": "enumerated", - "n_values": 50, - "description": "Updater: timer initiated background update check result code (see PING_BGUC_* constants defined in /toolkit/mozapps/update/nsUpdateService.js)" + "UPDATE_CHECK_NO_UPDATE_NOTIFY" : { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of no updates were found for a background update check (timer initiated)" }, - "UPDATER_INVALID_LASTUPDATETIME_EXTERNAL": { - "expires_in_version": "40", - "kind": "boolean", - "description": "Updater: Whether the last update time is invalid when a background update check was externally requested (typically by the application)" - }, - "UPDATER_INVALID_LASTUPDATETIME_NOTIFY": { - "expires_in_version": "40", - "kind": "boolean", - "description": "Updater: Whether the last update time is invalid when a background update check was timer initiated" - }, - "UPDATER_LAST_NOTIFY_INTERVAL_DAYS_EXTERNAL": { - "expires_in_version": "40", - "kind": "exponential", - "n_buckets": 10, - "high": "60", - "description": "Updater: The interval in days between the previous and the current background update check when the check was externally requested (typically by the application)" - }, - "UPDATER_LAST_NOTIFY_INTERVAL_DAYS_NOTIFY": { - "expires_in_version": "40", - "kind": "exponential", - "n_buckets": 10, - "high": "60", - "description": "Updater: The interval in days between the previous and the current background update check when the check was timer initiated" - }, - "UPDATER_STATUS_CODES": { + "UPDATE_CHECK_CODE_EXTERNAL": { "expires_in_version": "never", "kind": "enumerated", "n_values": 50, - "description": "Updater: the status of the latest update performed" + "description": "Update: background update check result code except for no updates found (externally initiated)" }, - "UPDATER_UPDATES_ENABLED": { - "expires_in_version": "default", + "UPDATE_CHECK_CODE_NOTIFY": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 50, + "description": "Update: background update check result code except for no updates found (timer initiated)" + }, + "UPDATE_CHECK_EXTENDED_ERROR_EXTERNAL": { + "expires_in_version": "never", + "kind": "count", + "keyed": true, + "description": "Update: keyed count (key names are prefixed with AUS_CHECK_EX_ERR_) of background update check extended error code (externally initiated)" + }, + "UPDATE_CHECK_EXTENDED_ERROR_NOTIFY": { + "expires_in_version": "never", + "kind": "count", + "keyed": true, + "description": "Update: keyed count (key names are prefixed with AUS_CHECK_EX_ERR_) of background update check extended error code (timer initiated)" + }, + "UPDATE_INVALID_LASTUPDATETIME_EXTERNAL": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of systems that have a last update time greater than the current time (externally initiated)" + }, + "UPDATE_INVALID_LASTUPDATETIME_NOTIFY": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of systems that have a last update time greater than the current time (timer initiated)" + }, + "UPDATE_LAST_NOTIFY_INTERVAL_DAYS_EXTERNAL": { + "expires_in_version": "never", + "kind": "exponential", + "n_buckets": 60, + "high": "365", + "description": "Update: interval in days since the last background update check (externally initiated)" + }, + "UPDATE_LAST_NOTIFY_INTERVAL_DAYS_NOTIFY": { + "expires_in_version": "never", + "kind": "exponential", + "n_buckets": 30, + "high": "180", + "description": "Update: interval in days since the last background update check (timer initiated)" + }, + "UPDATE_SERVICE_INSTALLED_EXTERNAL": { + "expires_in_version": "never", "kind": "boolean", - "description": "Updater: Whether or not updates are enabled" + "description": "Update: whether the service is installed (externally initiated)" }, - "UPDATER_UPDATES_METRO_ENABLED": { - "expires_in_version": "default", + "UPDATE_SERVICE_INSTALLED_NOTIFY": { + "expires_in_version": "never", "kind": "boolean", - "description": "Updater: Whether or not Metro updates are enabled" + "description": "Update: whether the service is installed (timer initiated)" }, - "UPDATER_UPDATES_AUTOMATIC": { - "expires_in_version": "40", + "UPDATE_SERVICE_MANUALLY_UNINSTALLED_EXTERNAL": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of systems that manually uninstalled the service (externally initiated)" + }, + "UPDATE_SERVICE_MANUALLY_UNINSTALLED_NOTIFY": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of systems that manually uninstalled the service (timer initiated)" + }, + "UPDATE_CANNOT_APPLY_EXTERNAL": { + "expires_in_version": "never", "kind": "boolean", - "description": "Updater: Whether or not updates are automatic" + "description": "Update: systems that cannot apply updates (externally initiated)" }, - "UPDATER_SERVICE_ENABLED": { - "expires_in_version": "default", + "UPDATE_CANNOT_APPLY_NOTIFY": { + "expires_in_version": "never", "kind": "boolean", - "description": "Updater: Whether or not the MozillaMaintenance service is enabled" + "description": "Update: systems that cannot apply updates (timer initiated)" }, - "UPDATER_SERVICE_ERROR_CODE": { - "expires_in_version": "default", + "UPDATE_CANNOT_STAGE_EXTERNAL": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of systems that cannot stage updates (externally initiated)" + }, + "UPDATE_CANNOT_STAGE_NOTIFY": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of systems that cannot stage updates (timer initiated)" + }, + "UPDATE_HAS_PREF_URL_OVERRIDE_EXTERNAL": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of systems that have an app.update.url.override preference (externally initiated)" + }, + "UPDATE_HAS_PREF_URL_OVERRIDE_NOTIFY": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of systems that have an app.update.url.override preference (timer initiated)" + }, + "UPDATE_PREF_UPDATE_CANCELATIONS_EXTERNAL": { + "expires_in_version": "never", "kind": "enumerated", "n_values": 100, - "description": "Updater: 0=success else SERVICE_* error code defined in /toolkit/mozapps/update/common/errors.h" + "description": "Update: number of sequential update elevation request cancelations greater than 0 (externally initiated)" }, - "UPDATER_SERVICE_ERRORS": { - "expires_in_version": "default", + "UPDATE_PREF_UPDATE_CANCELATIONS_NOTIFY": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 100, + "description": "Update: number of sequential update elevation request cancelations greater than 0 (timer initiated)" + }, + "UPDATE_PREF_SERVICE_ERRORS_EXTERNAL": { + "expires_in_version": "never", "kind": "enumerated", "n_values": 30, - "description": "Updater: The number of MozillaMaintenance service errors that have occurred" + "description": "Update: number of sequential update service errors greater than 0 (externally initiated)" }, - "UPDATER_SERVICE_INSTALLED": { - "expires_in_version": "default", - "kind": "boolean", - "description": "Updater: Whether or not the MozillaMaintenance service is installed" - }, - "UPDATER_SERVICE_MANUALLY_UNINSTALLED": { - "expires_in_version": "default", - "kind": "boolean", - "description": "Updater: Whether or not someone manually uninstalled the service." - }, - "UPDATER_STAGE_ENABLED": { - "expires_in_version": "40", - "kind": "boolean", - "description": "Updater: Whether or not staging updates are enabled" - }, - "UPDATER_HAS_PERMISSIONS": { - "expires_in_version": "40", - "kind": "boolean", - "description": "Updater: Whether or not the updater has permissions" - }, - "UPDATER_WIZ_LAST_PAGE_CODE": { - "expires_in_version": "40", + "UPDATE_PREF_SERVICE_ERRORS_NOTIFY": { + "expires_in_version": "never", "kind": "enumerated", - "n_values": 25, - "description": "Updater: The update wizard page displayed when the UI was closed (mapped in toolkit/mozapps/update/content/updates.js)" + "n_values": 30, + "description": "Update: number of sequential update service errors greater than 0 (timer initiated)" + }, + "UPDATE_NOT_PREF_UPDATE_AUTO_EXTERNAL": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of when the app.update.auto boolean preference is not the default value of true (true values are not submitted)" + }, + "UPDATE_NOT_PREF_UPDATE_AUTO_NOTIFY": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of when the app.update.auto boolean preference is not the default value of true (true values are not submitted)" + }, + "UPDATE_NOT_PREF_UPDATE_ENABLED_EXTERNAL": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of when the app.update.enabled boolean preference is not the default value of true (true values are not submitted)" + }, + "UPDATE_NOT_PREF_UPDATE_ENABLED_NOTIFY": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of when the app.update.enabled boolean preference is not the default value of true (true values are not submitted)" + }, + "UPDATE_NOT_PREF_UPDATE_STAGING_ENABLED_EXTERNAL": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of when the app.update.staging.enabled boolean preference is not the default value of true (true values are not submitted)" + }, + "UPDATE_NOT_PREF_UPDATE_STAGING_ENABLED_NOTIFY": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of when the app.update.staging.enabled boolean preference is not the default value of true (true values are not submitted)" + }, + "UPDATE_NOT_PREF_UPDATE_SERVICE_ENABLED_EXTERNAL": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of when the app.update.service.enabled boolean preference is not the default value of true (true values are not submitted)" + }, + "UPDATE_NOT_PREF_UPDATE_SERVICE_ENABLED_NOTIFY": { + "expires_in_version": "never", + "kind": "count", + "description": "Update: count of when the app.update.service.enabled boolean preference is not the default value of true (true values are not submitted)" + }, + "UPDATE_DOWNLOAD_CODE_COMPLETE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 50, + "description": "Update: complete patch download result code" + }, + "UPDATE_DOWNLOAD_CODE_PARTIAL": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 50, + "description": "Update: complete patch download result code" + }, + "UPDATE_STATE_CODE_COMPLETE_STARTUP": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 20, + "description": "Update: the state of a complete update from update.status on startup" + }, + "UPDATE_STATE_CODE_PARTIAL_STARTUP": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 20, + "description": "Update: the state of a partial patch update from update.status on startup" + }, + "UPDATE_STATE_CODE_UNKNOWN_STARTUP": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 20, + "description": "Update: the state of an unknown patch update from update.status on startup" + }, + "UPDATE_STATE_CODE_COMPLETE_STAGE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 20, + "description": "Update: the state of a complete patch update from update.status after staging" + }, + "UPDATE_STATE_CODE_PARTIAL_STAGE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 20, + "description": "Update: the state of a partial patch update from update.status after staging" + }, + "UPDATE_STATE_CODE_UNKNOWN_STAGE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 20, + "description": "Update: the state of an unknown patch update from update.status after staging" + }, + "UPDATE_STATUS_ERROR_CODE_COMPLETE_STARTUP": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 100, + "description": "Update: the status error code for a failed complete patch update from update.status on startup" + }, + "UPDATE_STATUS_ERROR_CODE_PARTIAL_STARTUP": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 100, + "description": "Update: the status error code for a failed partial patch update from update.status on startup" + }, + "UPDATE_STATUS_ERROR_CODE_UNKNOWN_STARTUP": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 100, + "description": "Update: the status error code for a failed unknown patch update from update.status on startup" + }, + "UPDATE_STATUS_ERROR_CODE_COMPLETE_STAGE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 100, + "description": "Update: the status error code for a failed complete patch update from update.status after staging" + }, + "UPDATE_STATUS_ERROR_CODE_PARTIAL_STAGE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 100, + "description": "Update: the status error code for a failed partial patch update from update.status after staging" + }, + "UPDATE_STATUS_ERROR_CODE_UNKNOWN_STAGE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 100, + "description": "Update: the status error code for a failed unknown patch update from update.status after staging" + }, + "UPDATE_WIZ_LAST_PAGE_CODE": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 30, + "description": "Update: the update wizard page displayed when the UI was closed (mapped in toolkit/mozapps/update/UpdateTelemetry.jsm)" }, "THUNDERBIRD_GLODA_SIZE_MB": { "expires_in_version": "40", diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index 8d70c41e37..370d5deb33 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -8,7 +8,7 @@ this.EXPORTED_SYMBOLS = ["AppConstants"]; // Immutable for export. -let AppConstants = Object.freeze({ +this.AppConstants = Object.freeze({ // See this wiki page for more details about channel specific build // defines: https://wiki.mozilla.org/Platform/Channel-specific_build_defines NIGHTLY_BUILD: @@ -63,6 +63,24 @@ let AppConstants = Object.freeze({ false, #endif + MOZ_SANDBOX: +#ifdef MOZ_SANDBOX + true, +#else + false, +#endif + + MOZ_SHARK: +#ifdef XP_MACOSX +#ifdef MOZ_SHARK + true, +#else + false, +#endif +#else + false, +#endif + MOZ_TELEMETRY_REPORTING: #ifdef MOZ_TELEMETRY_REPORTING true, @@ -70,6 +88,13 @@ let AppConstants = Object.freeze({ false, #endif + MOZ_UPDATER: +#ifdef MOZ_UPDATER + true, +#else + false, +#endif + MOZ_WEBRTC: #ifdef MOZ_WEBRTC true, @@ -77,6 +102,8 @@ let AppConstants = Object.freeze({ false, #endif +# NOTE! XP_LINUX has to go after MOZ_WIDGET_ANDROID otherwise Android +# builds will be misidentified as linux. platform: #ifdef MOZ_WIDGET_GTK "linux", @@ -90,6 +117,8 @@ let AppConstants = Object.freeze({ "android", #elif MOZ_WIDGET_GONK "gonk", +#elif XP_LINUX + "linux", #else "other", #endif @@ -101,7 +130,24 @@ let AppConstants = Object.freeze({ false, #endif - MOZ_APP_VERSION: "@MOZ_APP_VERSION@", + MOZ_MAINTENANCE_SERVICE: +#ifdef MOZ_MAINTENANCE_SERVICE + true, +#else + false, +#endif + E10S_TESTING_ONLY: +#ifdef E10S_TESTING_ONLY + true, +#else + false, +#endif + + MOZ_APP_NAME: "@MOZ_APP_NAME@", + MOZ_APP_VERSION: "@MOZ_APP_VERSION@", + MOZ_BUILD_APP: "@MOZ_BUILD_APP@", + MOZ_UPDATE_CHANNEL: "@MOZ_UPDATE_CHANNEL@", + MOZ_WIDGET_TOOLKIT: "@MOZ_WIDGET_TOOLKIT@", ANDROID_PACKAGE_NAME: "@ANDROID_PACKAGE_NAME@", }); diff --git a/toolkit/modules/CertUtils.jsm b/toolkit/modules/CertUtils.jsm index 00a2c52935..124e956ca9 100644 --- a/toolkit/modules/CertUtils.jsm +++ b/toolkit/modules/CertUtils.jsm @@ -1,9 +1,7 @@ -#if 0 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#endif this.EXPORTED_SYMBOLS = [ "BadCertHandler", "checkCert", "readCertPrefs", "validateCert" ]; const Ce = Components.Exception; diff --git a/toolkit/modules/GMPInstallManager.jsm b/toolkit/modules/GMPInstallManager.jsm index eac5e9c097..3c28f0c139 100644 --- a/toolkit/modules/GMPInstallManager.jsm +++ b/toolkit/modules/GMPInstallManager.jsm @@ -25,6 +25,7 @@ Cu.import("resource://gre/modules/osfile.jsm"); Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/ctypes.jsm"); Cu.import("resource://gre/modules/GMPUtils.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); this.EXPORTED_SYMBOLS = ["GMPInstallManager", "GMPExtractor", "GMPDownloader", "GMPAddon"]; @@ -62,122 +63,121 @@ function getScopedLogger(prefix) { // TODO: refactor this out somewhere else XPCOMUtils.defineLazyGetter(this, "gOSVersion", function aus_gOSVersion() { let osVersion; - let sysInfo = Cc["@mozilla.org/system-info;1"]. - getService(Ci.nsIPropertyBag2); try { - osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version"); + osVersion = Services.sysinfo.getProperty("name") + " " + + Services.sysinfo.getProperty("version"); } catch (e) { LOG("gOSVersion - OS Version unknown: updates are not possible."); } if (osVersion) { -#ifdef XP_WIN - const BYTE = ctypes.uint8_t; - const WORD = ctypes.uint16_t; - const DWORD = ctypes.uint32_t; - const WCHAR = ctypes.char16_t; - const BOOL = ctypes.int; - - // This structure is described at: - // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx - const SZCSDVERSIONLENGTH = 128; - const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW', - [ - {dwOSVersionInfoSize: DWORD}, - {dwMajorVersion: DWORD}, - {dwMinorVersion: DWORD}, - {dwBuildNumber: DWORD}, - {dwPlatformId: DWORD}, - {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)}, - {wServicePackMajor: WORD}, - {wServicePackMinor: WORD}, - {wSuiteMask: WORD}, - {wProductType: BYTE}, - {wReserved: BYTE} - ]); - - // This structure is described at: - // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx - const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO', - [ - {wProcessorArchitecture: WORD}, - {wReserved: WORD}, - {dwPageSize: DWORD}, - {lpMinimumApplicationAddress: ctypes.voidptr_t}, - {lpMaximumApplicationAddress: ctypes.voidptr_t}, - {dwActiveProcessorMask: DWORD.ptr}, - {dwNumberOfProcessors: DWORD}, - {dwProcessorType: DWORD}, - {dwAllocationGranularity: DWORD}, - {wProcessorLevel: WORD}, - {wProcessorRevision: WORD} - ]); - - let kernel32 = false; - try { - kernel32 = ctypes.open("Kernel32"); - } catch (e) { - LOG("gOSVersion - Unable to open kernel32! " + e); - osVersion += ".unknown (unknown)"; - } - - if(kernel32) { + if (AppConstants.platform == "win") { + const BYTE = ctypes.uint8_t; + const WORD = ctypes.uint16_t; + const DWORD = ctypes.uint32_t; + const WCHAR = ctypes.char16_t; + const BOOL = ctypes.int; + + // This structure is described at: + // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx + const SZCSDVERSIONLENGTH = 128; + const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW', + [ + {dwOSVersionInfoSize: DWORD}, + {dwMajorVersion: DWORD}, + {dwMinorVersion: DWORD}, + {dwBuildNumber: DWORD}, + {dwPlatformId: DWORD}, + {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)}, + {wServicePackMajor: WORD}, + {wServicePackMinor: WORD}, + {wSuiteMask: WORD}, + {wProductType: BYTE}, + {wReserved: BYTE} + ]); + + // This structure is described at: + // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx + const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO', + [ + {wProcessorArchitecture: WORD}, + {wReserved: WORD}, + {dwPageSize: DWORD}, + {lpMinimumApplicationAddress: ctypes.voidptr_t}, + {lpMaximumApplicationAddress: ctypes.voidptr_t}, + {dwActiveProcessorMask: DWORD.ptr}, + {dwNumberOfProcessors: DWORD}, + {dwProcessorType: DWORD}, + {dwAllocationGranularity: DWORD}, + {wProcessorLevel: WORD}, + {wProcessorRevision: WORD} + ]); + + let kernel32 = false; try { - // Get Service pack info + kernel32 = ctypes.open("Kernel32"); + } catch (e) { + LOG("gOSVersion - Unable to open kernel32! " + e); + osVersion += ".unknown (unknown)"; + } + + if(kernel32) { try { - let GetVersionEx = kernel32.declare("GetVersionExW", - ctypes.default_abi, - BOOL, - OSVERSIONINFOEXW.ptr); - let winVer = OSVERSIONINFOEXW(); - winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size; - - if(0 !== GetVersionEx(winVer.address())) { - osVersion += "." + winVer.wServicePackMajor - + "." + winVer.wServicePackMinor; - } else { - LOG("gOSVersion - Unknown failure in GetVersionEX (returned 0)"); + // Get Service pack info + try { + let GetVersionEx = kernel32.declare("GetVersionExW", + ctypes.default_abi, + BOOL, + OSVERSIONINFOEXW.ptr); + let winVer = OSVERSIONINFOEXW(); + winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size; + + if(0 !== GetVersionEx(winVer.address())) { + osVersion += "." + winVer.wServicePackMajor + + "." + winVer.wServicePackMinor; + } else { + LOG("gOSVersion - Unknown failure in GetVersionEX (returned 0)"); + osVersion += ".unknown"; + } + } catch (e) { + LOG("gOSVersion - error getting service pack information. Exception: " + e); osVersion += ".unknown"; } - } catch (e) { - LOG("gOSVersion - error getting service pack information. Exception: " + e); - osVersion += ".unknown"; - } - - // Get processor architecture - let arch = "unknown"; - try { - let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo", - ctypes.default_abi, - ctypes.void_t, - SYSTEM_INFO.ptr); - let sysInfo = SYSTEM_INFO(); - // Default to unknown - sysInfo.wProcessorArchitecture = 0xffff; - - GetNativeSystemInfo(sysInfo.address()); - switch(sysInfo.wProcessorArchitecture) { - case 9: - arch = "x64"; - break; - case 6: - arch = "IA64"; - break; - case 0: - arch = "x86"; - break; + + // Get processor architecture + let arch = "unknown"; + try { + let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo", + ctypes.default_abi, + ctypes.void_t, + SYSTEM_INFO.ptr); + let sysInfo = SYSTEM_INFO(); + // Default to unknown + sysInfo.wProcessorArchitecture = 0xffff; + + GetNativeSystemInfo(sysInfo.address()); + switch(sysInfo.wProcessorArchitecture) { + case 9: + arch = "x64"; + break; + case 6: + arch = "IA64"; + break; + case 0: + arch = "x86"; + break; + } + } catch (e) { + LOG("gOSVersion - error getting processor architecture. Exception: " + e); + } finally { + osVersion += " (" + arch + ")"; } - } catch (e) { - LOG("gOSVersion - error getting processor architecture. Exception: " + e); } finally { - osVersion += " (" + arch + ")"; + kernel32.close(); } - } finally { - kernel32.close(); } } -#endif try { osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")"; @@ -201,19 +201,15 @@ XPCOMUtils.defineLazyGetter(this, "gABI", function aus_gABI() { catch (e) { LOG("gABI - XPCOM ABI unknown: updates are not possible."); } -#ifdef XP_MACOSX - // Mac universal build should report a different ABI than either macppc - // or mactel. - let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"]. - getService(Ci.nsIMacUtils); + if (AppConstants.platform == "macosx") { + // Mac universal build should report a different ABI than either macppc + // or mactel. + let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"]. + getService(Ci.nsIMacUtils); - if (macutils.isUniversalBinary) - abi += "-u-" + macutils.architecturesInBinary; -#ifdef MOZ_SHARK - // Disambiguate optimised and shark nightlies - abi += "-shark" -#endif -#endif + if (macutils.isUniversalBinary) + abi += "-u-" + macutils.architecturesInBinary; + } return abi; }); diff --git a/toolkit/modules/LightweightThemeConsumer.jsm b/toolkit/modules/LightweightThemeConsumer.jsm index 338597351e..815ab86e52 100644 --- a/toolkit/modules/LightweightThemeConsumer.jsm +++ b/toolkit/modules/LightweightThemeConsumer.jsm @@ -8,6 +8,7 @@ const {utils: Cu} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer", "resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm"); @@ -144,13 +145,12 @@ LightweightThemeConsumer.prototype = { footer.removeAttribute("lwthemefooter"); } -#ifdef XP_MACOSX // On OS X, we extend the lightweight theme into the titlebar, which means setting // the chromemargin attribute. Some XUL applications already draw in the titlebar, // so we need to save the chromemargin value before we overwrite it with the value // that lets us draw in the titlebar. We stash this value on the root attribute so // that XUL applications have the ability to invalidate the saved value. - if (stateChanging) { + if (AppConstants.platform == "macosx" && stateChanging) { if (!root.hasAttribute("chromemargin-nonlwtheme")) { root.setAttribute("chromemargin-nonlwtheme", root.getAttribute("chromemargin")); } @@ -166,7 +166,6 @@ LightweightThemeConsumer.prototype = { } } } -#endif Services.obs.notifyObservers(this._win, "lightweight-theme-window-updated", JSON.stringify(aData)); } diff --git a/toolkit/modules/Troubleshoot.jsm b/toolkit/modules/Troubleshoot.jsm index 06747b0199..be999c1c56 100644 --- a/toolkit/modules/Troubleshoot.jsm +++ b/toolkit/modules/Troubleshoot.jsm @@ -10,6 +10,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/AddonManager.jsm"); Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); let Experiments; try { @@ -156,9 +157,8 @@ let dataProviders = { safeMode: Services.appinfo.inSafeMode, }; -#ifdef MOZ_UPDATER - data.updateChannel = Cu.import("resource://gre/modules/UpdateChannel.jsm", {}).UpdateChannel.get(); -#endif + if (AppConstants.MOZ_UPDATER) + data.updateChannel = Cu.import("resource://gre/modules/UpdateChannel.jsm", {}).UpdateChannel.get(); try { data.vendor = Services.prefs.getCharPref("app.support.vendor"); @@ -346,12 +346,9 @@ let dataProviders = { } if (!data.numAcceleratedWindows && gfxInfo) { - let feature = -#ifdef XP_WIN - gfxInfo.FEATURE_DIRECT3D_9_LAYERS; -#else - gfxInfo.FEATURE_OPENGL_LAYERS; -#endif + let win = AppConstants.platform == "win"; + let feature = win ? gfxInfo.FEATURE_DIRECT3D_9_LAYERS : + gfxInfo.FEATURE_OPENGL_LAYERS; data.numAcceleratedWindowsMessage = statusMsgForFeature(feature); } @@ -422,20 +419,20 @@ let dataProviders = { + " -- " + gl.getParameter(ext.UNMASKED_RENDERER_WEBGL); } else { - let feature = -#ifdef XP_WIN + let feature; + if (AppConstants.platform == "win") { // If ANGLE is not available but OpenGL is, we want to report on the // OpenGL feature, because that's what's going to get used. In all // other cases we want to report on the ANGLE feature. - gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_WEBGL_ANGLE) != - Ci.nsIGfxInfo.FEATURE_STATUS_OK && - gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_WEBGL_OPENGL) == - Ci.nsIGfxInfo.FEATURE_STATUS_OK ? - Ci.nsIGfxInfo.FEATURE_WEBGL_OPENGL : - Ci.nsIGfxInfo.FEATURE_WEBGL_ANGLE; -#else - Ci.nsIGfxInfo.FEATURE_WEBGL_OPENGL; -#endif + let angle = gfxInfo.getFeatureStatus(gfxInfo.FEATURE_WEBGL_ANGLE) == + gfxInfo.FEATURE_STATUS_OK; + let opengl = gfxInfo.getFeatureStatus(gfxInfo.FEATURE_WEBGL_OPENGL) == + gfxInfo.FEATURE_STATUS_OK; + feature = !angle && opengl ? gfxInfo.FEATURE_WEBGL_OPENGL : + gfxInfo.FEATURE_WEBGL_ANGLE; + } else { + feature = gfxInfo.FEATURE_WEBGL_OPENGL; + } data.webglRendererMessage = statusMsgForFeature(feature); } @@ -508,10 +505,24 @@ let dataProviders = { done({ exists: userJSFile.exists() && userJSFile.fileSize > 0, }); - }, + } +}; -#if defined(XP_LINUX) && defined (MOZ_SANDBOX) - sandbox: function sandbox(done) { +if (AppConstants.MOZ_CRASHREPORTER) { + dataProviders.crashes = function crashes(done) { + let CrashReports = Cu.import("resource://gre/modules/CrashReports.jsm").CrashReports; + let reports = CrashReports.getReports(); + let now = new Date(); + let reportsNew = reports.filter(report => (now - report.date < Troubleshoot.kMaxCrashAge)); + let reportsSubmitted = reportsNew.filter(report => (!report.pending)); + let reportsPendingCount = reportsNew.length - reportsSubmitted.length; + let data = {submitted : reportsSubmitted, pending : reportsPendingCount}; + done(data); + } +} + +if (AppConstants.platform == "linux" && AppConstants.MOZ_SANDBOX) { + dataProviders.sandbox = function sandbox(done) { const keys = ["hasSeccompBPF", "hasSeccompTSync", "hasPrivilegedUserNamespaces", "hasUserNamespaces", "canSandboxContent", "canSandboxMedia"]; @@ -526,5 +537,4 @@ let dataProviders = { } done(data); } -#endif -}; +} diff --git a/toolkit/modules/WindowDraggingUtils.jsm b/toolkit/modules/WindowDraggingUtils.jsm index da292c4220..ea1cdd07b2 100644 --- a/toolkit/modules/WindowDraggingUtils.jsm +++ b/toolkit/modules/WindowDraggingUtils.jsm @@ -2,23 +2,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifdef XP_WIN -#define USE_HITTEST -#elifdef MOZ_WIDGET_COCOA -#define USE_HITTEST -#endif +Components.utils.import("resource://gre/modules/AppConstants.jsm"); + +const USE_HITTEST = /^(win|macosx)/i.test(AppConstants.platform); this.EXPORTED_SYMBOLS = [ "WindowDraggingElement" ]; this.WindowDraggingElement = function WindowDraggingElement(elem) { this._elem = elem; this._window = elem.ownerDocument.defaultView; -#ifdef USE_HITTEST - if (!this.isPanel()) + + if (USE_HITTEST && !this.isPanel()) this._elem.addEventListener("MozMouseHittest", this, false); else -#endif - this._elem.addEventListener("mousedown", this, false); + this._elem.addEventListener("mousedown", this, false); }; WindowDraggingElement.prototype = { @@ -60,24 +57,23 @@ WindowDraggingElement.prototype = { }, handleEvent: function(aEvent) { let isPanel = this.isPanel(); -#ifdef USE_HITTEST - if (!isPanel) { + if (USE_HITTEST && !isPanel) { if (this.shouldDrag(aEvent)) aEvent.preventDefault(); return; } -#endif switch (aEvent.type) { case "mousedown": if (!this.shouldDrag(aEvent)) return; -#ifdef MOZ_WIDGET_GTK - // On GTK, there is a toolkit-level function which handles - // window dragging, which must be used. - this._window.beginWindowMove(aEvent, isPanel ? this._elem : null); -#else + if (/^gtk/i.test(AppConstants.MOZ_WIDGET_TOOLKIT)) { + // On GTK, there is a toolkit-level function which handles + // window dragging, which must be used. + this._window.beginWindowMove(aEvent, isPanel ? this._elem : null); + break; + } if (isPanel) { let screenRect = this._elem.getOuterScreenRect(); this._deltaX = aEvent.screenX - screenRect.left; @@ -90,7 +86,6 @@ WindowDraggingElement.prototype = { this._draggingWindow = true; this._window.addEventListener("mousemove", this, false); this._window.addEventListener("mouseup", this, false); -#endif break; case "mousemove": if (this._draggingWindow) { diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index c2ea65e2fe..5c878d7ab3 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -16,6 +16,7 @@ EXTRA_JS_MODULES += [ 'Battery.jsm', 'BinarySearch.jsm', 'BrowserUtils.jsm', + 'CertUtils.jsm', 'CharsetMenu.jsm', 'debug.js', 'DeferredTask.jsm', @@ -24,6 +25,7 @@ EXTRA_JS_MODULES += [ 'FileUtils.jsm', 'Finder.jsm', 'Geometry.jsm', + 'GMPInstallManager.jsm', 'GMPUtils.jsm', 'Http.jsm', 'InlineSpellChecker.jsm', @@ -47,6 +49,8 @@ EXTRA_JS_MODULES += [ 'RemoteSecurityUI.jsm', 'RemoteWebNavigation.jsm', 'RemoteWebProgress.jsm', + 'ResetProfile.jsm', + 'secondscreen/RokuApp.jsm', 'secondscreen/SimpleServiceDiscovery.jsm', 'SelectContentHelper.jsm', 'SelectParentHelper.jsm', @@ -60,24 +64,21 @@ EXTRA_JS_MODULES += [ 'Task.jsm', 'TelemetryTimestamps.jsm', 'Timer.jsm', + 'Troubleshoot.jsm', 'WebChannel.jsm', + 'WindowDraggingUtils.jsm', 'ZipUtils.jsm', ] EXTRA_PP_JS_MODULES += [ - 'CertUtils.jsm', - 'GMPInstallManager.jsm', - 'ResetProfile.jsm', - 'secondscreen/RokuApp.jsm', + 'AppConstants.jsm', 'Services.jsm', - 'Troubleshoot.jsm', 'UpdateChannel.jsm', - 'WindowDraggingUtils.jsm', 'WindowsPrefSync.jsm', ] if 'Android' != CONFIG['OS_TARGET']: - EXTRA_PP_JS_MODULES += [ + EXTRA_JS_MODULES += [ 'LightweightThemeConsumer.jsm', ] else: @@ -91,14 +92,12 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': for var in ('ANDROID_PACKAGE_NAME', 'MOZ_APP_NAME', - 'MOZ_APP_VERSION'): + 'MOZ_APP_VERSION', + 'MOZ_WIDGET_TOOLKIT'): DEFINES[var] = CONFIG[var] for var in ('MOZILLA_OFFICIAL', - 'MOZ_TOOLKIT_SEARCH'): + 'MOZ_TOOLKIT_SEARCH', + 'MOZ_UPDATER'): if CONFIG[var]: DEFINES[var] = True - -EXTRA_PP_JS_MODULES += [ - 'AppConstants.jsm', -] diff --git a/toolkit/modules/secondscreen/RokuApp.jsm b/toolkit/modules/secondscreen/RokuApp.jsm index 15a9ce2801..0f8ed712c2 100644 --- a/toolkit/modules/secondscreen/RokuApp.jsm +++ b/toolkit/modules/secondscreen/RokuApp.jsm @@ -10,6 +10,7 @@ this.EXPORTED_SYMBOLS = ["RokuApp"]; const { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AppConstants.jsm"); const WEBRTC_PLAYER_NAME = "WebRTC Player"; const MIRROR_PORT = 8011; @@ -28,11 +29,7 @@ const PROTOCOL_VERSION = 1; function RokuApp(service) { this.service = service; this.resourceURL = this.service.location; -#ifdef RELEASE_BUILD - this.app = "Firefox"; -#else - this.app = "Firefox Nightly"; -#endif + this.app = AppConstants.RELEASE_BUILD ? "Firefox" : "Firefox Nightly"; this.mediaAppID = -1; this.mirrorAppID = -1; } diff --git a/toolkit/mozapps/update/UpdateTelemetry.jsm b/toolkit/mozapps/update/UpdateTelemetry.jsm new file mode 100644 index 0000000000..5324b1cc5c --- /dev/null +++ b/toolkit/mozapps/update/UpdateTelemetry.jsm @@ -0,0 +1,520 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = [ + "AUSTLMY" +]; + +const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components; + +Cu.import("resource://gre/modules/Services.jsm", this); + +this.AUSTLMY = { + // Telemetry for the application update background update check occurs when + // the background update timer fires after the update interval which is + // determined by the app.update.interval preference and its telemetry + // histogram IDs have the suffix '_NOTIFY'. + // Telemetry for the externally initiated background update check occurs when + // a call is made to |checkForBackgroundUpdates| which is typically initiated + // by an application when it has determined that the application should have + // received an update. This has separate telemetry so it is possible to + // analyze using the telemetry data systems that have not been updating when + // they should have. + + // The update check was performed by the call to checkForBackgroundUpdates in + // nsUpdateService.js. + EXTERNAL: "EXTERNAL", + // The update check was performed by the call to notify in nsUpdateService.js. + NOTIFY: "NOTIFY", + + /** + * Values for the UPDATE_CHECK_CODE_NOTIFY and UPDATE_CHECK_CODE_EXTERNAL + * Telemetry histograms. + */ + // No update found (no notification) + CHK_NO_UPDATE_FOUND: 0, + // No incompatible add-ons found during incompatible check (background download) + CHK_ADDON_NO_INCOMPAT: 1, + // Showing prompt due to the update.xml specifying showPrompt + // (update notification) + CHK_SHOWPROMPT_SNIPPET: 2, + // Showing prompt due to preference (update notification) + CHK_SHOWPROMPT_PREF: 3, + // Incompatible add-on check disabled by preference (background download) + CHK_ADDON_PREF_DISABLED: 4, + // Incompatible add-on checke not performed due to same app version as the + // update's app version (background download) + CHK_ADDON_SAME_APP_VER: 5, + // Incompatible add-ons found and all of them have updates (background download) + CHK_ADDON_UPDATES_FOR_INCOMPAT: 6, + // Incompatible add-ons found (update notification) + CHK_ADDON_HAVE_INCOMPAT: 7, + // Already has an active update in progress (no notification) + CHK_HAS_ACTIVEUPDATE: 8, + // A background download is already in progress (no notification) + CHK_IS_DOWNLOADING: 9, + // An update is already staged (no notification) + CHK_IS_STAGED: 10, + // An update is already downloaded (no notification) + CHK_IS_DOWNLOADED: 11, + // Background checks disabled by preference (no notification) + CHK_PREF_DISABLED: 12, + // Update checks disabled by admin locked preference (no notification) + CHK_ADMIN_DISABLED: 13, + // Unable to check for updates per hasUpdateMutex() (no notification) + CHK_NO_MUTEX: 14, + // Unable to check for updates per gCanCheckForUpdates (no notification). This + // should be covered by other codes and is recorded just in case. + CHK_UNABLE_TO_CHECK: 15, + // Background checks disabled for the current session (no notification) + CHK_DISABLED_FOR_SESSION: 16, + // Unable to perform a background check while offline (no notification) + CHK_OFFLINE: 17, + // No update found certificate check failed and threshold reached + // (possible mitm attack notification) + CHK_CERT_ATTR_NO_UPDATE_PROMPT: 18, + // No update found certificate check failed and threshold not reached + // (no notification) + CHK_CERT_ATTR_NO_UPDATE_SILENT: 19, + // Update found certificate check failed and threshold reached + // (possible mitm attack notification) + CHK_CERT_ATTR_WITH_UPDATE_PROMPT: 20, + // Update found certificate check failed and threshold not reached + // (no notification) + CHK_CERT_ATTR_WITH_UPDATE_SILENT: 21, + // General update check failure and threshold reached + // (check failure notification) + CHK_GENERAL_ERROR_PROMPT: 22, + // General update check failure and threshold not reached (no notification) + CHK_GENERAL_ERROR_SILENT: 23, + // No compatible update found though there were updates (no notification) + CHK_NO_COMPAT_UPDATE_FOUND: 24, + // Update found for a previous version (no notification) + CHK_UPDATE_PREVIOUS_VERSION: 25, + // Update found for a version with the never preference set (no notification) + CHK_UPDATE_NEVER_PREF: 26, + // Update found without a type attribute (no notification) + CHK_UPDATE_INVALID_TYPE: 27, + // The system is no longer supported (system unsupported notification) + CHK_UNSUPPORTED: 28, + // Unable to apply updates (manual install to update notification) + CHK_UNABLE_TO_APPLY: 29, + // Unable to check for updates due to no OS version (no notification) + CHK_NO_OS_VERSION: 30, + // Unable to check for updates due to no OS ABI (no notification) + CHK_NO_OS_ABI: 31, + // Invalid url for app.update.url default preference (no notification) + CHK_INVALID_DEFAULT_URL: 32, + // Invalid url for app.update.url user preference (no notification) + CHK_INVALID_USER_OVERRIDE_URL: 33, + // Invalid url for app.update.url.override user preference (no notification) + CHK_INVALID_DEFAULT_OVERRIDE_URL: 34, + + /** + * Submit a telemetry ping for the update check result code or a telemetry + * ping for a count type histogram count when no update was found. The no + * update found ping is separate since it is the typical result, is less + * interesting than the other result codes, and it is easier to analyze the + * other codes without including it. + * + * @param aSuffix + * The histogram id suffix for histogram IDs: + * UPDATE_CHECK_CODE_EXTERNAL + * UPDATE_CHECK_CODE_NOTIFY + * UPDATE_CHECK_NO_UPDATE_EXTERNAL + * UPDATE_CHECK_NO_UPDATE_NOTIFY + * @param aCode + * An integer value as defined by the values that start with CHK_ in + * the above section. + */ + pingCheckCode: function UT_pingCheckCode(aSuffix, aCode) { + try { + if (aCode == this.CHK_NO_UPDATE_FOUND) { + let id = "UPDATE_CHECK_NO_UPDATE_" + aSuffix; + // count type histogram + Services.telemetry.getHistogramById(id).add(); + } else { + let id = "UPDATE_CHECK_CODE_" + aSuffix; + // enumerated type histogram + Services.telemetry.getHistogramById(id).add(aCode); + } + } catch (e) { + Cu.reportError(e); + } + }, + + /** + * Submit a telemetry ping for a failed update check's unhandled error code + * when the pingCheckCode is CHK_GENERAL_ERROR_SILENT. The histogram is a + * keyed count type with key names that are prefixed with 'AUS_CHECK_EX_ERR_'. + * + * @param aSuffix + * The histogram id suffix for histogram IDs: + * UPDATE_CHK_EXTENDED_ERROR_EXTERNAL + * UPDATE_CHK_EXTENDED_ERROR_NOTIFY + * @param aCode + * The extended error value return by a failed update check. + */ + pingCheckExError: function UT_pingCheckExError(aSuffix, aCode) { + try { + let id = "UPDATE_CHECK_EXTENDED_ERROR_" + aSuffix; + let val = "AUS_CHECK_EX_ERR_" + aCode; + // keyed count type histogram + Services.telemetry.getKeyedHistogramById(id).add(val); + } catch (e) { + Cu.reportError(e); + } + }, + + // The state code and if present the status error code were read on startup. + STARTUP: "STARTUP", + // The state code and status error code if present were read after staging. + STAGE: "STAGE", + + // Patch type Complete + PATCH_COMPLETE: "COMPLETE", + // Patch type partial + PATCH_PARTIAL: "PARTIAL", + // Patch type unknown + PATCH_UNKNOWN: "UNKNOWN", + + /** + * Values for the UPDATE_DOWNLOAD_CODE_COMPLETE and + * UPDATE_DOWNLOAD_CODE_PARTIAL Telemetry histograms. + */ + DWNLD_SUCCESS: 0, + DWNLD_RETRY_OFFLINE: 1, + DWNLD_RETRY_NET_TIMEOUT: 2, + DWNLD_RETRY_CONNECTION_REFUSED: 3, + DWNLD_RETRY_NET_RESET: 4, + DWNLD_ERR_NO_UPDATE: 5, + DWNLD_ERR_NO_UPDATE_PATCH: 6, + DWNLD_ERR_NO_PATCH_FILE: 7, + DWNLD_ERR_PATCH_SIZE_LARGER: 8, + DWNLD_ERR_PATCH_SIZE_NOT_EQUAL: 9, + DWNLD_ERR_BINDING_ABORTED: 10, + DWNLD_ERR_ABORT: 11, + DWNLD_ERR_DOCUMENT_NOT_CACHED: 12, + DWNLD_ERR_VERIFY_NO_REQUEST: 13, + DWNLD_ERR_VERIFY_PATCH_SIZE_NOT_EQUAL: 14, + DWNLD_ERR_VERIFY_NO_HASH_MATCH: 15, + + /** + * Submit a telemetry ping for the update download result code. + * + * @param aIsComplete + * If true the histogram is for a patch type complete, if false the + * histogram is for a patch type partial, and when undefined the + * histogram is for an unknown patch type. This is used to determine + * the histogram ID out of the following histogram IDs: + * UPDATE_DOWNLOAD_CODE_COMPLETE + * UPDATE_DOWNLOAD_CODE_PARTIAL + * @param aCode + * An integer value as defined by the values that start with DWNLD_ in + * the above section. + */ + pingDownloadCode: function UT_pingDownloadCode(aIsComplete, aCode) { + let patchType = this.PATCH_UNKNOWN; + if (aIsComplete === true) { + patchType = this.PATCH_COMPLETE; + } else if (aIsComplete === false) { + patchType = this.PATCH_PARTIAL; + } + try { + let id = "UPDATE_DOWNLOAD_CODE_" + patchType; + // enumerated type histogram + Services.telemetry.getHistogramById(id).add(aCode); + } catch (e) { + Cu.reportError(e); + } + }, + + /** + * Submit a telemetry ping for the update status state code. + * + * @param aSuffix + * The histogram id suffix for histogram IDs: + * UPDATE_STATE_CODE_COMPLETE_STARTUP + * UPDATE_STATE_CODE_PARTIAL_STARTUP + * UPDATE_STATE_CODE_UNKNOWN_STARTUP + * UPDATE_STATE_CODE_COMPLETE_STAGE + * UPDATE_STATE_CODE_PARTIAL_STAGE + * UPDATE_STATE_CODE_UNKNOWN_STAGE + * @param aCode + * An integer value as defined by the values that start with STATE_ in + * the above section for the update state from the update.status file. + */ + pingStateCode: function UT_pingStateCode(aSuffix, aCode) { + try { + let id = "UPDATE_STATE_CODE_" + aSuffix; + // enumerated type histogram + Services.telemetry.getHistogramById(id).add(aCode); + } catch(e) { + Cu.reportError(e); + } + }, + + /** + * Submit a telemetry ping for the update status error code. This does not + * submit a success value which can be determined from the state code. + * + * @param aSuffix + * The histogram id suffix for histogram IDs: + * UPDATE_STATUS_ERROR_CODE_COMPLETE_STARTUP + * UPDATE_STATUS_ERROR_CODE_PARTIAL_STARTUP + * UPDATE_STATUS_ERROR_CODE_UNKNOWN_STARTUP + * UPDATE_STATUS_ERROR_CODE_COMPLETE_STAGE + * UPDATE_STATUS_ERROR_CODE_PARTIAL_STAGE + * UPDATE_STATUS_ERROR_CODE_UNKNOWN_STAGE + * @param aCode + * An integer value for the error code from the update.status file. + */ + pingStatusErrorCode: function UT_pingStatusErrorCode(aSuffix, aCode) { + try { + let id = "UPDATE_STATUS_ERROR_CODE_" + aSuffix; + // enumerated type histogram + Services.telemetry.getHistogramById(id).add(aCode); + } catch(e) { + Cu.reportError(e); + } + }, + + /** + * Submit the interval in days since the last notification for this background + * update check or a boolean if the last notification is in the future. + * + * @param aSuffix + * The histogram id suffix for histogram IDs: + * UPDATE_INVALID_LASTUPDATETIME_EXTERNAL + * UPDATE_INVALID_LASTUPDATETIME_NOTIFY + * UPDATE_LAST_NOTIFY_INTERVAL_DAYS_EXTERNAL + * UPDATE_LAST_NOTIFY_INTERVAL_DAYS_NOTIFY + */ + pingLastUpdateTime: function UT_pingLastUpdateTime(aSuffix) { + const PREF_APP_UPDATE_LASTUPDATETIME = "app.update.lastUpdateTime.background-update-timer"; + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_LASTUPDATETIME)) { + let lastUpdateTimeSeconds = Services.prefs.getIntPref(PREF_APP_UPDATE_LASTUPDATETIME); + if (lastUpdateTimeSeconds) { + let currentTimeSeconds = Math.round(Date.now() / 1000); + if (lastUpdateTimeSeconds > currentTimeSeconds) { + try { + let id = "UPDATE_INVALID_LASTUPDATETIME_" + aSuffix; + // count type histogram + Services.telemetry.getHistogramById().add(); + } catch(e) { + Cu.reportError(e); + } + } else { + let intervalDays = (currentTimeSeconds - lastUpdateTimeSeconds) / + (60 * 60 * 24); + try { + let id = "UPDATE_LAST_NOTIFY_INTERVAL_DAYS_" + aSuffix; + // exponential type histogram + Services.telemetry.getHistogramById(id).add(intervalDays); + } catch(e) { + Cu.reportError(e); + } + } + } + } + }, + + /** + * Submit a telemetry ping for the last page displayed by the update wizard. + * + * @param aPageID + * The page id for the last page displayed. + */ + pingWizLastPageCode: function UT_pingWizLastPageCode(aPageID) { + let pageMap = { invalid: 0, + dummy: 1, + checking: 2, + pluginupdatesfound: 3, + noupdatesfound: 4, + manualUpdate: 5, + unsupported: 6, + incompatibleCheck: 7, + updatesfoundbasic: 8, + updatesfoundbillboard: 9, + license: 10, + incompatibleList: 11, + downloading: 12, + errors: 13, + errorextra: 14, + errorpatching: 15, + finished: 16, + finishedBackground: 17, + installed: 18 }; + try { + let id = "UPDATE_WIZ_LAST_PAGE_CODE"; + // enumerated type histogram + Services.telemetry.getHistogramById(id).add(pageMap[aPageID] || + pageMap.invalid); + } catch (e) { + Cu.reportError(e); + } + }, + + /** + * Submit a telemetry ping for a boolean type histogram that indicates if the + * service is installed and a telemetry ping for a boolean type histogram that + * indicates if the service was at some point installed and is now + * uninstalled. + * Note: the total for the following histogram IDs can be used to determine + * the total number of telemetry timer and externally initiated + * submissions for systems that build with MOZ_MAINTENANCE_SERVICE + * defined: + * UPDATE_SERVICE_INSTALLED_EXTERNAL + * UPDATE_SERVICE_INSTALLED_NOTIFY + * + * @param aSuffix + * The histogram id suffix for histogram IDs: + * UPDATE_SERVICE_INSTALLED_EXTERNAL + * UPDATE_SERVICE_INSTALLED_NOTIFY + * UPDATE_SERVICE_MANUALLY_UNINSTALLED_EXTERNAL + * UPDATE_SERVICE_MANUALLY_UNINSTALLED_NOTIFY + * @param aInstalled + * Whether the service is installed. + */ + pingServiceInstallStatus: function UT_PSIS(aSuffix, aInstalled) { + // Report the error but don't throw since it is more important to + // successfully update than to throw. + if (!("@mozilla.org/windows-registry-key;1" in Cc)) { + Cu.reportError(Cr.NS_ERROR_NOT_AVAILABLE); + return; + } + + try { + let id = "UPDATE_SERVICE_INSTALLED_" + aSuffix; + // boolean type histogram + Services.telemetry.getHistogramById(id).add(aInstalled); + } catch(e) { + Cu.reportError(e); + } + + let attempted = 0; + try { + let wrk = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); + wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE, + "SOFTWARE\\Mozilla\\MaintenanceService", + wrk.ACCESS_READ | wrk.WOW64_64); + // Was the service at some point installed, but is now uninstalled? + attempted = wrk.readIntValue("Attempted"); + wrk.close(); + } catch(e) { + // Since this will throw if the registry key doesn't exist (e.g. the + // service has never been installed) don't report an error. + } + + try { + let id = "UPDATE_SERVICE_MANUALLY_UNINSTALLED_" + aSuffix; + if (!aInstalled && attempted) { + // count type histogram + Services.telemetry.getHistogramById(id).add(); + } + } catch(e) { + Cu.reportError(e); + } + }, + + /** + * Submit a telemetry ping for a count type histogram when the expected value + * does not equal the boolean value of a pref or if the pref isn't present + * when the expected value does not equal default value. This lessens the + * amount of data submitted to telemetry. + * + * @param aID + * The histogram ID to report to. + * @param aPref + * The preference to check. + * @param aDefault + * The default value when the preference isn't present. + * @param aExpected (optional) + * If specified and the value is the same as the value that will be + * added the value won't be added to telemetry. + */ + pingBoolPref: function UT_pingBoolPref(aID, aPref, aDefault, aExpected) { + try { + let val = aDefault; + if (Services.prefs.getPrefType(aPref) != Ci.nsIPrefBranch.PREF_INVALID) { + val = Services.prefs.getBoolPref(aPref); + } + if (val != aExpected) { + // count type histogram + Services.telemetry.getHistogramById(aID).add(); + } + } catch(e) { + Cu.reportError(e); + } + }, + + /** + * Submit a telemetry ping for a histogram with the integer value of a + * preference when it is not the expected value or the default value when it + * is not the expected value. This lessens the amount of data submitted to + * telemetry. + * + * @param aID + * The histogram ID to report to. + * @param aPref + * The preference to check. + * @param aDefault + * The default value when the pref is not set. + * @param aExpected (optional) + * If specified and the value is the same as the value that will be + * added the value won't be added to telemetry. + */ + pingIntPref: function UT_pingIntPref(aID, aPref, aDefault, aExpected) { + try { + let val = aDefault; + if (Services.prefs.getPrefType(aPref) != Ci.nsIPrefBranch.PREF_INVALID) { + val = Services.prefs.getIntPref(aPref); + } + if (aExpected === undefined || val != aExpected) { + // enumerated or exponential type histogram + Services.telemetry.getHistogramById(aID).add(val); + } + } catch(e) { + Cu.reportError(e); + } + }, + + /** + * Submit a telemetry ping for all histogram types that take a single + * parameter to the telemetry add function and the count type histogram when + * the aExpected parameter is specified. If the aExpected parameter is + * specified and it equals the value specified by the aValue + * parameter the telemetry submission will be skipped. + * Note: the total for the following histogram IDs can be used to determine + * the total number of telemetry timer and externally initiated + * submissions: + * UPDATE_CANNOT_APPLY_EXTERNAL + * UPDATE_CANNOT_APPLY_NOTIFY + * + * @param aID + * The histogram ID to report to. + * @param aValue + * The value to add when aExpected is not defined or the value to + * check if it is equal to when aExpected is defined. + * @param aExpected (optional) + * If specified and the value is the same as the value specified by + * aValue parameter the submission will be skipped. + */ + pingGeneric: function UT_pingGeneric(aID, aValue, aExpected) { + try { + if (aExpected === undefined) { + Services.telemetry.getHistogramById(aID).add(aValue); + } else if (aValue != aExpected) { + // count type histogram + Services.telemetry.getHistogramById(aID).add(); + } + } catch(e) { + Cu.reportError(e); + } + } +}; +Object.freeze(AUSTLMY); diff --git a/toolkit/mozapps/update/UpdaterHealthProvider.jsm b/toolkit/mozapps/update/UpdaterHealthProvider.jsm deleted file mode 100644 index d15e0cf86d..0000000000 --- a/toolkit/mozapps/update/UpdaterHealthProvider.jsm +++ /dev/null @@ -1,69 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = [ - "UpdateProvider", -]; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Metrics.jsm", this); -Cu.import("resource://gre/modules/Task.jsm", this); - -const DAILY_COUNTER_FIELD = {type: Metrics.Storage.FIELD_DAILY_COUNTER}; -const DAILY_DISCRETE_NUMERIC_FIELD = {type: Metrics.Storage.FIELD_DAILY_DISCRETE_NUMERIC}; - -function UpdateMeasurement1() { - Metrics.Measurement.call(this); -} - -UpdateMeasurement1.prototype = Object.freeze({ - __proto__: Metrics.Measurement.prototype, - - name: "update", - version: 1, - - fields: { - updateCheckStartCount: DAILY_COUNTER_FIELD, - updateCheckSuccessCount: DAILY_COUNTER_FIELD, - updateCheckFailedCount: DAILY_COUNTER_FIELD, - updateCheckFailedStatuses: DAILY_DISCRETE_NUMERIC_FIELD, - completeUpdateStartCount: DAILY_COUNTER_FIELD, - partialUpdateStartCount: DAILY_COUNTER_FIELD, - completeUpdateSuccessCount: DAILY_COUNTER_FIELD, - partialUpdateSuccessCount: DAILY_COUNTER_FIELD, - updateFailedCount: DAILY_COUNTER_FIELD, - updateFailedStatuses: DAILY_DISCRETE_NUMERIC_FIELD, - }, -}); - -this.UpdateProvider = function () { - Metrics.Provider.call(this); -}; -UpdateProvider.prototype = Object.freeze({ - __proto__: Metrics.Provider.prototype, - - name: "org.mozilla.update", - - measurementTypes: [ - UpdateMeasurement1, - ], - - recordUpdate: function (field, status) { - let m = this.getMeasurement(UpdateMeasurement1.prototype.name, - UpdateMeasurement1.prototype.version); - - return this.enqueueStorageOperation(function recordUpdateFields() { - return Task.spawn(function recordUpdateFieldsTask() { - yield m.incrementDailyCounter(field + "Count"); - - if ((field == "updateFailed" || field == "updateCheckFailed") && status) { - yield m.addDailyDiscreteNumeric(field + "Statuses", status); - } - }.bind(this)); - }.bind(this)); - }, -}); diff --git a/toolkit/mozapps/update/common/errors.h b/toolkit/mozapps/update/common/errors.h index 03c1ed5d6d..c284fd481b 100644 --- a/toolkit/mozapps/update/common/errors.h +++ b/toolkit/mozapps/update/common/errors.h @@ -9,9 +9,12 @@ #define OK 0 -// Old unused error codes: -// #define MEM_ERROR 1 // Replaced with errors 10-16 (inclusive) -// #define IO_ERROR 2 // Use READ_ERROR or WRITE_ERROR instead +// Error codes that are no longer used should not be used again unless they +// aren't used in client code (e.g. nsUpdateService.js, updates.js, +// UpdatePrompt.js, etc.). + +#define MAR_ERROR_EMPTY_ACTION_LIST 1 +#define LOADSOURCE_ERROR_WRONG_SIZE 2 // Error codes 3-16 are for general update problems. #define USAGE_ERROR 3 @@ -39,8 +42,7 @@ #define MAR_CHANNEL_MISMATCH_ERROR 22 #define VERSION_DOWNGRADE_ERROR 23 -// Error codes 24-34 are related to the maintenance service -// and so are Windows only +// Error codes 24-33 and 49 are for the Windows maintenance service. #define SERVICE_UPDATER_COULD_NOT_BE_STARTED 24 #define SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS 25 #define SERVICE_UPDATER_SIGN_ERROR 26 diff --git a/toolkit/mozapps/update/content/updates.js b/toolkit/mozapps/update/content/updates.js index f0ead6c26c..f15c33449e 100644 --- a/toolkit/mozapps/update/content/updates.js +++ b/toolkit/mozapps/update/content/updates.js @@ -5,15 +5,14 @@ 'use strict'; -Components.utils.import("resource://gre/modules/DownloadUtils.jsm"); -Components.utils.import("resource://gre/modules/AddonManager.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); - // Firefox's macBrowserOverlay.xul includes scripts that define Cc, Ci, and Cr // so we have to use different names. -const CoC = Components.classes; -const CoI = Components.interfaces; -const CoR = Components.results; +const {classes: CoC, interfaces: CoI, results: CoR, utils: CoU} = Components; + +CoU.import("resource://gre/modules/DownloadUtils.jsm", this); +CoU.import("resource://gre/modules/AddonManager.jsm", this); +CoU.import("resource://gre/modules/Services.jsm", this); +CoU.import("resource://gre/modules/UpdateTelemetry.jsm", this); const XMLNS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; @@ -22,13 +21,16 @@ const PREF_APP_UPDATE_BILLBOARD_TEST_URL = "app.update.billboard.test_url"; const PREF_APP_UPDATE_CERT_ERRORS = "app.update.cert.errors"; const PREF_APP_UPDATE_ENABLED = "app.update.enabled"; const PREF_APP_UPDATE_LOG = "app.update.log"; -const PREF_APP_UPDATE_MANUAL_URL = "app.update.url.manual"; -const PREF_APP_UPDATE_NEVER_BRANCH = "app.update.never."; const PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED = "app.update.notifiedUnsupported"; const PREF_APP_UPDATE_TEST_LOOP = "app.update.test.loop"; -const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; +const PREF_APP_UPDATE_URL_MANUAL = "app.update.url.manual"; -const UPDATE_TEST_LOOP_INTERVAL = 2000; +const PREFBRANCH_APP_UPDATE_NEVER = "app.update.never."; + +const PREF_EM_HOTFIX_ID = "extensions.hotfix.id"; +const PREF_PLUGINS_UPDATE_URL = "plugins.update.url"; + +const UPDATE_TEST_LOOP_INTERVAL = 2000; const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.properties"; @@ -143,38 +145,12 @@ var gUpdates = { _runUnload: true, /** - * Submit the last page code when the wizard exited. The pageid is used to map - * to an integer instead of using the pageindex since pages can be added and - * removed which would change the page's pageindex. - * @param pageID + * Submit on close telemtry values for the update wizard. + * @param pageID + * The page id for the last page displayed. */ - _sendLastPageCodePing: function(pageID) { - var pageMap = { invalid: 0, - dummy: 1, - checking: 2, - pluginupdatesfound: 3, - noupdatesfound: 4, - manualUpdate: 5, - unsupported: 6, - incompatibleCheck: 7, - updatesfoundbasic: 8, - updatesfoundbillboard: 9, - license: 10, - incompatibleList: 11, - downloading: 12, - errors: 13, - errorextra: 14, - errorpatching: 15, - finished: 16, - finishedBackground: 17, - installed: 18 }; - try { - Services.telemetry.getHistogramById("UPDATER_WIZ_LAST_PAGE_CODE"). - add(pageMap[pageID] || pageMap.invalid); - } - catch (e) { - Components.utils.reportError(e); - } + _submitTelemetry: function(aPageID) { + AUSTLMY.pingWizLastPageCode(aPageID); }, /** @@ -267,7 +243,7 @@ var gUpdates = { // If the user clicks "No Thanks", we should not prompt them to update to // this version again unless they manually select "Check for Updates..." // which will clear all of the "never" prefs. - var neverPrefName = PREF_APP_UPDATE_NEVER_BRANCH + this.update.appVersion; + var neverPrefName = PREFBRANCH_APP_UPDATE_NEVER + this.update.appVersion; Services.prefs.setBoolPref(neverPrefName, true); }, @@ -286,7 +262,7 @@ var gUpdates = { var pageid = document.documentElement.currentPage.pageid; if ("onWizardFinish" in this._pages[pageid]) this._pages[pageid].onWizardFinish(); - this._sendLastPageCodePing(pageid); + this._submitTelemetry(pageid); }, /** @@ -298,7 +274,7 @@ var gUpdates = { var pageid = document.documentElement.currentPage.pageid; if ("onWizardCancel" in this._pages[pageid]) this._pages[pageid].onWizardCancel(); - this._sendLastPageCodePing(pageid); + this._submitTelemetry(pageid); }, /** @@ -551,7 +527,7 @@ var gUpdates = { "or the findUpdates method!"; if (addon.id) errMsg += " Add-on ID: " + addon.id; - Components.utils.reportError(errMsg); + CoU.reportError(errMsg); return; } @@ -573,7 +549,7 @@ var gUpdates = { self.addons.push(addon); } catch (e) { - Components.utils.reportError(e); + CoU.reportError(e); } }); @@ -626,7 +602,7 @@ var gCheckingPage = { // clicked "never" for an update, selected "Check for Updates...", and // then canceled. If we don't clear the "never" prefs future // notifications will never happen. - Services.prefs.deleteBranch(PREF_APP_UPDATE_NEVER_BRANCH); + Services.prefs.deleteBranch(PREFBRANCH_APP_UPDATE_NEVER); // The user will be notified if there is an error so clear the background // check error count. @@ -737,18 +713,18 @@ var gPluginsPage = { * URL of the plugin updates page */ _url: null, - + /** * Initialize */ onPageShow: function() { var prefs = Services.prefs; - if (prefs.getPrefType(PREF_PLUGINS_UPDATEURL) == prefs.PREF_INVALID) { + if (prefs.getPrefType(PREF_PLUGINS_UPDATE_URL) == prefs.PREF_INVALID) { gUpdates.wiz.goTo("noupdatesfound"); return; } - - this._url = Services.urlFormatter.formatURLPref(PREF_PLUGINS_UPDATEURL); + + this._url = Services.urlFormatter.formatURLPref(PREF_PLUGINS_UPDATE_URL); var link = document.getElementById("pluginupdateslink"); link.setAttribute("href", this._url); @@ -775,7 +751,7 @@ var gPluginsPage = { gUpdates.setButtons(null, null, "okButton", true); gUpdates.wiz.getButton("finish").focus(); }, - + /** * Finish button clicked. */ @@ -907,7 +883,7 @@ var gIncompatibleCheckPage = { */ var gManualUpdatePage = { onPageShow: function() { - var manualURL = Services.urlFormatter.formatURLPref(PREF_APP_UPDATE_MANUAL_URL); + var manualURL = Services.urlFormatter.formatURLPref(PREF_APP_UPDATE_URL_MANUAL); var manualUpdateLinkLabel = document.getElementById("manualUpdateLinkLabel"); manualUpdateLinkLabel.value = manualURL; manualUpdateLinkLabel.setAttribute("url", manualURL); @@ -1710,7 +1686,7 @@ var gErrorsPage = { var errorReason = document.getElementById("errorReason"); errorReason.value = statusText; - var manualURL = Services.urlFormatter.formatURLPref(PREF_APP_UPDATE_MANUAL_URL); + var manualURL = Services.urlFormatter.formatURLPref(PREF_APP_UPDATE_URL_MANUAL); var errorLinkLabel = document.getElementById("errorLinkLabel"); errorLinkLabel.value = manualURL; errorLinkLabel.setAttribute("url", manualURL); @@ -1749,7 +1725,7 @@ var gErrorExtraPage = { } else document.getElementById("genericBackgroundErrorLabel").hidden = false; - var manualURL = Services.urlFormatter.formatURLPref(PREF_APP_UPDATE_MANUAL_URL); + var manualURL = Services.urlFormatter.formatURLPref(PREF_APP_UPDATE_URL_MANUAL); var errorLinkLabel = document.getElementById("errorExtraLinkLabel"); errorLinkLabel.value = manualURL; errorLinkLabel.setAttribute("url", manualURL); @@ -1772,7 +1748,7 @@ var gErrorPatchingPage = { onWizardNext: function() { switch (gUpdates.update.selectedPatch.state) { case STATE_PENDING: - case STATE_PENDING_SVC: + case STATE_PENDING_SVC: gUpdates.wiz.goTo("finished"); break; case STATE_DOWNLOADING: diff --git a/toolkit/mozapps/update/moz.build b/toolkit/mozapps/update/moz.build index 94de7d42aa..83316c84d8 100644 --- a/toolkit/mozapps/update/moz.build +++ b/toolkit/mozapps/update/moz.build @@ -31,16 +31,13 @@ if CONFIG['MOZ_UPDATER']: ] EXTRA_COMPONENTS += [ - 'nsUpdateService.manifest', - ] - - EXTRA_PP_COMPONENTS += [ 'nsUpdateService.js', + 'nsUpdateService.manifest', 'nsUpdateServiceStub.js', ] EXTRA_JS_MODULES += [ - 'UpdaterHealthProvider.jsm' + 'UpdateTelemetry.jsm', ] JAR_MANIFESTS += ['jar.mn'] diff --git a/toolkit/mozapps/update/nsIUpdateService.idl b/toolkit/mozapps/update/nsIUpdateService.idl index 4e2e32cb33..537897017b 100644 --- a/toolkit/mozapps/update/nsIUpdateService.idl +++ b/toolkit/mozapps/update/nsIUpdateService.idl @@ -476,7 +476,7 @@ interface nsIUpdateProcessor : nsISupports * An interface describing a global application service that maintains a list * of updates previously performed as well as the current active update. */ -[scriptable, uuid(c5df56de-919d-406b-aaf9-106dfa9b685b)] +[scriptable, uuid(f8371237-10a6-46a5-b23f-f6f7684e9d71)] interface nsIUpdateManager : nsISupports { /** @@ -505,7 +505,7 @@ interface nsIUpdateManager : nsISupports /** * Refresh the update status based on the information in update.status. */ - void refreshUpdateStatus(in nsIUpdate update); + void refreshUpdateStatus(); }; /** diff --git a/toolkit/mozapps/update/nsUpdateService.js b/toolkit/mozapps/update/nsUpdateService.js index e30afc09b8..417fcdcc49 100644 --- a/toolkit/mozapps/update/nsUpdateService.js +++ b/toolkit/mozapps/update/nsUpdateService.js @@ -1,25 +1,18 @@ -#filter substitution +/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ +const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/FileUtils.jsm"); -Components.utils.import("resource://gre/modules/AddonManager.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); -Components.utils.import("resource://gre/modules/ctypes.jsm"); -#ifdef MOZ_SERVICES_HEALTHREPORT -Components.utils.import("resource://gre/modules/UpdaterHealthProvider.jsm"); -#endif - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; -const Cu = Components.utils; +Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); +Cu.import("resource://gre/modules/FileUtils.jsm", this); +Cu.import("resource://gre/modules/AddonManager.jsm", this); +Cu.import("resource://gre/modules/Services.jsm", this); +Cu.import("resource://gre/modules/ctypes.jsm", this); +Cu.import("resource://gre/modules/UpdateTelemetry.jsm", this); +Cu.import("resource://gre/modules/AppConstants.jsm", this); const UPDATESERVICE_CID = Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}"); const UPDATESERVICE_CONTRACTID = "@mozilla.org/updates/update-service;1"; @@ -29,6 +22,7 @@ const PREF_APP_UPDATE_AUTO = "app.update.auto"; const PREF_APP_UPDATE_BACKGROUND_INTERVAL = "app.update.download.backgroundInterval"; const PREF_APP_UPDATE_BACKGROUNDERRORS = "app.update.backgroundErrors"; const PREF_APP_UPDATE_BACKGROUNDMAXERRORS = "app.update.backgroundMaxErrors"; +const PREF_APP_UPDATE_CANCELATIONS = "app.update.cancelations"; const PREF_APP_UPDATE_CERTS_BRANCH = "app.update.certs."; const PREF_APP_UPDATE_CERT_CHECKATTRS = "app.update.cert.checkAttributes"; const PREF_APP_UPDATE_CERT_ERRORS = "app.update.cert.errors"; @@ -36,11 +30,9 @@ const PREF_APP_UPDATE_CERT_MAXERRORS = "app.update.cert.maxErrors"; const PREF_APP_UPDATE_CERT_REQUIREBUILTIN = "app.update.cert.requireBuiltIn"; const PREF_APP_UPDATE_CUSTOM = "app.update.custom"; const PREF_APP_UPDATE_ENABLED = "app.update.enabled"; -const PREF_APP_UPDATE_METRO_ENABLED = "app.update.metro.enabled"; const PREF_APP_UPDATE_IDLETIME = "app.update.idletime"; const PREF_APP_UPDATE_INCOMPATIBLE_MODE = "app.update.incompatible.mode"; const PREF_APP_UPDATE_INTERVAL = "app.update.interval"; -const PREF_APP_UPDATE_LASTUPDATETIME = "app.update.lastUpdateTime.background-update-timer"; const PREF_APP_UPDATE_LOG = "app.update.log"; const PREF_APP_UPDATE_MODE = "app.update.mode"; const PREF_APP_UPDATE_NEVER_BRANCH = "app.update.never."; @@ -50,6 +42,7 @@ const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime"; const PREF_APP_UPDATE_SHOW_INSTALLED_UI = "app.update.showInstalledUI"; const PREF_APP_UPDATE_SILENT = "app.update.silent"; const PREF_APP_UPDATE_STAGING_ENABLED = "app.update.staging.enabled"; +const PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED = "app.update.notifiedUnsupported"; const PREF_APP_UPDATE_URL = "app.update.url"; const PREF_APP_UPDATE_URL_DETAILS = "app.update.url.details"; const PREF_APP_UPDATE_URL_OVERRIDE = "app.update.url.override"; @@ -67,33 +60,19 @@ const URI_BRAND_PROPERTIES = "chrome://branding/locale/brand.properties"; const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.properties"; const URI_UPDATE_NS = "http://www.mozilla.org/2005/app-update"; -const CATEGORY_UPDATE_TIMER = "update-timer"; - const KEY_GRED = "GreD"; const KEY_UPDROOT = "UpdRootD"; const KEY_EXECUTABLE = "XREExeF"; +// Gonk only +const KEY_UPDATE_ARCHIVE_DIR = "UpdArchD"; -#ifdef MOZ_WIDGET_GONK -#define USE_UPDATE_ARCHIVE_DIR -#endif - -#ifdef USE_UPDATE_ARCHIVE_DIR -const KEY_UPDATE_ARCHIVE_DIR = "UpdArchD" -#endif - +const DIR_UPDATED = "updated"; +const DIR_UPDATED_APP = "Updated.app"; const DIR_UPDATES = "updates"; -#ifdef XP_MACOSX -const UPDATED_DIR = "Updated.app"; -#else -const UPDATED_DIR = "updated"; -#endif + const FILE_UPDATE_STATUS = "update.status"; const FILE_UPDATE_VERSION = "update.version"; -#ifdef MOZ_WIDGET_ANDROID -const FILE_UPDATE_ARCHIVE = "update.apk"; -#else const FILE_UPDATE_ARCHIVE = "update.mar"; -#endif const FILE_UPDATE_LINK = "update.link"; const FILE_UPDATE_LOG = "update.log"; const FILE_UPDATES_DB = "updates.xml"; @@ -113,33 +92,80 @@ const STATE_SUCCEEDED = "succeeded"; const STATE_DOWNLOAD_FAILED = "download-failed"; const STATE_FAILED = "failed"; -// From updater/errors.h: -const WRITE_ERROR = 7; -// const UNEXPECTED_ERROR = 8; // Replaced with errors 38-42 -const ELEVATION_CANCELED = 9; +// The values below used by this code are from common/errors.h +const WRITE_ERROR = 7; +const ELEVATION_CANCELED = 9; +const SERVICE_UPDATER_COULD_NOT_BE_STARTED = 24; +const SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS = 25; +const SERVICE_UPDATER_SIGN_ERROR = 26; +const SERVICE_UPDATER_COMPARE_ERROR = 27; +const SERVICE_UPDATER_IDENTITY_ERROR = 28; +const SERVICE_STILL_APPLYING_ON_SUCCESS = 29; +const SERVICE_STILL_APPLYING_ON_FAILURE = 30; +const SERVICE_UPDATER_NOT_FIXED_DRIVE = 31; +const SERVICE_COULD_NOT_LOCK_UPDATER = 32; +const SERVICE_INSTALLDIR_ERROR = 33; +const WRITE_ERROR_ACCESS_DENIED = 35; +const WRITE_ERROR_CALLBACK_APP = 37; +const FILESYSTEM_MOUNT_READWRITE_ERROR = 43; +const SERVICE_COULD_NOT_COPY_UPDATER = 49; +const SERVICE_STILL_APPLYING_TERMINATED = 50; +const SERVICE_STILL_APPLYING_NO_EXIT_CODE = 51; +const WRITE_ERROR_FILE_COPY = 61; +const WRITE_ERROR_DELETE_FILE = 62; +const WRITE_ERROR_OPEN_PATCH_FILE = 63; +const WRITE_ERROR_PATCH_FILE = 64; +const WRITE_ERROR_APPLY_DIR_PATH = 65; +const WRITE_ERROR_CALLBACK_PATH = 66; +const WRITE_ERROR_FILE_ACCESS_DENIED = 67; +const WRITE_ERROR_DIR_ACCESS_DENIED = 68; +const WRITE_ERROR_DELETE_BACKUP = 69; +const WRITE_ERROR_EXTRACT = 70; -const WRITE_ERROR_ACCESS_DENIED = 35; -// const WRITE_ERROR_SHARING_VIOLATION = 36; // Replaced with errors 46-48 -const WRITE_ERROR_CALLBACK_APP = 37; -const INVALID_UPDATER_STATUS_CODE = 38; -const UNEXPECTED_BZIP_ERROR = 39; -const UNEXPECTED_MAR_ERROR = 40; -const UNEXPECTED_BSPATCH_ERROR = 41; -const UNEXPECTED_FILE_OPERATION_ERROR = 42; -const FILESYSTEM_MOUNT_READWRITE_ERROR = 43; -const FOTA_GENERAL_ERROR = 44; -const FOTA_UNKNOWN_ERROR = 45; -const WRITE_ERROR_SHARING_VIOLATION_SIGNALED = 46; -const WRITE_ERROR_SHARING_VIOLATION_NOPROCESSFORPID = 47; -const WRITE_ERROR_SHARING_VIOLATION_NOPID = 48; -const FOTA_FILE_OPERATION_ERROR = 49; -const FOTA_RECOVERY_ERROR = 50; +// Array of write errors to simplify checks for write errors +const WRITE_ERRORS = [WRITE_ERROR, + WRITE_ERROR_ACCESS_DENIED, + WRITE_ERROR_CALLBACK_APP, + WRITE_ERROR_FILE_COPY, + WRITE_ERROR_DELETE_FILE, + WRITE_ERROR_OPEN_PATCH_FILE, + WRITE_ERROR_PATCH_FILE, + WRITE_ERROR_APPLY_DIR_PATH, + WRITE_ERROR_CALLBACK_PATH, + WRITE_ERROR_FILE_ACCESS_DENIED, + WRITE_ERROR_DIR_ACCESS_DENIED, + WRITE_ERROR_DELETE_BACKUP, + WRITE_ERROR_EXTRACT]; +// Array of write errors to simplify checks for service errors +const SERVICE_ERRORS = [SERVICE_UPDATER_COULD_NOT_BE_STARTED, + SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS, + SERVICE_UPDATER_SIGN_ERROR, + SERVICE_UPDATER_COMPARE_ERROR, + SERVICE_UPDATER_IDENTITY_ERROR, + SERVICE_STILL_APPLYING_ON_SUCCESS, + SERVICE_STILL_APPLYING_ON_FAILURE, + SERVICE_UPDATER_NOT_FIXED_DRIVE, + SERVICE_COULD_NOT_LOCK_UPDATER, + SERVICE_INSTALLDIR_ERROR, + SERVICE_COULD_NOT_COPY_UPDATER]; + +// Error codes 80 through 99 are reserved for nsUpdateService.js and are not +// defined in common/errors.h +const FOTA_GENERAL_ERROR = 80; +const FOTA_UNKNOWN_ERROR = 81; +const FOTA_FILE_OPERATION_ERROR = 82; +const FOTA_RECOVERY_ERROR = 83; +// Staging failed and changed the state to pending +const STAGE_FAIL_FALLBACK = 97; +const INVALID_UPDATER_STATE_CODE = 98; +const INVALID_UPDATER_STATUS_CODE = 99; + +// Custom update error codes const CERT_ATTR_CHECK_FAILED_NO_UPDATE = 100; const CERT_ATTR_CHECK_FAILED_HAS_UPDATE = 101; const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110; const NETWORK_ERROR_OFFLINE = 111; -const FILE_ERROR_TOO_BIG = 112; // Error codes should be < 1000. Errors above 1000 represent http status codes const HTTP_ERROR_OFFSET = 1000; @@ -161,100 +187,19 @@ const DEFAULT_SOCKET_MAX_ERRORS = 10; // The number of milliseconds to wait before retrying a connection error. const DEFAULT_UPDATE_RETRY_TIMEOUT = 2000; -// A background download is in progress (no notification) -const PING_BGUC_IS_DOWNLOADING = 0; -// An update is staged (no notification) -const PING_BGUC_IS_STAGED = 1; -// Invalid url for app.update.url default preference (no notification) -const PING_BGUC_INVALID_DEFAULT_URL = 2; -// Invalid url for app.update.url user preference (no notification) -const PING_BGUC_INVALID_CUSTOM_URL = 3; -// Invalid url for app.update.url.override user preference (no notification) -const PING_BGUC_INVALID_OVERRIDE_URL = 4; -// Unable to check for updates per gCanCheckForUpdates and hasUpdateMutex() -// (no notification) -const PING_BGUC_UNABLE_TO_CHECK = 5; -// Already has an active update in progress (no notification) -const PING_BGUC_HAS_ACTIVEUPDATE = 6; -// Background checks disabled by preference (no notification) -const PING_BGUC_PREF_DISABLED = 7; -// Background checks disabled for the current session (no notification) -const PING_BGUC_DISABLED_FOR_SESSION = 8; -// Background checks disabled in Metro (no notification) -const PING_BGUC_METRO_DISABLED = 9; -// Unable to perform a background check while offline (no notification) -const PING_BGUC_OFFLINE = 10; -// No update found certificate check failed and threshold reached -// (possible mitm attack notification) -const PING_BGUC_CERT_ATTR_NO_UPDATE_NOTIFY = 11; -// No update found certificate check failed and threshold not reached -// (no notification) -const PING_BGUC_CERT_ATTR_NO_UPDATE_SILENT = 12; -// Update found certificate check failed and threshold reached -// (possible mitm attack notification) -const PING_BGUC_CERT_ATTR_WITH_UPDATE_NOTIFY = 13; -// Update found certificate check failed and threshold not reached -// (no notification) -const PING_BGUC_CERT_ATTR_WITH_UPDATE_SILENT = 14; -// General update check failure and threshold reached -// (check failure notification) -const PING_BGUC_GENERAL_ERROR_NOTIFY = 15; -// General update check failure and threshold not reached -// (no notification) -const PING_BGUC_GENERAL_ERROR_SILENT = 16; -// No update found (no notification) -const PING_BGUC_NO_UPDATE_FOUND = 17; -// No compatible update found though there were updates (no notification) -const PING_BGUC_NO_COMPAT_UPDATE_FOUND = 18; -// Update found for a previous version (no notification) -const PING_BGUC_UPDATE_PREVIOUS_VERSION = 19; -// Update found for a version with the never preference set (no notification) -const PING_BGUC_UPDATE_NEVER_PREF = 20; -// Update found without a type attribute (no notification) -const PING_BGUC_UPDATE_INVALID_TYPE = 21; -// The system is no longer supported (system unsupported notification) -const PING_BGUC_UNSUPPORTED = 22; -// Unable to apply updates (manual install to update notification) -const PING_BGUC_UNABLE_TO_APPLY = 23; -// Showing prompt due to the update.xml specifying showPrompt -// (update notification) -const PING_BGUC_SHOWPROMPT_SNIPPET = 24; -// Showing prompt due to preference (update notification) -const PING_BGUC_SHOWPROMPT_PREF = 25; -// Incompatible add-on check disabled by preference (background download) -const PING_BGUC_ADDON_PREF_DISABLED = 26; -// Incompatible add-on not checked not performed due to same update version and -// app version (background download) -const PING_BGUC_ADDON_SAME_APP_VER = 27; -// No incompatible add-ons found during incompatible check (background download) -const PING_BGUC_CHECK_NO_INCOMPAT = 28; -// Incompatible add-ons found and all of them have updates (background download) -const PING_BGUC_ADDON_UPDATES_FOR_INCOMPAT = 29; -// Incompatible add-ons found (update notification) -const PING_BGUC_ADDON_HAVE_INCOMPAT = 30; - -// Health report field names -const UpdaterHealthReportFields = { - CHECK_START: "updateCheckStart", - CHECK_SUCCESS: "updateCheckSuccess", - CHECK_FAILED: "updateCheckFailed", - COMPLETE_START: "completeUpdateStart", - PARTIAL_START: "partialUpdateStart", - COMPLETE_SUCCESS: "completeUpdateSuccess", - PARTIAL_SUCCESS: "partialUpdateSuccess", - FAILED: "updateFailed" -}; - var gLocale = null; var gUpdateMutexHandle = null; -#ifdef MOZ_WIDGET_GONK +// Gonk only var gSDCardMountLock = null; +// Gonk only XPCOMUtils.defineLazyGetter(this, "gExtStorage", function aus_gExtStorage() { - return Services.env.get("EXTERNAL_STORAGE"); + if (AppConstants.platform != "gonk") { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + } + return Services.env.get("EXTERNAL_STORAGE"); }); -#endif XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel", "resource://gre/modules/UpdateChannel.jsm"); @@ -282,154 +227,140 @@ XPCOMUtils.defineLazyGetter(this, "gABI", function aus_gABI() { catch (e) { LOG("gABI - XPCOM ABI unknown: updates are not possible."); } -#ifdef XP_MACOSX - // Mac universal build should report a different ABI than either macppc - // or mactel. - let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"]. - getService(Ci.nsIMacUtils); - if (macutils.isUniversalBinary) - abi += "-u-" + macutils.architecturesInBinary; -#ifdef MOZ_SHARK - // Disambiguate optimised and shark nightlies - abi += "-shark" -#endif -#endif + if (AppConstants.platform == "macosx") { + // Mac universal build should report a different ABI than either macppc + // or mactel. + let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"]. + getService(Ci.nsIMacUtils); + + if (macutils.isUniversalBinary) { + abi += "-u-" + macutils.architecturesInBinary; + } + } return abi; }); -#ifdef MOZ_WIDGET_GONK -XPCOMUtils.defineLazyGetter(this, "gProductModel", function aus_gProductModel() { - Cu.import("resource://gre/modules/systemlibs.js"); - return libcutils.property_get("ro.product.model"); -}); -XPCOMUtils.defineLazyGetter(this, "gProductDevice", function aus_gProductDevice() { - Cu.import("resource://gre/modules/systemlibs.js"); - return libcutils.property_get("ro.product.device"); -}); -#endif - XPCOMUtils.defineLazyGetter(this, "gOSVersion", function aus_gOSVersion() { let osVersion; - let sysInfo = Cc["@mozilla.org/system-info;1"]. - getService(Ci.nsIPropertyBag2); try { - osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version"); + osVersion = Services.sysinfo.getProperty("name") + " " + + Services.sysinfo.getProperty("version"); } catch (e) { LOG("gOSVersion - OS Version unknown: updates are not possible."); } if (osVersion) { -#ifdef XP_WIN - const BYTE = ctypes.uint8_t; - const WORD = ctypes.uint16_t; - const DWORD = ctypes.uint32_t; - const WCHAR = ctypes.char16_t; - const BOOL = ctypes.int; + if (AppConstants.platform == "win") { + const BYTE = ctypes.uint8_t; + const WORD = ctypes.uint16_t; + const DWORD = ctypes.uint32_t; + const WCHAR = ctypes.char16_t; + const BOOL = ctypes.int; - // This structure is described at: - // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx - const SZCSDVERSIONLENGTH = 128; - const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW', - [ - {dwOSVersionInfoSize: DWORD}, - {dwMajorVersion: DWORD}, - {dwMinorVersion: DWORD}, - {dwBuildNumber: DWORD}, - {dwPlatformId: DWORD}, - {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)}, - {wServicePackMajor: WORD}, - {wServicePackMinor: WORD}, - {wSuiteMask: WORD}, - {wProductType: BYTE}, - {wReserved: BYTE} - ]); + // This structure is described at: + // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx + const SZCSDVERSIONLENGTH = 128; + const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW', + [ + {dwOSVersionInfoSize: DWORD}, + {dwMajorVersion: DWORD}, + {dwMinorVersion: DWORD}, + {dwBuildNumber: DWORD}, + {dwPlatformId: DWORD}, + {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)}, + {wServicePackMajor: WORD}, + {wServicePackMinor: WORD}, + {wSuiteMask: WORD}, + {wProductType: BYTE}, + {wReserved: BYTE} + ]); - // This structure is described at: - // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx - const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO', - [ - {wProcessorArchitecture: WORD}, - {wReserved: WORD}, - {dwPageSize: DWORD}, - {lpMinimumApplicationAddress: ctypes.voidptr_t}, - {lpMaximumApplicationAddress: ctypes.voidptr_t}, - {dwActiveProcessorMask: DWORD.ptr}, - {dwNumberOfProcessors: DWORD}, - {dwProcessorType: DWORD}, - {dwAllocationGranularity: DWORD}, - {wProcessorLevel: WORD}, - {wProcessorRevision: WORD} - ]); + // This structure is described at: + // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx + const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO', + [ + {wProcessorArchitecture: WORD}, + {wReserved: WORD}, + {dwPageSize: DWORD}, + {lpMinimumApplicationAddress: ctypes.voidptr_t}, + {lpMaximumApplicationAddress: ctypes.voidptr_t}, + {dwActiveProcessorMask: DWORD.ptr}, + {dwNumberOfProcessors: DWORD}, + {dwProcessorType: DWORD}, + {dwAllocationGranularity: DWORD}, + {wProcessorLevel: WORD}, + {wProcessorRevision: WORD} + ]); - let kernel32 = false; - try { - kernel32 = ctypes.open("Kernel32"); - } catch (e) { - LOG("gOSVersion - Unable to open kernel32! " + e); - osVersion += ".unknown (unknown)"; - } - - if(kernel32) { + let kernel32 = false; try { - // Get Service pack info - try { - let GetVersionEx = kernel32.declare("GetVersionExW", - ctypes.default_abi, - BOOL, - OSVERSIONINFOEXW.ptr); - let winVer = OSVERSIONINFOEXW(); - winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size; + kernel32 = ctypes.open("Kernel32"); + } catch (e) { + LOG("gOSVersion - Unable to open kernel32! " + e); + osVersion += ".unknown (unknown)"; + } - if(0 !== GetVersionEx(winVer.address())) { - osVersion += "." + winVer.wServicePackMajor - + "." + winVer.wServicePackMinor; - } else { - LOG("gOSVersion - Unknown failure in GetVersionEX (returned 0)"); + if(kernel32) { + try { + // Get Service pack info + try { + let GetVersionEx = kernel32.declare("GetVersionExW", + ctypes.default_abi, + BOOL, + OSVERSIONINFOEXW.ptr); + let winVer = OSVERSIONINFOEXW(); + winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size; + + if(0 !== GetVersionEx(winVer.address())) { + osVersion += "." + winVer.wServicePackMajor + + "." + winVer.wServicePackMinor; + } else { + LOG("gOSVersion - Unknown failure in GetVersionEX (returned 0)"); + osVersion += ".unknown"; + } + } catch (e) { + LOG("gOSVersion - error getting service pack information. Exception: " + e); osVersion += ".unknown"; } - } catch (e) { - LOG("gOSVersion - error getting service pack information. Exception: " + e); - osVersion += ".unknown"; - } - // Get processor architecture - let arch = "unknown"; - try { - let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo", - ctypes.default_abi, - ctypes.void_t, - SYSTEM_INFO.ptr); - let sysInfo = SYSTEM_INFO(); - // Default to unknown - sysInfo.wProcessorArchitecture = 0xffff; + // Get processor architecture + let arch = "unknown"; + try { + let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo", + ctypes.default_abi, + ctypes.void_t, + SYSTEM_INFO.ptr); + let winSystemInfo = SYSTEM_INFO(); + // Default to unknown + winSystemInfo.wProcessorArchitecture = 0xffff; - GetNativeSystemInfo(sysInfo.address()); - switch(sysInfo.wProcessorArchitecture) { - case 9: - arch = "x64"; - break; - case 6: - arch = "IA64"; - break; - case 0: - arch = "x86"; - break; + GetNativeSystemInfo(winSystemInfo.address()); + switch(winSystemInfo.wProcessorArchitecture) { + case 9: + arch = "x64"; + break; + case 6: + arch = "IA64"; + break; + case 0: + arch = "x86"; + break; + } + } catch (e) { + LOG("gOSVersion - error getting processor architecture. Exception: " + e); + } finally { + osVersion += " (" + arch + ")"; } - } catch (e) { - LOG("gOSVersion - error getting processor architecture. Exception: " + e); } finally { - osVersion += " (" + arch + ")"; + kernel32.close(); } - } finally { - kernel32.close(); } } -#endif try { - osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")"; + osVersion += " (" + Services.sysinfo.getProperty("secondaryLibrary") + ")"; } catch (e) { // Not all platforms have a secondary widget library, so an error is nothing to worry about. @@ -456,16 +387,14 @@ function testWriteAccess(updateTestFile, createDirectory) { updateTestFile.remove(false); } -#ifdef XP_WIN - /** - * Closes a Win32 handle + * Windows only function that closes a Win32 handle. * * @param handle The handle to close */ function closeHandle(handle) { - var lib = ctypes.open("kernel32.dll"); - var CloseHandle = lib.declare("CloseHandle", + let lib = ctypes.open("kernel32.dll"); + let CloseHandle = lib.declare("CloseHandle", ctypes.winapi_abi, ctypes.int32_t, /* success */ ctypes.void_t.ptr); /* handle */ @@ -474,7 +403,7 @@ function closeHandle(handle) { } /** - * Creates a mutex. + * Windows only function that creates a mutex. * * @param aName * The name for the mutex. @@ -482,51 +411,54 @@ function closeHandle(handle) { * If false the function will close the handle and return null. * @return The Win32 handle to the mutex. */ -function createMutex(aName, aAllowExisting) { - if (aAllowExisting === undefined) { - aAllowExisting = true; +function createMutex(aName, aAllowExisting = true) { + if (AppConstants.platform != "win") { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; } const INITIAL_OWN = 1; const ERROR_ALREADY_EXISTS = 0xB7; - var lib = ctypes.open("kernel32.dll"); - var CreateMutexW = lib.declare("CreateMutexW", + let lib = ctypes.open("kernel32.dll"); + let CreateMutexW = lib.declare("CreateMutexW", ctypes.winapi_abi, ctypes.void_t.ptr, /* return handle */ ctypes.void_t.ptr, /* security attributes */ ctypes.int32_t, /* initial owner */ ctypes.char16_t.ptr); /* name */ - var handle = CreateMutexW(null, INITIAL_OWN, aName); - var alreadyExists = ctypes.winLastError == ERROR_ALREADY_EXISTS; + let handle = CreateMutexW(null, INITIAL_OWN, aName); + let alreadyExists = ctypes.winLastError == ERROR_ALREADY_EXISTS; if (handle && !handle.isNull() && !aAllowExisting && alreadyExists) { closeHandle(handle); handle = null; } lib.close(); - if (handle && handle.isNull()) + if (handle && handle.isNull()) { handle = null; + } return handle; } /** - * Determines a unique mutex name for the installation + * Windows only function that determines a unique mutex name for the + * installation. * * @param aGlobal true if the function should return a global mutex. A global * mutex is valid across different sessions * @return Global mutex path */ -function getPerInstallationMutexName(aGlobal) { - if (aGlobal === undefined) { - aGobal = true; +function getPerInstallationMutexName(aGlobal = true) { + if (AppConstants.platform != "win") { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; } + let hasher = Cc["@mozilla.org/security/hash;1"]. createInstance(Ci.nsICryptoHash); hasher.init(hasher.SHA1); - var exeFile = Services.dirsvc.get(KEY_EXECUTABLE, Ci.nsILocalFile); + let exeFile = Services.dirsvc.get(KEY_EXECUTABLE, Ci.nsILocalFile); let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]. createInstance(Ci.nsIScriptableUnicodeConverter); @@ -536,139 +468,125 @@ function getPerInstallationMutexName(aGlobal) { hasher.update(data, data.length); return (aGlobal ? "Global\\" : "") + "MozillaUpdateMutex-" + hasher.finish(true); } -#endif // XP_WIN /** * Whether or not the current instance has the update mutex. The update mutex * gives protection against 2 applications from the same installation updating: * 1) Running multiple profiles from the same installation path - * 2) Running a Metro and Desktop application at the same time from the same - * path - * 3) 2 applications running in 2 different user sessions from the same path + * 2) Two applications running in 2 different user sessions from the same path * * @return true if this instance holds the update mutex */ function hasUpdateMutex() { -#ifdef XP_WIN + if (AppConstants.platform != "win") { + return true; + } if (!gUpdateMutexHandle) { gUpdateMutexHandle = createMutex(getPerInstallationMutexName(true), false); } - return !!gUpdateMutexHandle; -#else - return true; -#endif // XP_WIN } function getCanApplyUpdates() { - function submitHasPermissionsTelemetryPing(val) { + let useService = false; + if (shouldUseService()) { + // No need to perform directory write checks, the maintenance service will + // be able to write to all directories. + LOG("getCanApplyUpdates - bypass the write checks because we'll use the service"); + useService = true; + } + + if (!useService) { try { - let h = Services.telemetry.getHistogramById("UPDATER_HAS_PERMISSIONS"); - h.add(+val); - } catch(e) { - // Don't allow any exception to be propagated. - Components.utils.reportError(e); - } - } + let updateTestFile = getUpdateFile([FILE_PERMS_TEST]); + LOG("getCanApplyUpdates - testing write access " + updateTestFile.path); + testWriteAccess(updateTestFile, false); + if (AppConstants.platform == "macosx") { + // Check that the application bundle can be written to. + let appDirTestFile = getAppBaseDir(); + appDirTestFile.append(FILE_PERMS_TEST); + LOG("getCanApplyUpdates - testing write access " + appDirTestFile.path); + if (appDirTestFile.exists()) { + appDirTestFile.remove(false) + } + appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + appDirTestFile.remove(false); + } else if (AppConstants.platform == "win") { + // Example windowsVersion: Windows XP == 5.1 + let windowsVersion = Services.sysinfo.getProperty("version"); + LOG("gCanApplyUpdates - windowsVersion = " + windowsVersion); - try { - var updateTestFile = getUpdateFile([FILE_PERMS_TEST]); - LOG("getCanApplyUpdates - testing write access " + updateTestFile.path); - testWriteAccess(updateTestFile, false); -#ifdef XP_MACOSX - // Check that the application bundle can be written to. - var appDirTestFile = getAppBaseDir(); - appDirTestFile.append(FILE_PERMS_TEST); - LOG("getCanApplyUpdates - testing write access " + appDirTestFile.path); - if (appDirTestFile.exists()) { - appDirTestFile.remove(false) - } - appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); - appDirTestFile.remove(false); -#elifdef XP_WIN - var sysInfo = Cc["@mozilla.org/system-info;1"]. - getService(Ci.nsIPropertyBag2); + /** + * For Vista, updates can be performed to a location requiring admin + * privileges by requesting elevation via the UAC prompt when launching + * updater.exe if the appDir is under the Program Files directory + * (e.g. C:\Program Files\) and UAC is turned on and we can elevate + * (e.g. user has a split token). + * + * Note: this does note attempt to handle the case where UAC is turned on + * and the installation directory is in a restricted location that + * requires admin privileges to update other than Program Files. + */ + let userCanElevate = false; - // Example windowsVersion: Windows XP == 5.1 - var windowsVersion = sysInfo.getProperty("version"); - LOG("getCanApplyUpdates - windowsVersion = " + windowsVersion); + if (parseFloat(windowsVersion) >= 6) { + try { + // KEY_UPDROOT will fail and throw an exception if + // appDir is not under the Program Files, so we rely on that + let dir = Services.dirsvc.get(KEY_UPDROOT, Ci.nsIFile); + // appDir is under Program Files, so check if the user can elevate + userCanElevate = Services.appinfo.QueryInterface(Ci.nsIWinAppHelper). + userCanElevate; + LOG("gCanApplyUpdates - on Vista, userCanElevate: " + userCanElevate); + } + catch (ex) { + // When the installation directory is not under Program Files, + // fall through to checking if write access to the + // installation directory is available. + LOG("gCanApplyUpdates - on Vista, appDir is not under Program Files"); + } + } - /** -# For Vista, updates can be performed to a location requiring admin -# privileges by requesting elevation via the UAC prompt when launching -# updater.exe if the appDir is under the Program Files directory -# (e.g. C:\Program Files\) and UAC is turned on and we can elevate -# (e.g. user has a split token). -# -# Note: this does note attempt to handle the case where UAC is turned on -# and the installation directory is in a restricted location that -# requires admin privileges to update other than Program Files. - */ - var userCanElevate = false; - - if (parseFloat(windowsVersion) >= 6) { - try { - var fileLocator = Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties); - // KEY_UPDROOT will fail and throw an exception if - // appDir is not under the Program Files, so we rely on that - var dir = fileLocator.get(KEY_UPDROOT, Ci.nsIFile); - // appDir is under Program Files, so check if the user can elevate - userCanElevate = Services.appinfo.QueryInterface(Ci.nsIWinAppHelper). - userCanElevate; - LOG("getCanApplyUpdates - on Vista, userCanElevate: " + userCanElevate); + /** + * On Windows, we no longer store the update under the app dir. + * + * If we are on Windows (including Vista, if we can't elevate) we need to + * to check that we can create and remove files from the actual app + * directory (like C:\Program Files\Mozilla Firefox). If we can't + * (because this user is not an adminstrator, for example) canUpdate() + * should return false. + * + * For Vista, we perform this check to enable updating the application + * when the user has write access to the installation directory under the + * following scenarios: + * 1) the installation directory is not under Program Files + * (e.g. C:\Program Files) + * 2) UAC is turned off + * 3) UAC is turned on and the user is not an admin + * (e.g. the user does not have a split token) + * 4) UAC is turned on and the user is already elevated, so they can't be + * elevated again + */ + if (!userCanElevate) { + // if we're unable to create the test file this will throw an exception. + let appDirTestFile = getAppBaseDir(); + appDirTestFile.append(FILE_PERMS_TEST); + LOG("gCanApplyUpdates - testing write access " + appDirTestFile.path); + if (appDirTestFile.exists()) + appDirTestFile.remove(false) + appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + appDirTestFile.remove(false); + } } - catch (ex) { - // When the installation directory is not under Program Files, - // fall through to checking if write access to the - // installation directory is available. - LOG("getCanApplyUpdates - on Vista, appDir is not under Program Files"); - } - } - - /** -# On Windows, we no longer store the update under the app dir. -# -# If we are on Windows (including Vista, if we can't elevate) we need to -# to check that we can create and remove files from the actual app -# directory (like C:\Program Files\Mozilla Firefox). If we can't -# (because this user is not an adminstrator, for example) canUpdate() -# should return false. -# -# For Vista, we perform this check to enable updating the application -# when the user has write access to the installation directory under the -# following scenarios: -# 1) the installation directory is not under Program Files -# (e.g. C:\Program Files) -# 2) UAC is turned off -# 3) UAC is turned on and the user is not an admin -# (e.g. the user does not have a split token) -# 4) UAC is turned on and the user is already elevated, so they can't be -# elevated again - */ - if (!userCanElevate) { - // if we're unable to create the test file this will throw an exception. - var appDirTestFile = getAppBaseDir(); - appDirTestFile.append(FILE_PERMS_TEST); - LOG("getCanApplyUpdates - testing write access " + appDirTestFile.path); - if (appDirTestFile.exists()) - appDirTestFile.remove(false) - appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); - appDirTestFile.remove(false); - } -#endif //XP_WIN - } - catch (e) { + } catch (e) { LOG("getCanApplyUpdates - unable to apply updates. Exception: " + e); // No write privileges to install directory - submitHasPermissionsTelemetryPing(false); return false; - } + } // if (!useService) LOG("getCanApplyUpdates - able to apply updates"); - submitHasPermissionsTelemetryPing(true); return true; -} +}; /** * Whether or not the application can stage an update. @@ -683,14 +601,17 @@ function getCanStageUpdates() { return false; } -#ifdef MOZ_WIDGET_GONK // For Gonk, the updater will remount the /system partition to move staged - // files into place. - if (getPref("getBoolPref", PREF_APP_UPDATE_SERVICE_ENABLED, false)) { - LOG("getCanStageUpdates - able to stage updates because this is gonk"); - return true; + // files into place and it uses the app.update.service.enabled preference for + // this purpose. + if (AppConstants.platform == "win" || AppConstants.platform == "gonk") { + if (getPref("getBoolPref", PREF_APP_UPDATE_SERVICE_ENABLED, false)) { + // No need to perform directory write checks, the maintenance service will + // be able to write to all directories. + LOG("getCanStageUpdates - able to stage updates because we'll use the service"); + return true; + } } -#endif if (!hasUpdateMutex()) { LOG("getCanStageUpdates - unable to apply updates because another " + @@ -712,20 +633,19 @@ function getCanStageUpdates() { LOG("canStageUpdatesSession - testing write access " + updateTestFile.path); testWriteAccess(updateTestFile, true); -#ifndef XP_MACOSX - // On all platforms except Mac, we need to test the parent directory as - // well, as we need to be able to move files in that directory during the - // replacing step. - updateTestFile = getInstallDirRoot().parent; - updateTestFile.append(FILE_PERMS_TEST); - LOG("canStageUpdatesSession - testing write access " + - updateTestFile.path); - updateTestFile.createUnique(Ci.nsILocalFile.DIRECTORY_TYPE, - FileUtils.PERMS_DIRECTORY); - updateTestFile.remove(false); -#endif - } - catch (e) { + if (AppConstants.platform != "macosx") { + // On all platforms except Mac, we need to test the parent directory as + // well, as we need to be able to move files in that directory during the + // replacing step. + updateTestFile = getInstallDirRoot().parent; + updateTestFile.append(FILE_PERMS_TEST); + LOG("canStageUpdatesSession - testing write access " + + updateTestFile.path); + updateTestFile.createUnique(Ci.nsILocalFile.DIRECTORY_TYPE, + FileUtils.PERMS_DIRECTORY); + updateTestFile.remove(false); + } + } catch (e) { LOG("canStageUpdatesSession - unable to stage updates. Exception: " + e); // No write privileges @@ -739,23 +659,6 @@ function getCanStageUpdates() { return canStageUpdatesSession; } -XPCOMUtils.defineLazyGetter(this, "gMetroUpdatesEnabled", function aus_gMetroUpdatesEnabled() { -#ifdef XP_WIN -#ifdef MOZ_METRO - if (Services.metro && Services.metro.immersive) { - let metroUpdate = getPref("getBoolPref", PREF_APP_UPDATE_METRO_ENABLED, true); - if (!metroUpdate) { - LOG("gMetroUpdatesEnabled - unable to automatically check for metro " + - "updates, disabled by pref"); - return false; - } - } -#endif -#endif - - return true; -}); - XPCOMUtils.defineLazyGetter(this, "gCanCheckForUpdates", function aus_gCanCheckForUpdates() { // If the administrator has disabled app update and locked the preference so // users can't check for updates. This preference check is ok in this lazy @@ -767,10 +670,6 @@ XPCOMUtils.defineLazyGetter(this, "gCanCheckForUpdates", function aus_gCanCheckF return false; } - if (!gMetroUpdatesEnabled) { - return false; - } - // If we don't know the binary platform we're updating, we can't update. if (!gABI) { LOG("gCanCheckForUpdates - unable to check for updates, unknown ABI"); @@ -801,16 +700,16 @@ function LOG(string) { } /** -# Gets a preference value, handling the case where there is no default. -# @param func -# The name of the preference function to call, on nsIPrefBranch -# @param preference -# The name of the preference -# @param defaultValue -# The default value to return in the event the preference has -# no setting -# @return The value of the preference, or undefined if there was no -# user or default value. + * Gets a preference value, handling the case where there is no default. + * @param func + * The name of the preference function to call, on nsIPrefBranch + * @param preference + * The name of the preference + * @param defaultValue + * The default value to return in the event the preference has + * no setting + * @return The value of the preference, or undefined if there was no + * user or default value. */ function getPref(func, preference, defaultValue) { try { @@ -836,24 +735,24 @@ function binaryToHex(input) { } /** -# Gets the specified directory at the specified hierarchy under the -# update root directory and creates it if it doesn't exist. -# @param pathArray -# An array of path components to locate beneath the directory -# specified by |key| -# @return nsIFile object for the location specified. + * Gets the specified directory at the specified hierarchy under the + * update root directory and creates it if it doesn't exist. + * @param pathArray + * An array of path components to locate beneath the directory + * specified by |key| + * @return nsIFile object for the location specified. */ function getUpdateDirCreate(pathArray) { return FileUtils.getDir(KEY_UPDROOT, pathArray, true); } /** -# Gets the specified directory at the specified hierarchy under the -# update root directory and without creating it if it doesn't exist. -# @param pathArray -# An array of path components to locate beneath the directory -# specified by |key| -# @return nsIFile object for the location specified. + * Gets the specified directory at the specified hierarchy under the + * update root directory and without creating it if it doesn't exist. + * @param pathArray + * An array of path components to locate beneath the directory + * specified by |key| + * @return nsIFile object for the location specified. */ function getUpdateDirNoCreate(pathArray) { return FileUtils.getDir(KEY_UPDROOT, pathArray, false); @@ -876,11 +775,11 @@ function getAppBaseDir() { * @return nsIFile object for the directory */ function getInstallDirRoot() { - var dir = getAppBaseDir(); -#ifdef XP_MACOSX - // On Mac, we store the Updated.app directory inside the bundle directory. - dir = dir.parent.parent; -#endif + let dir = getAppBaseDir(); + if (AppConstants.platform == "macosx") { + // On Mac, we store the Updated.app directory inside the bundle directory. + dir = dir.parent.parent; + } return dir; } @@ -895,7 +794,7 @@ function getInstallDirRoot() { * the way are. */ function getUpdateFile(pathArray) { - var file = getUpdateDirCreate(pathArray.slice(0, -1)); + let file = getUpdateDirCreate(pathArray.slice(0, -1)); file.append(pathArray[pathArray.length - 1]); return file; } @@ -911,7 +810,7 @@ function getUpdateFile(pathArray) { * @return A human readable status text string */ function getStatusTextFromCode(code, defaultCode) { - var reason; + let reason; try { reason = gUpdateBundle.GetStringFromName("check_error-" + code); LOG("getStatusTextFromCode - transfer error: " + reason + ", code: " + @@ -926,37 +825,6 @@ function getStatusTextFromCode(code, defaultCode) { return reason; } -/** - * Record count in the health report. - * @param field - * The field name to record - * @param status - * Status code for errors, 0 otherwise - */ -function recordInHealthReport(field, status) { -#ifdef MOZ_SERVICES_HEALTHREPORT - try { - LOG("recordInHealthReport - " + field + " - " + status); - - let reporter = Cc["@mozilla.org/datareporting/service;1"] - .getService().wrappedJSObject.healthReporter; - - if (reporter) { - reporter.onInit().then(function recordUpdateInHealthReport() { - try { - reporter.getProvider("org.mozilla.update").recordUpdate(field, status); - } catch (ex) { - Cu.reportError(ex); - } - }); - } - // If getting the heath reporter service fails, don't fail updating. - } catch (ex) { - LOG("recordInHealthReport - could not initialize health reporter"); - } -#endif -} - /** * Get the Active Updates directory * @return The active updates directory, as a nsIFile object @@ -974,15 +842,15 @@ function getUpdatesDir() { * nsIFile object. */ function getUpdatesDirInApplyToDir() { - var dir = getAppBaseDir(); -#ifdef XP_MACOSX - dir = dir.parent.parent; // the bundle directory -#endif - dir.append(UPDATED_DIR); -#ifdef XP_MACOSX - dir.append("Contents"); - dir.append("MacOS"); -#endif + let dir = getAppBaseDir(); + if (AppConstants.platform == "macosx") { + dir = dir.parent.parent; // the bundle directory + dir.append(DIR_UPDATED_APP); + dir.append("Contents"); + dir.append("MacOS"); + } else { + dir.append(DIR_UPDATED); + } dir.append(DIR_UPDATES); if (!dir.exists()) { dir.create(Ci.nsILocalFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); @@ -998,9 +866,9 @@ function getUpdatesDirInApplyToDir() { * @return The status value of the update. */ function readStatusFile(dir) { - var statusFile = dir.clone(); + let statusFile = dir.clone(); statusFile.append(FILE_UPDATE_STATUS); - var status = readStringFromFile(statusFile) || STATE_NONE; + let status = readStringFromFile(statusFile) || STATE_NONE; LOG("readStatusFile - status: " + status + ", path: " + statusFile.path); return status; } @@ -1016,16 +884,36 @@ function readStatusFile(dir) { * The state value to write. */ function writeStatusFile(dir, state) { - var statusFile = dir.clone(); + let statusFile = dir.clone(); statusFile.append(FILE_UPDATE_STATUS); writeStringToFile(statusFile, state); } -#ifdef MOZ_WIDGET_GONK /** - * Reads the link file specified in the update.link file in the - * specified directory and returns the nsIFile for the - * corresponding file. + * Writes the update's application version to a file in the patch directory. If + * the update doesn't provide application version information via the + * appVersion attribute the string "null" will be written to the file. + * This value is compared during startup (in nsUpdateDriver.cpp) to determine if + * the update should be applied. Note that this won't provide protection from + * downgrade of the application for the nightly user case where the application + * version doesn't change. + * @param dir + * The patch directory where the update.version file should be + * written. + * @param version + * The version value to write. Will be the string "null" when the + * update doesn't provide the appVersion attribute in the update xml. + */ +function writeVersionFile(dir, version) { + let versionFile = dir.clone(); + versionFile.append(FILE_UPDATE_VERSION); + writeStringToFile(versionFile, version); +} + +/** + * Gonk only function that reads the link file specified in the update.link file + * in the specified directory and returns the nsIFile for the corresponding + * file. * @param dir * The dir to look for an update.link file in * @return A nsIFile for the file path specified in the @@ -1033,9 +921,12 @@ function writeStatusFile(dir, state) { * doesn't exist. */ function getFileFromUpdateLink(dir) { - var linkFile = dir.clone(); + if (AppConstants.platform != "gonk") { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + } + let linkFile = dir.clone(); linkFile.append(FILE_UPDATE_LINK); - var link = readStringFromFile(linkFile); + let link = readStringFromFile(linkFile); LOG("getFileFromUpdateLink linkFile.path: " + linkFile.path + ", link: " + link); if (!link) { return null; @@ -1046,8 +937,8 @@ function getFileFromUpdateLink(dir) { } /** - * Creates a link file, which allows the actual patch to live in - * a directory different from the update directory. + * Gonk only function to create a link file. This allows the actual patch to + * live in a directory different from the update directory. * @param dir * The patch directory where the update.link file * should be written. @@ -1055,7 +946,10 @@ function getFileFromUpdateLink(dir) { * The fully qualified filename of the patchfile. */ function writeLinkFile(dir, patchFile) { - var linkFile = dir.clone(); + if (AppConstants.platform != "gonk") { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + } + let linkFile = dir.clone(); linkFile.append(FILE_UPDATE_LINK); writeStringToFile(linkFile, patchFile.path); if (patchFile.path.indexOf(gExtStorage) == 0) { @@ -1067,12 +961,15 @@ function writeLinkFile(dir, patchFile) { } /** - * Acquires a VolumeMountLock for the sdcard volume. + * Gonk only function to acquire a VolumeMountLock for the sdcard volume. * * This prevents the SDCard from being shared with the PC while * we're downloading the update. */ function acquireSDCardMountLock() { + if (AppConstants.platform != "gonk") { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + } let volsvc = Cc["@mozilla.org/telephony/volume-service;1"]. getService(Ci.nsIVolumeService); if (volsvc) { @@ -1081,56 +978,76 @@ function acquireSDCardMountLock() { } /** - * Determines if the state corresponds to an interrupted update. - * This could either be because the download was interrupted, or - * because staging the update was interrupted. + * Gonk only function that determines if the state corresponds to an + * interrupted update. This could either be because the download was + * interrupted, or because staging the update was interrupted. * * @return true if the state corresponds to an interrupted * update. */ function isInterruptedUpdate(status) { + if (AppConstants.platform != "gonk") { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + } return (status == STATE_DOWNLOADING) || (status == STATE_PENDING) || (status == STATE_APPLYING); } -#endif // MOZ_WIDGET_GONK /** * Releases any SDCard mount lock that we might have. * * This once again allows the SDCard to be shared with the PC. - * - * This function was placed outside the #ifdef so that we didn't - * need to put #ifdefs around the callers. */ function releaseSDCardMountLock() { -#ifdef MOZ_WIDGET_GONK + if (AppConstants.platform != "gonk") { + throw Cr.NS_ERROR_UNEXPECTED; + } if (gSDCardMountLock) { gSDCardMountLock.unlock(); gSDCardMountLock = null; } -#endif } /** -# Writes the update's application version to a file in the patch directory. If -# the update doesn't provide application version information via the -# appVersion attribute the string "null" will be written to the file. -# This value is compared during startup (in nsUpdateDriver.cpp) to determine if -# the update should be applied. Note that this won't provide protection from -# downgrade of the application for the nightly user case where the application -# version doesn't change. -# @param dir -# The patch directory where the update.version file should be -# written. -# @param version -# The version value to write. Will be the string "null" when the -# update doesn't provide the appVersion attribute in the update xml. + * Determines if the service should be used to attempt an update + * or not. For now this is only when PREF_APP_UPDATE_SERVICE_ENABLED + * is true and we have Firefox. + * + * @return true if the service should be used for updates. */ -function writeVersionFile(dir, version) { - var versionFile = dir.clone(); - versionFile.append(FILE_UPDATE_VERSION); - writeStringToFile(versionFile, version); +function shouldUseService() { + if (AppConstants.MOZ_MAINTENANCE_SERVICE) { + return getPref("getBoolPref", + PREF_APP_UPDATE_SERVICE_ENABLED, false); + } + return false; +} + +/** + * Determines if the service is is installed and enabled or not. + * + * @return true if the service should be used for updates, + * is installed and enabled. + */ +function isServiceInstalled() { + if (AppConstants.MOZ_MAINTENANCE_SERVICE && AppConstants.platform == "win") { + let installed = 0; + try { + let wrk = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); + wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE, + "SOFTWARE\\Mozilla\\MaintenanceService", + wrk.ACCESS_READ | wrk.WOW64_64); + installed = wrk.readIntValue("Installed"); + wrk.close(); + } catch(e) { + } + installed = installed == 1; // convert to bool + LOG("isServiceInstalled = " + installed); + return installed; + } + return false; } /** @@ -1151,9 +1068,7 @@ function cleanUpMozUpdaterDirs() { } try { - var tmpDir = Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties). - get("TmpD", Ci.nsIFile); + var tmpDir = Services.dirsvc.get("TmpD", Ci.nsIFile); // We used to store MozUpdater-i directories in the temp directory. // We need to remove these directories if we detect that they still exist. @@ -1234,14 +1149,14 @@ function cleanUpUpdatesDir(aBackgroundUpdate) { let e = updateDir.directoryEntries; while (e.hasMoreElements()) { let f = e.getNext().QueryInterface(Ci.nsIFile); -#ifdef MOZ_WIDGET_GONK - if (f.leafName == FILE_UPDATE_LINK) { - let linkedFile = getFileFromUpdateLink(updateDir); - if (linkedFile && linkedFile.exists()) { - linkedFile.remove(false); + if (AppConstants.platform == "gonk") { + if (f.leafName == FILE_UPDATE_LINK) { + let linkedFile = getFileFromUpdateLink(updateDir); + if (linkedFile && linkedFile.exists()) { + linkedFile.remove(false); + } } } -#endif // Now, recursively remove this file. The recursive removal is needed for // Mac OSX because this directory will contain a copy of updater.app, @@ -1253,7 +1168,9 @@ function cleanUpUpdatesDir(aBackgroundUpdate) { } } } - releaseSDCardMountLock(); + if (AppConstants.platform == "gonk") { + releaseSDCardMountLock(); + } } /** @@ -1405,12 +1322,8 @@ function handleUpdateFailure(update, errorCode) { return true; } - if (update.errorCode == WRITE_ERROR || - update.errorCode == WRITE_ERROR_ACCESS_DENIED || - update.errorCode == WRITE_ERROR_SHARING_VIOLATION_SIGNALED || - update.errorCode == WRITE_ERROR_SHARING_VIOLATION_NOPROCESSFORPID || - update.errorCode == WRITE_ERROR_SHARING_VIOLATION_NOPID || - update.errorCode == WRITE_ERROR_CALLBACK_APP || + // Replace with Array.prototype.includes when it has stabilized. + if (WRITE_ERRORS.indexOf(update.errorCode) != -1 || update.errorCode == FILESYSTEM_MOUNT_READWRITE_ERROR) { Cc["@mozilla.org/updates/update-prompt;1"]. createInstance(Ci.nsIUpdatePrompt). @@ -1421,9 +1334,45 @@ function handleUpdateFailure(update, errorCode) { if (update.errorCode == ELEVATION_CANCELED) { writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING); + let cancelations = getPref("getIntPref", PREF_APP_UPDATE_CANCELATIONS, 0); + cancelations++; + Services.prefs.setIntPref(PREF_APP_UPDATE_CANCELATIONS, cancelations); return true; } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CANCELATIONS)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_CANCELATIONS); + } + + // Replace with Array.prototype.includes when it has stabilized. + if (SERVICE_ERRORS.indexOf(update.errorCode) != -1) { + var failCount = getPref("getIntPref", + PREF_APP_UPDATE_SERVICE_ERRORS, 0); + var maxFail = getPref("getIntPref", + PREF_APP_UPDATE_SERVICE_MAX_ERRORS, + DEFAULT_SERVICE_MAX_ERRORS); + + // As a safety, when the service reaches maximum failures, it will + // disable itself and fallback to using the normal update mechanism + // without the service. + if (failCount >= maxFail) { + Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, false); + Services.prefs.clearUserPref(PREF_APP_UPDATE_SERVICE_ERRORS); + } else { + failCount++; + Services.prefs.setIntPref(PREF_APP_UPDATE_SERVICE_ERRORS, + failCount); + } + + writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING); + return true; + } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SERVICE_ERRORS)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_SERVICE_ERRORS); + } + return false; } @@ -1458,6 +1407,71 @@ function handleFallbackToCompleteUpdate(update, postStaging) { update.setProperty("patchingFailed", oldType); } +function pingStateAndStatusCodes(aUpdate, aStartup, aStatus) { + let patchType = AUSTLMY.PATCH_UNKNOWN; + if (aUpdate && aUpdate.selectedPatch && aUpdate.selectedPatch.type) { + if (aUpdate.selectedPatch.type == "complete") { + patchType = AUSTLMY.PATCH_COMPLETE; + } else if (aUpdate.selectedPatch.type == "partial") { + patchType = AUSTLMY.PATCH_PARTIAL; + } + } + + let suffix = patchType + "_" + (aStartup ? AUSTLMY.STARTUP : AUSTLMY.STAGE); + let stateCode = 0; + let parts = aStatus.split(":"); + if (parts.length > 0) { + switch (parts[0]) { + case STATE_NONE: + stateCode = 2; + break; + case STATE_DOWNLOADING: + stateCode = 3; + break; + case STATE_PENDING: + stateCode = 4; + parts[0] = STATE_FAILED; + parts.push(STAGE_FAIL_FALLBACK); + break; + case STATE_PENDING_SVC: + stateCode = 5; + break; + case STATE_APPLYING: + stateCode = 6; + break; + case STATE_APPLIED: + stateCode = 7; + break; + case STATE_APPLIED_OS: + stateCode = 8; + break; + case STATE_APPLIED_SVC: + stateCode = 9; + break; + case STATE_SUCCEEDED: + stateCode = 10; + break; + case STATE_DOWNLOAD_FAILED: + stateCode = 11; + break; + case STATE_FAILED: + stateCode = 12; + break; + default: + stateCode = 1; + } + + if (parts.length > 1) { + let statusErrorCode = INVALID_UPDATER_STATE_CODE; + if (parts[0] == STATE_FAILED) { + statusErrorCode = parseInt(parts[1]) || INVALID_UPDATER_STATUS_CODE; + } + AUSTLMY.pingStatusErrorCode(suffix, statusErrorCode); + } + } + AUSTLMY.pingStateCode(suffix, stateCode); +} + /** * Update Patch * @param patch @@ -1932,12 +1946,12 @@ function UpdateService() { LOG("Creating UpdateService"); Services.obs.addObserver(this, "xpcom-shutdown", false); Services.prefs.addObserver(PREF_APP_UPDATE_LOG, this, false); -#ifdef MOZ_WIDGET_GONK - // PowerManagerService::SyncProfile (which is called for Reboot, PowerOff - // and Restart) sends the profile-change-net-teardown event. We can then - // pause the download in a similar manner to xpcom-shutdown. - Services.obs.addObserver(this, "profile-change-net-teardown", false); -#endif + if (AppConstants.platform == "gonk") { + // PowerManagerService::SyncProfile (which is called for Reboot, PowerOff + // and Restart) sends the profile-change-net-teardown event. We can then + // pause the download in a similar manner to xpcom-shutdown. + Services.obs.addObserver(this, "profile-change-net-teardown", false); + } } UpdateService.prototype = { @@ -1996,21 +2010,17 @@ UpdateService.prototype = { gLogEnabled = getPref("getBoolPref", PREF_APP_UPDATE_LOG, false); } break; -#ifdef MOZ_WIDGET_GONK case "profile-change-net-teardown": // fall thru -#endif case "xpcom-shutdown": Services.obs.removeObserver(this, topic); Services.prefs.removeObserver(PREF_APP_UPDATE_LOG, this); -#ifdef XP_WIN - // If we hold the update mutex, let it go! - // The OS would clean this up sometime after shutdown, - // but that would have no guarantee on timing. - if (gUpdateMutexHandle) { + if (AppConstants.platform == "win" && gUpdateMutexHandle) { + // If we hold the update mutex, let it go! + // The OS would clean this up sometime after shutdown, + // but that would have no guarantee on timing. closeHandle(gUpdateMutexHandle); } -#endif if (this._retryTimer) { this._retryTimer.cancel(); } @@ -2038,17 +2048,7 @@ UpdateService.prototype = { * notify the user of install success. */ _postUpdateProcessing: function AUS__postUpdateProcessing() { - // canCheckForUpdates will return false when metro-only updates are disabled - // from within metro. In that case we still want _postUpdateProcessing to - // run. gMetroUpdatesEnabled returns true on non Windows 8 platforms. - // We want _postUpdateProcessing to run so that it will update the history - // XML. Without updating the history XML, the about flyout will continue to - // have the "Restart to Apply Update" button (history xml indicates update - // is applied). - // TODO: I think this whole if-block should be removed since updates can - // always be applied via the about dialog, we should be running post update - // in those cases. - if (!this.canCheckForUpdates && gMetroUpdatesEnabled) { + if (!this.canCheckForUpdates) { LOG("UpdateService:_postUpdateProcessing - unable to check for " + "updates... returning early"); return; @@ -2063,36 +2063,35 @@ UpdateService.prototype = { return; } + var um = Cc["@mozilla.org/updates/update-manager;1"]. + getService(Ci.nsIUpdateManager); + var update = um.activeUpdate; var status = readStatusFile(getUpdatesDir()); - // STATE_NONE status means that the update.status file is present but a - // background download error occurred. + pingStateAndStatusCodes(update, true, status); + // STATE_NONE status typically means that the update.status file is present + // but a background download error occurred. if (status == STATE_NONE) { LOG("UpdateService:_postUpdateProcessing - no status, no update"); cleanupActiveUpdate(); return; } - var um = Cc["@mozilla.org/updates/update-manager;1"]. - getService(Ci.nsIUpdateManager); - -#ifdef MOZ_WIDGET_GONK - // This code is called very early in the boot process, before we've even - // had a chance to setup the UI so we can give feedback to the user. - // - // Since the download may be occuring over a link which has associated - // cost, we want to require user-consent before resuming the download. - // Also, applying an already downloaded update now is undesireable, - // since the phone will look dead while the update is being applied. - // Applying the update can take several minutes. Instead we wait until - // the UI is initialized so it is possible to give feedback to and get - // consent to update from the user. - if (isInterruptedUpdate(status)) { - LOG("UpdateService:_postUpdateProcessing - interrupted update detected - wait for user consent"); - return; + if (AppConstants.platform == "gonk") { + // This code is called very early in the boot process, before we've even + // had a chance to setup the UI so we can give feedback to the user. + // + // Since the download may be occuring over a link which has associated + // cost, we want to require user-consent before resuming the download. + // Also, applying an already downloaded update now is undesireable, + // since the phone will look dead while the update is being applied. + // Applying the update can take several minutes. Instead we wait until + // the UI is initialized so it is possible to give feedback to and get + // consent to update from the user. + if (isInterruptedUpdate(status)) { + LOG("UpdateService:_postUpdateProcessing - interrupted update detected - wait for user consent"); + return; + } } -#endif - - var update = um.activeUpdate; if (status == STATE_DOWNLOADING) { LOG("UpdateService:_postUpdateProcessing - patch found in downloading " + @@ -2133,34 +2132,33 @@ UpdateService.prototype = { return; } -#ifdef MOZ_WIDGET_GONK - // The update is only applied but not selected to be installed - if (status == STATE_APPLIED && update && update.isOSUpdate) { - LOG("UpdateService:_postUpdateProcessing - update staged as applied found"); - return; - } + if (AppConstants.platform == "gonk") { + // The update is only applied but not selected to be installed + if (status == STATE_APPLIED && update && update.isOSUpdate) { + LOG("UpdateService:_postUpdateProcessing - update staged as applied found"); + return; + } - if (status == STATE_APPLIED_OS && update && update.isOSUpdate) { - // In gonk, we need to check for OS update status after startup, since - // the recovery partition won't write to update.status for us - var recoveryService = Cc["@mozilla.org/recovery-service;1"]. - getService(Ci.nsIRecoveryService); - - var fotaStatus = recoveryService.getFotaUpdateStatus(); - switch (fotaStatus) { - case Ci.nsIRecoveryService.FOTA_UPDATE_SUCCESS: - status = STATE_SUCCEEDED; - break; - case Ci.nsIRecoveryService.FOTA_UPDATE_FAIL: - status = STATE_FAILED + ": " + FOTA_GENERAL_ERROR; - break; - case Ci.nsIRecoveryService.FOTA_UPDATE_UNKNOWN: - default: - status = STATE_FAILED + ": " + FOTA_UNKNOWN_ERROR; - break; + if (status == STATE_APPLIED_OS && update && update.isOSUpdate) { + // In gonk, we need to check for OS update status after startup, since + // the recovery partition won't write to update.status for us + let recoveryService = Cc["@mozilla.org/recovery-service;1"]. + getService(Ci.nsIRecoveryService); + let fotaStatus = recoveryService.getFotaUpdateStatus(); + switch (fotaStatus) { + case Ci.nsIRecoveryService.FOTA_UPDATE_SUCCESS: + status = STATE_SUCCEEDED; + break; + case Ci.nsIRecoveryService.FOTA_UPDATE_FAIL: + status = STATE_FAILED + ": " + FOTA_GENERAL_ERROR; + break; + case Ci.nsIRecoveryService.FOTA_UPDATE_UNKNOWN: + default: + status = STATE_FAILED + ": " + FOTA_UNKNOWN_ERROR; + break; + } } } -#endif if (!update) { if (status != STATE_SUCCEEDED) { @@ -2176,7 +2174,6 @@ UpdateService.prototype = { createInstance(Ci.nsIUpdatePrompt); update.state = status; - this._sendStatusCodeTelemetryPing(status); if (status == STATE_SUCCEEDED) { update.statusText = gUpdateBundle.GetStringFromName("installSuccess"); @@ -2217,129 +2214,6 @@ UpdateService.prototype = { cleanUpMozUpdaterDirs(); }, - /** - * Submit a telemetry ping with the boolean value of a pref for a histogram - * - * @param pref - * The preference to report - * @param histogram - * The histogram ID to report to - */ - _sendBoolPrefTelemetryPing: function AUS__boolTelemetryPing(pref, histogram) { - try { - // The getPref is already wrapped in a try/catch but we never - // want telemetry pings breaking app update so we just put it - // inside the try to be safe. - let val = getPref("getBoolPref", pref, false); - Services.telemetry.getHistogramById(histogram).add(+val); - } catch(e) { - // Don't allow any exception to be propagated. - Cu.reportError(e); - } - }, - - /** - * Submit a telemetry ping with the int value of a pref for a histogram - * - * @param pref - * The preference to report - * @param histogram - * The histogram ID to report to - */ - _sendIntPrefTelemetryPing: function AUS__intTelemetryPing(pref, histogram) { - try { - // The getPref is already wrapped in a try/catch but we never - // want telemetry pings breaking app update so we just put it - // inside the try to be safe. - let val = getPref("getIntPref", pref, 0); - Services.telemetry.getHistogramById(histogram).add(val); - } catch(e) { - // Don't allow any exception to be propagated. - Cu.reportError(e); - } - }, - - - /** - * Submit the results of applying the update via telemetry. - * - * @param status - * The status of the update as read from the update.status file - */ - _sendStatusCodeTelemetryPing: function AUS__statusTelemetryPing(status) { - try { - let parts = status.split(":"); - if ((parts.length == 1 && status != STATE_SUCCEEDED) || - (parts.length > 1 && parts[0] != STATE_FAILED)) { - // Should also report STATE_DOWNLOAD_FAILED - return; - } - let result = 0; // 0 means success - if (parts.length > 1) { - result = parseInt(parts[1]) || INVALID_UPDATER_STATUS_CODE; - } - Services.telemetry.getHistogramById("UPDATER_STATUS_CODES").add(result); - } catch(e) { - // Don't allow any exception to be propagated. - Cu.reportError(e); - } - }, - - /** - * Submit the interval in days since the last notification for this background - * update check. - */ - _sendLastNotifyIntervalPing: function AUS__notifyIntervalPing() { - if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_LASTUPDATETIME)) { - let idSuffix = this._isNotify ? "NOTIFY" : "EXTERNAL"; - let lastUpdateTimeSeconds = getPref("getIntPref", - PREF_APP_UPDATE_LASTUPDATETIME, 0); - if (lastUpdateTimeSeconds) { - let currentTimeSeconds = Math.round(Date.now() / 1000); - if (lastUpdateTimeSeconds > currentTimeSeconds) { - try { - Services.telemetry. - getHistogramById("UPDATER_INVALID_LASTUPDATETIME_" + idSuffix). - add(1); - } catch(e) { - Cu.reportError(e); - } - } - else { - let intervalDays = (currentTimeSeconds - lastUpdateTimeSeconds) / - (60 * 60 * 24); - try { - Services.telemetry. - getHistogramById("UPDATER_INVALID_LASTUPDATETIME_" + idSuffix). - add(0); - Services.telemetry. - getHistogramById("UPDATER_LAST_NOTIFY_INTERVAL_DAYS_" + idSuffix). - add(intervalDays); - } catch(e) { - Cu.reportError(e); - } - } - } - } - }, - - /** - * Submit the result for the background update check. - * - * @param code - * An integer value as defined by the PING_BGUC_* constants. - */ - _backgroundUpdateCheckCodePing: function AUS__backgroundUpdateCheckCodePing(code) { - try { - let idSuffix = this._isNotify ? "NOTIFY" : "EXTERNAL"; - Services.telemetry. - getHistogramById("UPDATER_BACKGROUND_CHECK_CODE_" + idSuffix).add(code); - } - catch (e) { - Cu.reportError(e); - } - }, - /** * Register an observer when the network comes online, so we can short-circuit * the app.update.interval when there isn't connectivity @@ -2388,7 +2262,9 @@ UpdateService.prototype = { if (update.errorCode == NETWORK_ERROR_OFFLINE) { // Register an online observer to try again this._registerOnlineObserver(); - this._backgroundUpdateCheckCodePing(PING_BGUC_OFFLINE); + if (this._pingSuffix) { + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_OFFLINE); + } return; } @@ -2398,8 +2274,7 @@ UpdateService.prototype = { errCount++; Services.prefs.setIntPref(PREF_APP_UPDATE_CERT_ERRORS, errCount); maxErrors = getPref("getIntPref", PREF_APP_UPDATE_CERT_MAXERRORS, 5); - } - else { + } else { update.errorCode = BACKGROUNDCHECK_MULTIPLE_FAILURES; errCount = getPref("getIntPref", PREF_APP_UPDATE_BACKGROUNDERRORS, 0); errCount++; @@ -2408,7 +2283,7 @@ UpdateService.prototype = { 10); } - var pingCode; + let checkCode; if (errCount >= maxErrors) { var prompter = Cc["@mozilla.org/updates/update-prompt;1"]. createInstance(Ci.nsIUpdatePrompt); @@ -2416,28 +2291,29 @@ UpdateService.prototype = { switch (update.errorCode) { case CERT_ATTR_CHECK_FAILED_NO_UPDATE: - pingCode = PING_BGUC_CERT_ATTR_NO_UPDATE_NOTIFY; + checkCode = AUSTLMY.CHK_CERT_ATTR_NO_UPDATE_PROMPT; break; case CERT_ATTR_CHECK_FAILED_HAS_UPDATE: - pingCode = PING_BGUC_CERT_ATTR_WITH_UPDATE_NOTIFY; + checkCode = AUSTLMY.CHK_CERT_ATTR_WITH_UPDATE_PROMPT; break; default: - pingCode = PING_BGUC_GENERAL_ERROR_NOTIFY; + checkCode = AUSTLMY.CHK_GENERAL_ERROR_PROMPT; + AUSTLMY.pingCheckExError(this._pingSuffix, update.errorCode); } - } - else { + } else { switch (update.errorCode) { case CERT_ATTR_CHECK_FAILED_NO_UPDATE: - pingCode = PING_BGUC_CERT_ATTR_NO_UPDATE_SILENT; + checkCode = AUSTLMY.CHK_CERT_ATTR_NO_UPDATE_SILENT; break; case CERT_ATTR_CHECK_FAILED_HAS_UPDATE: - pingCode = PING_BGUC_CERT_ATTR_WITH_UPDATE_SILENT; + checkCode = AUSTLMY.CHK_CERT_ATTR_WITH_UPDATE_SILENT; break; default: - pingCode = PING_BGUC_GENERAL_ERROR_SILENT; + checkCode = AUSTLMY.CHK_GENERAL_ERROR_SILENT; + AUSTLMY.pingCheckExError(this._pingSuffix, update.errorCode); } } - this._backgroundUpdateCheckCodePing(pingCode); + AUSTLMY.pingCheckCode(this._pingSuffix, checkCode); }, /** @@ -2471,15 +2347,6 @@ UpdateService.prototype = { * The timer that fired */ notify: function AUS_notify(timer) { - // The telemetry below is specific to background notification. - this._sendBoolPrefTelemetryPing(PREF_APP_UPDATE_ENABLED, - "UPDATER_UPDATES_ENABLED"); - this._sendBoolPrefTelemetryPing(PREF_APP_UPDATE_METRO_ENABLED, - "UPDATER_UPDATES_METRO_ENABLED"); - this._sendBoolPrefTelemetryPing(PREF_APP_UPDATE_AUTO, - "UPDATER_UPDATES_AUTOMATIC"); - this._sendBoolPrefTelemetryPing(PREF_APP_UPDATE_STAGING_ENABLED, - "UPDATER_STAGE_ENABLED"); this._checkForBackgroundUpdates(true); }, @@ -2490,6 +2357,11 @@ UpdateService.prototype = { this._checkForBackgroundUpdates(false); }, + // The suffix used for background update check telemetry histogram ID's. + get _pingSuffix() { + return this._isNotify ? AUSTLMY.NOTIFY : AUSTLMY.EXTERNAL; + }, + /** * Checks for updates in the background. * @param isNotify @@ -2498,55 +2370,125 @@ UpdateService.prototype = { */ _checkForBackgroundUpdates: function AUS__checkForBackgroundUpdates(isNotify) { this._isNotify = isNotify; - // From this point on, the telemetry reported differentiates between a call - // to notify and a call to checkForBackgroundUpdates so they are reported - // separately. - this._sendLastNotifyIntervalPing(); + + // Histogram IDs: + // UPDATE_CANNOT_APPLY_EXTERNAL + // UPDATE_CANNOT_APPLY_NOTIFY + AUSTLMY.pingGeneric("UPDATE_CANNOT_APPLY_" + this._pingSuffix, + gCanApplyUpdates); + // Histogram IDs: + // UPDATE_CANNOT_STAGE_EXTERNAL + // UPDATE_CANNOT_STAGE_NOTIFY + AUSTLMY.pingGeneric("UPDATE_CANNOT_STAGE_" + this._pingSuffix, + getCanStageUpdates(), true); + // Histogram IDs: + // UPDATE_INVALID_LASTUPDATETIME_EXTERNAL + // UPDATE_INVALID_LASTUPDATETIME_NOTIFY + // UPDATE_LAST_NOTIFY_INTERVAL_DAYS_EXTERNAL + // UPDATE_LAST_NOTIFY_INTERVAL_DAYS_NOTIFY + AUSTLMY.pingLastUpdateTime(this._pingSuffix); + // Histogram IDs: + // UPDATE_NOT_PREF_UPDATE_ENABLED_EXTERNAL + // UPDATE_NOT_PREF_UPDATE_ENABLED_NOTIFY + AUSTLMY.pingBoolPref("UPDATE_NOT_PREF_UPDATE_ENABLED_" + this._pingSuffix, + PREF_APP_UPDATE_ENABLED, true, true); + // Histogram IDs: + // UPDATE_NOT_PREF_UPDATE_AUTO_EXTERNAL + // UPDATE_NOT_PREF_UPDATE_AUTO_NOTIFY + AUSTLMY.pingBoolPref("UPDATE_NOT_PREF_UPDATE_AUTO_" + this._pingSuffix, + PREF_APP_UPDATE_AUTO, true, true); + // Histogram IDs: + // UPDATE_NOT_PREF_UPDATE_STAGING_ENABLED_EXTERNAL + // UPDATE_NOT_PREF_UPDATE_STAGING_ENABLED_NOTIFY + AUSTLMY.pingBoolPref("UPDATE_NOT_PREF_UPDATE_STAGING_ENABLED_" + + this._pingSuffix, + PREF_APP_UPDATE_STAGING_ENABLED, true, true); + if (AppConstants.platform == "win") { + // Histogram IDs: + // UPDATE_PREF_UPDATE_CANCELATIONS_EXTERNAL + // UPDATE_PREF_UPDATE_CANCELATIONS_NOTIFY + AUSTLMY.pingIntPref("UPDATE_PREF_UPDATE_CANCELATIONS_" + this._pingSuffix, + PREF_APP_UPDATE_CANCELATIONS, 0, 0); + } + if (AppConstants.MOZ_MAINTENANCE_SERVICE) { + // Histogram IDs: + // UPDATE_NOT_PREF_UPDATE_SERVICE_ENABLED_EXTERNAL + // UPDATE_NOT_PREF_UPDATE_SERVICE_ENABLED_NOTIFY + AUSTLMY.pingBoolPref("UPDATE_NOT_PREF_UPDATE_SERVICE_ENABLED_" + + this._pingSuffix, + PREF_APP_UPDATE_SERVICE_ENABLED, true); + // Histogram IDs: + // UPDATE_PREF_SERVICE_ERRORS_EXTERNAL + // UPDATE_PREF_SERVICE_ERRORS_NOTIFY + AUSTLMY.pingIntPref("UPDATE_PREF_SERVICE_ERRORS_" + this._pingSuffix, + PREF_APP_UPDATE_SERVICE_ERRORS, 0, 0); + if (AppConstants.platform == "win") { + // Histogram IDs: + // UPDATE_SERVICE_INSTALLED_EXTERNAL + // UPDATE_SERVICE_INSTALLED_NOTIFY + // UPDATE_SERVICE_MANUALLY_UNINSTALLED_EXTERNAL + // UPDATE_SERVICE_MANUALLY_UNINSTALLED_NOTIFY + AUSTLMY.pingServiceInstallStatus(this._pingSuffix, isServiceInstalled()); + } + } + + let prefType = Services.prefs.getPrefType(PREF_APP_UPDATE_URL_OVERRIDE); + let overridePrefHasValue = prefType != Ci.nsIPrefBranch.PREF_INVALID; + // Histogram IDs: + // UPDATE_HAS_PREF_URL_OVERRIDE_EXTERNAL + // UPDATE_HAS_PREF_URL_OVERRIDE_NOTIFY + AUSTLMY.pingGeneric("UPDATE_HAS_PREF_URL_OVERRIDE_" + this._pingSuffix, + overridePrefHasValue, false); // If a download is in progress or the patch has been staged do nothing. if (this.isDownloading) { - this._backgroundUpdateCheckCodePing(PING_BGUC_IS_DOWNLOADING); + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_IS_DOWNLOADING); return; } if (this._downloader && this._downloader.patchIsStaged) { - this._backgroundUpdateCheckCodePing(PING_BGUC_IS_STAGED); + let readState = readStatusFile(getUpdatesDir()); + if (readState == STATE_PENDING || readState == STATE_PENDING_SVC) { + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_IS_DOWNLOADED); + } else { + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_IS_STAGED); + } return; } - // The following checks will return early without notification in the call - // to checkForUpdates below. To simplify the background update check ping - // their values are checked here. + let validUpdateURL = true; try { - if (!this.backgroundChecker.getUpdateURL(false)) { - let prefs = Services.prefs; - if (!prefs.prefHasUserValue(PREF_APP_UPDATE_URL_OVERRIDE)) { - if (!prefs.prefHasUserValue(PREF_APP_UPDATE_URL)) { - this._backgroundUpdateCheckCodePing(PING_BGUC_INVALID_DEFAULT_URL); - } - else { - this._backgroundUpdateCheckCodePing(PING_BGUC_INVALID_CUSTOM_URL); - } - } - else { - this._backgroundUpdateCheckCodePing(PING_BGUC_INVALID_OVERRIDE_URL); - } - } - else if (!gMetroUpdatesEnabled) { - this._backgroundUpdateCheckCodePing(PING_BGUC_METRO_DISABLED); - } - else if (!getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true)) { - this._backgroundUpdateCheckCodePing(PING_BGUC_PREF_DISABLED); - } - else if (!(gCanCheckForUpdates && hasUpdateMutex())) { - this._backgroundUpdateCheckCodePing(PING_BGUC_UNABLE_TO_CHECK); - } - else if (!this.backgroundChecker._enabled) { - this._backgroundUpdateCheckCodePing(PING_BGUC_DISABLED_FOR_SESSION); - } + this.backgroundChecker.getUpdateURL(false); + } catch (e) { + validUpdateURL = false; } - catch (e) { - Cu.reportError(e); + // The following checks are done here so they can be differentiated from + // foreground checks. + if (!gOSVersion) { + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_NO_OS_VERSION); + } else if (!gABI) { + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_NO_OS_ABI); + } else if (!validUpdateURL) { + if (overridePrefHasValue) { + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_OVERRIDE)) { + AUSTLMY.pingCheckCode(this._pingSuffix, + AUSTLMY.CHK_INVALID_USER_OVERRIDE_URL); + } else { + AUSTLMY.pingCheckCode(this._pingSuffix, + AUSTLMY.CHK_INVALID_DEFAULT_OVERRIDE_URL); + } + } else { + AUSTLMY.pingCheckCode(this._pingSuffix, + AUSTLMY.CHK_INVALID_DEFAULT_URL); + } + } else if (!getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true)) { + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_PREF_DISABLED); + } else if (!hasUpdateMutex()) { + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_NO_MUTEX); + } else if (!gCanCheckForUpdates) { + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_UNABLE_TO_CHECK); + } else if (!this.backgroundChecker._enabled) { + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_DISABLED_FOR_SESSION); } this.backgroundChecker.checkForUpdates(this, false); @@ -2562,19 +2504,20 @@ UpdateService.prototype = { */ selectUpdate: function AUS_selectUpdate(updates) { if (updates.length == 0) { - this._backgroundUpdateCheckCodePing(PING_BGUC_NO_UPDATE_FOUND); + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_NO_UPDATE_FOUND); return null; } // The ping for unsupported is sent after the call to showPrompt. - if (updates.length == 1 && updates[0].unsupported) + if (updates.length == 1 && updates[0].unsupported) { return updates[0]; + } // Choose the newest of the available minor and major updates. var majorUpdate = null; var minorUpdate = null; var vc = Services.vc; - var lastPingCode = PING_BGUC_NO_COMPAT_UPDATE_FOUND; + let lastCheckCode = AUSTLMY.CHK_NO_COMPAT_UPDATE_FOUND; updates.forEach(function(aUpdate) { // Ignore updates for older versions of the applications and updates for @@ -2587,7 +2530,7 @@ UpdateService.prototype = { LOG("UpdateService:selectUpdate - skipping update because the " + "update's application version or build id is less than or the " + "same as the current application version or build id"); - lastPingCode = PING_BGUC_UPDATE_PREVIOUS_VERSION; + lastCheckCode = AUSTLMY.CHK_UPDATE_PREVIOUS_VERSION; return; } @@ -2599,7 +2542,7 @@ UpdateService.prototype = { getPref("getBoolPref", neverPrefName, false)) { LOG("UpdateService:selectUpdate - skipping update because the " + "preference " + neverPrefName + " is true"); - lastPingCode = PING_BGUC_UPDATE_NEVER_PREF; + lastCheckCode = AUSTLMY.CHK_UPDATE_NEVER_PREF; return; } @@ -2619,14 +2562,15 @@ UpdateService.prototype = { default: LOG("UpdateService:selectUpdate - skipping unknown update type: " + aUpdate.type); - lastPingCode = PING_BGUC_UPDATE_INVALID_TYPE; + lastCheckCode = AUSTLMY.CHK_UPDATE_INVALID_TYPE; break; } }); var update = minorUpdate || majorUpdate; - if (!update) - this._backgroundUpdateCheckCodePing(lastPingCode); + if (!update) { + AUSTLMY.pingCheckCode(this._pingSuffix, lastCheckCode); + } return update; }, @@ -2649,28 +2593,23 @@ UpdateService.prototype = { var um = Cc["@mozilla.org/updates/update-manager;1"]. getService(Ci.nsIUpdateManager); if (um.activeUpdate) { -#ifdef MOZ_WIDGET_GONK - // For gonk, the user isn't necessarily aware of the update, so we need - // to show the prompt to make sure. - this._showPrompt(um.activeUpdate); -#endif - this._backgroundUpdateCheckCodePing(PING_BGUC_HAS_ACTIVEUPDATE); + if (AppConstants.platform == "gonk") { + // For gonk, the user isn't necessarily aware of the update, so we need + // to show the prompt to make sure. + this._showPrompt(um.activeUpdate); + } + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_HAS_ACTIVEUPDATE); return; } var updateEnabled = getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true); if (!updateEnabled) { - this._backgroundUpdateCheckCodePing(PING_BGUC_PREF_DISABLED); + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_PREF_DISABLED); LOG("UpdateService:_selectAndInstallUpdate - not prompting because " + "update is disabled"); return; } - if (!gMetroUpdatesEnabled) { - this._backgroundUpdateCheckCodePing(PING_BGUC_METRO_DISABLED); - return; - } - var update = this.selectUpdate(updates, updates.length); if (!update) { return; @@ -2697,49 +2636,45 @@ UpdateService.prototype = { } /** -# From this point on there are two possible outcomes: -# 1. download and install the update automatically -# 2. notify the user about the availability of an update -# -# Notes: -# a) if the app.update.auto preference is false then automatic download and -# install is disabled and the user will be notified. -# b) if the update has a showPrompt attribute the user will be notified. -# c) Mode is determined by the value of the app.update.mode preference. -# -# If the update when it is first read has an appVersion attribute the -# following behavior implemented in bug 530872 will occur: -# Mode Incompatible Add-ons Outcome -# 0 N/A Auto Install -# 1 Yes Notify -# 1 No Auto Install -# -# If the update when it is first read does not have an appVersion attribute -# the following deprecated behavior will occur: -# Update Type Mode Incompatible Add-ons Outcome -# Major all N/A Notify -# Minor 0 N/A Auto Install -# Minor 1 Yes Notify -# Minor 1 No Auto Install + * From this point on there are two possible outcomes: + * 1. download and install the update automatically + * 2. notify the user about the availability of an update + * + * Notes: + * a) if the app.update.auto preference is false then automatic download and + * install is disabled and the user will be notified. + * b) if the update has a showPrompt attribute the user will be notified. + * c) Mode is determined by the value of the app.update.mode preference. + * + * If the update when it is first read has an appVersion attribute the + * following behavior implemented in bug 530872 will occur: + * Mode Incompatible Add-ons Outcome + * 0 N/A Auto Install + * 1 Yes Notify + * 1 No Auto Install + * + * If the update when it is first read does not have an appVersion attribute + * the following deprecated behavior will occur: + * Update Type Mode Incompatible Add-ons Outcome + * Major all N/A Notify + * Minor 0 N/A Auto Install + * Minor 1 Yes Notify + * Minor 1 No Auto Install */ if (update.showPrompt) { LOG("UpdateService:_selectAndInstallUpdate - prompting because the " + "update snippet specified showPrompt"); + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_SHOWPROMPT_SNIPPET); this._showPrompt(update); - if (!Services.metro || !Services.metro.immersive) { - this._backgroundUpdateCheckCodePing(PING_BGUC_SHOWPROMPT_SNIPPET); - return; - } + return; } if (!getPref("getBoolPref", PREF_APP_UPDATE_AUTO, true)) { LOG("UpdateService:_selectAndInstallUpdate - prompting because silent " + "install is disabled"); + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_SHOWPROMPT_PREF); this._showPrompt(update); - if (!Services.metro || !Services.metro.immersive) { - this._backgroundUpdateCheckCodePing(PING_BGUC_SHOWPROMPT_PREF); - return; - } + return; } if (getPref("getIntPref", PREF_APP_UPDATE_MODE, 1) == 0) { @@ -2749,7 +2684,7 @@ UpdateService.prototype = { var status = this.downloadUpdate(update, true); if (status == STATE_NONE) cleanupActiveUpdate(); - this._backgroundUpdateCheckCodePing(PING_BGUC_ADDON_PREF_DISABLED); + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_ADDON_PREF_DISABLED); return; } @@ -2763,10 +2698,11 @@ UpdateService.prototype = { LOG("UpdateService:_selectAndInstallUpdate - add-on compatibility " + "check not performed due to the update version being the same as " + "the current application version, just download the update"); - var status = this.downloadUpdate(update, true); - if (status == STATE_NONE) + let status = this.downloadUpdate(update, true); + if (status == STATE_NONE) { cleanupActiveUpdate(); - this._backgroundUpdateCheckCodePing(PING_BGUC_ADDON_SAME_APP_VER); + } + AUSTLMY.pingCheckCode(this._pingSuffix,AUSTLMY.CHK_ADDON_SAME_APP_VER); } }, @@ -2787,8 +2723,9 @@ UpdateService.prototype = { if (!("isCompatibleWith" in addon) || !("findUpdates" in addon)) { let errMsg = "Add-on doesn't implement either the isCompatibleWith " + "or the findUpdates method!"; - if (addon.id) + if (addon.id) { errMsg += " Add-on ID: " + addon.id; + } Cu.reportError(errMsg); return; } @@ -2807,34 +2744,34 @@ UpdateService.prototype = { !addon.appDisabled && !addon.userDisabled && addon.scope != AddonManager.SCOPE_APPLICATION && !addon.isCompatibleWith(self._update.appVersion, - self._update.platformVersion)) + self._update.platformVersion)) { self._incompatibleAddons.push(addon); - } - catch (e) { + } + } catch (e) { Cu.reportError(e); } }); if (self._incompatibleAddons.length > 0) { /** -# PREF_APP_UPDATE_INCOMPATIBLE_MODE -# Controls the mode in which we check for updates as follows. -# -# PREF_APP_UPDATE_INCOMPATIBLE_MODE != 1 -# We check for VersionInfo _and_ NewerVersion updates for the -# incompatible add-ons - i.e. if Foo 1.2 is installed and it is -# incompatible with the update, and we find Foo 2.0 which is but has -# not been installed, then we do NOT prompt because the user can -# download Foo 2.0 when they restart after the update during the add-on -# mismatch checking UI. This is the default, since it suppresses most -# prompt dialogs. -# -# PREF_APP_UPDATE_INCOMPATIBLE_MODE == 1 -# We check for VersionInfo updates for the incompatible add-ons - i.e. -# if the situation above with Foo 1.2 and available update to 2.0 -# applies, we DO show the prompt since a download operation will be -# required after the update. This is not the default and is supplied -# only as a hidden option for those that want it. + * PREF_APP_UPDATE_INCOMPATIBLE_MODE + * Controls the mode in which we check for updates as follows. + * + * PREF_APP_UPDATE_INCOMPATIBLE_MODE != 1 + * We check for VersionInfo _and_ NewerVersion updates for the + * incompatible add-ons - i.e. if Foo 1.2 is installed and it is + * incompatible with the update, and we find Foo 2.0 which is but has + * not been installed, then we do NOT prompt because the user can + * download Foo 2.0 when they restart after the update during the add-on + * mismatch checking UI. This is the default, since it suppresses most + * prompt dialogs. + * + * PREF_APP_UPDATE_INCOMPATIBLE_MODE == 1 + * We check for VersionInfo updates for the incompatible add-ons - i.e. + * if the situation above with Foo 1.2 and available update to 2.0 + * applies, we DO show the prompt since a download operation will be + * required after the update. This is not the default and is supplied + * only as a hidden option for those that want it. */ self._updateCheckCount = self._incompatibleAddons.length; LOG("UpdateService:_checkAddonCompatibility - checking for " + @@ -2852,7 +2789,7 @@ UpdateService.prototype = { if (status == STATE_NONE) cleanupActiveUpdate(); self._update = null; - self._backgroundUpdateCheckCodePing(PING_BGUC_CHECK_NO_INCOMPAT); + AUSTLMY.pingCheckCode(self._pingSuffix, AUSTLMY.CHK_ADDON_NO_INCOMPAT); } }); }, @@ -2871,41 +2808,45 @@ UpdateService.prototype = { }, onUpdateAvailable: function(addon, install) { - if (getPref("getIntPref", PREF_APP_UPDATE_INCOMPATIBLE_MODE, 0) == 1) + if (getPref("getIntPref", PREF_APP_UPDATE_INCOMPATIBLE_MODE, 0) == 1) { return; + } // If the new version of this add-on is blocklisted for the new application // then it isn't a valid update and the user should still be warned that // the add-on will become incompatible. - let bs = Cc["@mozilla.org/extensions/blocklist;1"]. - getService(Ci.nsIBlocklistService); - if (bs.isAddonBlocklisted(addon, - this._update.appVersion, - this._update.platformVersion)) + if (Services.blocklist.isAddonBlocklisted(addon, this._update.appVersion, + this._update.platformVersion)) { return; + } // Compatibility or new version updates mean the same thing here. this.onCompatibilityUpdateAvailable(addon); }, onUpdateFinished: function(addon) { - if (--this._updateCheckCount > 0) + if (--this._updateCheckCount > 0) { return; + } - if (this._incompatibleAddons.length > 0 || - !(getCanApplyUpdates() && hasUpdateMutex())) { + if (this._incompatibleAddons.length > 0 || !gCanApplyUpdates) { LOG("UpdateService:onUpdateEnded - prompting because there are " + "incompatible add-ons"); + if (this._incompatibleAddons.length > 0) { + AUSTLMY.pingCheckCode(this._pingSuffix, + AUSTLMY.CHK_ADDON_HAVE_INCOMPAT); + } else { + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_UNABLE_TO_APPLY); + } this._showPrompt(this._update); - this._backgroundUpdateCheckCodePing(PING_BGUC_ADDON_HAVE_INCOMPAT); - } - else { + } else { LOG("UpdateService:_selectAndInstallUpdate - updates for all " + "incompatible add-ons found, just download the update"); var status = this.downloadUpdate(this._update, true); if (status == STATE_NONE) cleanupActiveUpdate(); - this._backgroundUpdateCheckCodePing(PING_BGUC_ADDON_UPDATES_FOR_INCOMPAT); + AUSTLMY.pingCheckCode(this._pingSuffix, + AUSTLMY.CHK_ADDON_UPDATES_FOR_INCOMPAT); } this._update = null; }, @@ -3010,21 +2951,21 @@ UpdateService.prototype = { } this._downloader.cancel(); } -#ifdef MOZ_WIDGET_GONK - var um = Cc["@mozilla.org/updates/update-manager;1"]. - getService(Ci.nsIUpdateManager); - var activeUpdate = um.activeUpdate; - if (activeUpdate && - (activeUpdate.appVersion != update.appVersion || - activeUpdate.buildID != update.buildID)) { - // We have an activeUpdate (which presumably was interrupted), and are - // about start downloading a new one. Make sure we remove all traces - // of the active one (otherwise we'll start appending the new update.mar - // the the one that's been partially downloaded). - LOG("UpdateService:downloadUpdate - removing stale active update."); - cleanupActiveUpdate(); + if (AppConstants.platform == "gonk") { + let um = Cc["@mozilla.org/updates/update-manager;1"]. + getService(Ci.nsIUpdateManager); + let activeUpdate = um.activeUpdate; + if (activeUpdate && + (activeUpdate.appVersion != update.appVersion || + activeUpdate.buildID != update.buildID)) { + // We have an activeUpdate (which presumably was interrupted), and are + // about start downloading a new one. Make sure we remove all traces + // of the active one (otherwise we'll start appending the new update.mar + // the the one that's been partially downloaded). + LOG("UpdateService:downloadUpdate - removing stale active update."); + cleanupActiveUpdate(); + } } -#endif // Set the previous application version prior to downloading the update. update.previousAppVersion = Services.appinfo.version; this._downloader = new Downloader(background, this); @@ -3073,6 +3014,8 @@ UpdateService.prototype = { if (!osApplyToDir) { LOG("UpdateService:applyOsUpdate - Error: osApplyToDir is not defined" + "in the nsIUpdate!"); + pingStateAndStatusCodes(aUpdate, false, + STATE_FAILED + ": " + FOTA_FILE_OPERATION_ERROR); handleUpdateFailure(aUpdate, FOTA_FILE_OPERATION_ERROR); return; } @@ -3082,6 +3025,8 @@ UpdateService.prototype = { if (!updateFile.exists()) { LOG("UpdateService:applyOsUpdate - Error: OS update is not found at " + updateFile.path); + pingStateAndStatusCodes(aUpdate, false, + STATE_FAILED + ": " + FOTA_FILE_OPERATION_ERROR); handleUpdateFailure(aUpdate, FOTA_FILE_OPERATION_ERROR); return; } @@ -3096,6 +3041,8 @@ UpdateService.prototype = { } catch (e) { LOG("UpdateService:applyOsUpdate - Error: Couldn't reboot into recovery" + " to apply FOTA update " + updateFile.path); + pingStateAndStatusCodes(aUpdate, false, + STATE_FAILED + ": " + FOTA_RECOVERY_ERROR); writeStatusFile(getUpdatesDir(), aUpdate.state = STATE_APPLIED); handleUpdateFailure(aUpdate, FOTA_RECOVERY_ERROR); } @@ -3383,15 +3330,20 @@ UpdateManager.prototype = { /** * See nsIUpdateService.idl */ - refreshUpdateStatus: function UM_refreshUpdateStatus(aUpdate) { - var update = this._activeUpdate ? this._activeUpdate : aUpdate; + refreshUpdateStatus: function UM_refreshUpdateStatus() { + var update = this._activeUpdate; + if (!update) { + return; + } var updateSucceeded = true; var status = readStatusFile(getUpdatesDir()); - var ary = status.split(":"); - update.state = ary[0]; - if (update.state == STATE_FAILED && ary[1]) { + pingStateAndStatusCodes(update, false, status); + var parts = status.split(":"); + update.state = parts[0]; + + if (update.state == STATE_FAILED && parts[1]) { updateSucceeded = false; - if (!handleUpdateFailure(update, ary[1])) { + if (!handleUpdateFailure(update, parts[1])) { handleFallbackToCompleteUpdate(update, true); } } @@ -3414,18 +3366,19 @@ UpdateManager.prototype = { // Do this after *everything* else, since it will likely cause the app // to shut down. -#ifdef MOZ_WIDGET_GONK - if (update.state == STATE_APPLIED) { - // Notify the user that an update has been staged and is ready for - // installation (i.e. that they should restart the application). We do - // not notify on failed update attempts. - var prompter = Cc["@mozilla.org/updates/update-prompt;1"]. - createInstance(Ci.nsIUpdatePrompt); - prompter.showUpdateDownloaded(update, true); - } else { - releaseSDCardMountLock(); + if (AppConstants.platform == "gonk") { + if (update.state == STATE_APPLIED) { + // Notify the user that an update has been staged and is ready for + // installation (i.e. that they should restart the application). We do + // not notify on failed update attempts. + let prompter = Cc["@mozilla.org/updates/update-prompt;1"]. + createInstance(Ci.nsIUpdatePrompt); + prompter.showUpdateDownloaded(update, true); + } else { + releaseSDCardMountLock(); + } + return; } -#else // Only prompt when the UI isn't already open. let windowType = getPref("getCharPref", PREF_APP_UPDATE_ALTWINDOWTYPE, null); if (Services.wm.getMostRecentWindow(UPDATE_WINDOW_NAME) || @@ -3433,14 +3386,15 @@ UpdateManager.prototype = { return; } - if (update.state == STATE_APPLIED || update.state == STATE_PENDING) { - // Notify the user that an update has been staged and is ready for - // installation (i.e. that they should restart the application). - var prompter = Cc["@mozilla.org/updates/update-prompt;1"]. + + if (update.state == STATE_APPLIED || update.state == STATE_APPLIED_SVC || + update.state == STATE_PENDING || update.state == STATE_PENDING_SVC) { + // Notify the user that an update has been staged and is ready for + // installation (i.e. that they should restart the application). + let prompter = Cc["@mozilla.org/updates/update-prompt;1"]. createInstance(Ci.nsIUpdatePrompt); prompter.showUpdateDownloaded(update, true); } -#endif }, classID: Components.ID("{093C2356-4843-4C65-8709-D7DBCBBE7DFB}"), @@ -3473,7 +3427,7 @@ Checker.prototype = { this._forced = force; // Use the override URL if specified. - var url = getPref("getCharPref", PREF_APP_UPDATE_URL_OVERRIDE, null); + let url = getPref("getCharPref", PREF_APP_UPDATE_URL_OVERRIDE, null); // Otherwise, construct the update URL from component parts. if (!url) { @@ -3494,8 +3448,9 @@ Checker.prototype = { url = url.replace(/%BUILD_ID%/g, Services.appinfo.appBuildID); url = url.replace(/%BUILD_TARGET%/g, Services.appinfo.OS + "_" + gABI); url = url.replace(/%OS_VERSION%/g, gOSVersion); - if (/%LOCALE%/.test(url)) + if (/%LOCALE%/.test(url)) { url = url.replace(/%LOCALE%/g, getLocale()); + } url = url.replace(/%CHANNEL%/g, UpdateChannel.get()); url = url.replace(/%PLATFORM_VERSION%/g, Services.appinfo.platformVersion); url = url.replace(/%DISTRIBUTION%/g, @@ -3505,14 +3460,20 @@ Checker.prototype = { url = url.replace(/%CUSTOM%/g, getPref("getCharPref", PREF_APP_UPDATE_CUSTOM, "")); url = url.replace(/\+/g, "%2B"); -#ifdef MOZ_WIDGET_GONK - url = url.replace(/%PRODUCT_MODEL%/g, gProductModel); - url = url.replace(/%PRODUCT_DEVICE%/g, gProductDevice); - url = url.replace(/%B2G_VERSION%/g, getPref("getCharPref", PREF_APP_B2G_VERSION, null)); -#endif + if (AppConstants.platform == "gonk") { + let sysLibs = {}; + Cu.import("resource://gre/modules/systemlibs.js", sysLibs); + url = url.replace(/%PRODUCT_MODEL%/g, + sysLibs.libcutils.property_get("ro.product.model")); + url = url.replace(/%PRODUCT_DEVICE%/g, + sysLibs.libcutils.property_get("ro.product.device")); + url = url.replace(/%B2G_VERSION%/g, + getPref("getCharPref", PREF_APP_B2G_VERSION, null)); + } - if (force) + if (force) { url += (url.indexOf("?") != -1 ? "&" : "?") + "force=1"; + } LOG("Checker:getUpdateURL - update URL: " + url); return url; @@ -3532,8 +3493,6 @@ Checker.prototype = { if (!url || (!this.enabled && !force)) return; - recordInHealthReport(UpdaterHealthReportFields.CHECK_START, 0); - this._request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. createInstance(Ci.nsISupports); // This is here to let unit test code override XHR @@ -3657,8 +3616,6 @@ Checker.prototype = { if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS)) Services.prefs.clearUserPref(PREF_APP_UPDATE_BACKGROUNDERRORS); - recordInHealthReport(UpdaterHealthReportFields.CHECK_SUCCESS, 0); - // Tell the callback about the updates this._callback.onCheckComplete(event.target, updates, updates.length); } @@ -3680,8 +3637,6 @@ Checker.prototype = { : CERT_ATTR_CHECK_FAILED_NO_UPDATE; } - recordInHealthReport(UpdaterHealthReportFields.CHECK_FAILED, update.errorCode); - this._callback.onError(request, update); } @@ -3713,10 +3668,7 @@ Checker.prototype = { update.errorCode = HTTP_ERROR_OFFSET + status; } - recordInHealthReport(UpdaterHealthReportFields.CHECK_FAILED, update.errorCode); - this._callback.onError(request, update); - this._request = null; }, @@ -3725,10 +3677,6 @@ Checker.prototype = { */ _enabled: true, get enabled() { - if (!gMetroUpdatesEnabled) { - return false; - } - return getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true) && gCanCheckForUpdates && hasUpdateMutex() && this._enabled; }, @@ -3806,7 +3754,9 @@ Downloader.prototype = { if (this._request && this._request instanceof Ci.nsIRequest) { this._request.cancel(cancelError); } - releaseSDCardMountLock(); + if (AppConstants.platform == "gonk") { + releaseSDCardMountLock(); + } }, /** @@ -3827,6 +3777,8 @@ Downloader.prototype = { _verifyDownload: function Downloader__verifyDownload() { LOG("Downloader:_verifyDownload called"); if (!this._request) { + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, + AUSTLMY.DWNLD_ERR_VERIFY_NO_REQUEST); return false; } @@ -3835,6 +3787,8 @@ Downloader.prototype = { // Ensure that the file size matches the expected file size. if (destination.fileSize != this._patch.size) { LOG("Downloader:_verifyDownload downloaded size != expected size."); + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, + AUSTLMY.DWNLD_ERR_VERIFY_PATCH_SIZE_NOT_EQUAL); return false; } @@ -3872,6 +3826,8 @@ Downloader.prototype = { } LOG("Downloader:_verifyDownload hashes do not match. "); + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, + AUSTLMY.DWNLD_ERR_VERIFY_NO_HASH_MATCH); return false; }, @@ -3916,38 +3872,36 @@ Downloader.prototype = { if (selectedPatch) { LOG("Downloader:_selectPatch - found existing patch with state: " + state); - switch (state) { - case STATE_DOWNLOADING: - LOG("Downloader:_selectPatch - resuming download"); - return selectedPatch; -#ifdef MOZ_WIDGET_GONK - case STATE_PENDING: - case STATE_APPLYING: - LOG("Downloader:_selectPatch - resuming interrupted apply"); - return selectedPatch; - case STATE_APPLIED: - LOG("Downloader:_selectPatch - already downloaded and staged"); - return null; -#else - case STATE_PENDING_SVC: - case STATE_PENDING: - LOG("Downloader:_selectPatch - already downloaded and staged"); - return null; -#endif - default: - // Something went wrong when we tried to apply the previous patch. - // Try the complete patch next time. - if (update && selectedPatch.type == "partial") { - useComplete = true; - } else { - // This is a pretty fatal error. Just bail. - LOG("Downloader:_selectPatch - failed to apply complete patch!"); - writeStatusFile(updateDir, STATE_NONE); - writeVersionFile(getUpdatesDir(), null); - return null; - } + if (state == STATE_DOWNLOADING) { + LOG("Downloader:_selectPatch - resuming download"); + return selectedPatch; } + if (AppConstants.platform == "gonk") { + if (state == STATE_PENDING || state == STATE_APPLYING) { + LOG("Downloader:_selectPatch - resuming interrupted apply"); + return selectedPatch; + } + if (state == STATE_APPLIED) { + LOG("Downloader:_selectPatch - already downloaded and staged"); + return null; + } + } else if (state == STATE_PENDING || state == STATE_PENDING_SVC) { + LOG("Downloader:_selectPatch - already downloaded and staged"); + return null; + } + + if (update && selectedPatch.type == "complete") { + // This is a pretty fatal error. Just bail. + LOG("Downloader:_selectPatch - failed to apply complete patch!"); + writeStatusFile(updateDir, STATE_NONE); + writeVersionFile(getUpdatesDir(), null); + return null; + } + + // Something went wrong when we tried to apply the previous patch. + // Try the complete patch next time. + useComplete = true; selectedPatch = null; } @@ -3994,15 +3948,15 @@ Downloader.prototype = { */ _getUpdateArchiveFile: function Downloader__getUpdateArchiveFile() { var updateArchive; -#ifdef USE_UPDATE_ARCHIVE_DIR - try { - updateArchive = FileUtils.getDir(KEY_UPDATE_ARCHIVE_DIR, [], true); - } catch (e) { - return null; + if (AppConstants.platform == "gonk") { + try { + updateArchive = FileUtils.getDir(KEY_UPDATE_ARCHIVE_DIR, [], true); + } catch (e) { + return null; + } + } else { + updateArchive = getUpdatesDir().clone(); } -#else - updateArchive = getUpdatesDir().clone(); -#endif updateArchive.append(FILE_UPDATE_ARCHIVE); return updateArchive; @@ -4015,8 +3969,10 @@ Downloader.prototype = { */ downloadUpdate: function Downloader_downloadUpdate(update) { LOG("UpdateService:_downloadUpdate"); - if (!update) + if (!update) { + AUSTLMY.pingDownloadCode(undefined, AUSTLMY.DWNLD_ERR_NO_UPDATE); throw Cr.NS_ERROR_NULL_POINTER; + } var updateDir = getUpdatesDir(); @@ -4027,90 +3983,92 @@ Downloader.prototype = { this._patch = this._selectPatch(update, updateDir); if (!this._patch) { LOG("Downloader:downloadUpdate - no patch to download"); + AUSTLMY.pingDownloadCode(undefined, AUSTLMY.DWNLD_ERR_NO_UPDATE_PATCH); return readStatusFile(updateDir); } this.isCompleteUpdate = this._patch.type == "complete"; - recordInHealthReport( - this.isCompleteUpdate ? UpdaterHealthReportFields.COMPLETE_START : - UpdaterHealthReportFields.PARTIAL_START, 0); + let patchFile = null; - var patchFile = null; - -#ifdef MOZ_WIDGET_GONK - let status = readStatusFile(updateDir); - if (isInterruptedUpdate(status)) { - LOG("Downloader:downloadUpdate - interruptted update"); - // The update was interrupted. Try to locate the existing patch file. - // For an interrupted download, this allows a resume rather than a - // re-download. - patchFile = getFileFromUpdateLink(updateDir); - if (!patchFile) { - // No link file. We'll just assume that the update.mar is in the - // update directory. - patchFile = updateDir.clone(); - patchFile.append(FILE_UPDATE_ARCHIVE); - } - if (patchFile.exists()) { - LOG("Downloader:downloadUpdate - resuming with patchFile " + patchFile.path); - if (patchFile.fileSize == this._patch.size) { - LOG("Downloader:downloadUpdate - patchFile appears to be fully downloaded"); - // Bump the status along so that we don't try to redownload again. - status = STATE_PENDING; + // Only used by gonk + let status = STATE_NONE; + if (AppConstants.platform == "gonk") { + status = readStatusFile(updateDir); + if (isInterruptedUpdate(status)) { + LOG("Downloader:downloadUpdate - interruptted update"); + // The update was interrupted. Try to locate the existing patch file. + // For an interrupted download, this allows a resume rather than a + // re-download. + patchFile = getFileFromUpdateLink(updateDir); + if (!patchFile) { + // No link file. We'll just assume that the update.mar is in the + // update directory. + patchFile = updateDir.clone(); + patchFile.append(FILE_UPDATE_ARCHIVE); } - } else { - LOG("Downloader:downloadUpdate - patchFile " + patchFile.path + - " doesn't exist - performing full download"); - // The patchfile doesn't exist, we might as well treat this like - // a new download. - patchFile = null; - } - if (patchFile && (status != STATE_DOWNLOADING)) { - // It looks like the patch was downloaded, but got interrupted while it - // was being verified or applied. So we'll fake the downloading portion. + if (patchFile.exists()) { + LOG("Downloader:downloadUpdate - resuming with patchFile " + patchFile.path); + if (patchFile.fileSize == this._patch.size) { + LOG("Downloader:downloadUpdate - patchFile appears to be fully downloaded"); + // Bump the status along so that we don't try to redownload again. + status = STATE_PENDING; + } + } else { + LOG("Downloader:downloadUpdate - patchFile " + patchFile.path + + " doesn't exist - performing full download"); + // The patchfile doesn't exist, we might as well treat this like + // a new download. + patchFile = null; + } + if (patchFile && status != STATE_DOWNLOADING) { + // It looks like the patch was downloaded, but got interrupted while it + // was being verified or applied. So we'll fake the downloading portion. - writeStatusFile(updateDir, STATE_PENDING); + writeStatusFile(updateDir, STATE_PENDING); - // Since the code expects the onStopRequest callback to happen - // asynchronously (And you have to call AUS_addDownloadListener - // after calling AUS_downloadUpdate) we need to defer this. + // Since the code expects the onStopRequest callback to happen + // asynchronously (And you have to call AUS_addDownloadListener + // after calling AUS_downloadUpdate) we need to defer this. - this._downloadTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this._downloadTimer.initWithCallback(function() { - this._downloadTimer = null; - // Send a fake onStopRequest. Filling in the destination allows - // _verifyDownload to work, and then the update will be applied. - this._request = {destination: patchFile}; - this.onStopRequest(this._request, null, Cr.NS_OK); - }.bind(this), 0, Ci.nsITimer.TYPE_ONE_SHOT); + this._downloadTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + this._downloadTimer.initWithCallback(function() { + this._downloadTimer = null; + // Send a fake onStopRequest. Filling in the destination allows + // _verifyDownload to work, and then the update will be applied. + this._request = {destination: patchFile}; + this.onStopRequest(this._request, null, Cr.NS_OK); + }.bind(this), 0, Ci.nsITimer.TYPE_ONE_SHOT); - // Returning STATE_DOWNLOADING makes UpdatePrompt think we're - // downloading. The onStopRequest that we spoofed above will make it - // look like the download finished. - return STATE_DOWNLOADING; + // Returning STATE_DOWNLOADING makes UpdatePrompt think we're + // downloading. The onStopRequest that we spoofed above will make it + // look like the download finished. + return STATE_DOWNLOADING; + } } } -#endif + if (!patchFile) { // Find a place to put the patchfile that we're going to download. patchFile = this._getUpdateArchiveFile(); } if (!patchFile) { + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, + AUSTLMY.DWNLD_ERR_NO_PATCH_FILE); return STATE_NONE; } -#ifdef MOZ_WIDGET_GONK - if (patchFile.path.indexOf(updateDir.path) != 0) { - // The patchFile is in a directory which is different from the - // updateDir, create a link file. - writeLinkFile(updateDir, patchFile); + if (AppConstants.platform == "gonk") { + if (patchFile.path.indexOf(updateDir.path) != 0) { + // The patchFile is in a directory which is different from the + // updateDir, create a link file. + writeLinkFile(updateDir, patchFile); - if (!isInterruptedUpdate(status) && patchFile.exists()) { - // Remove stale patchFile - patchFile.remove(false); + if (!isInterruptedUpdate(status) && patchFile.exists()) { + // Remove stale patchFile + patchFile.remove(false); + } } } -#endif var uri = Services.io.newURI(this._patch.URL, null, null); @@ -4213,6 +4171,8 @@ Downloader.prototype = { // It's important that we use a different code than // NS_ERROR_CORRUPTED_CONTENT so that tests can verify the difference // between a hash error and a wrong download error. + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, + AUSTLMY.DWNLD_ERR_PATCH_SIZE_LARGER); this.cancel(Cr.NS_ERROR_UNEXPECTED); return; } @@ -4223,6 +4183,8 @@ Downloader.prototype = { // It's important that we use a different code than // NS_ERROR_CORRUPTED_CONTENT so that tests can verify the difference // between a hash error and a wrong download error. + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, + AUSTLMY.DWNLD_ERR_PATCH_SIZE_NOT_EQUAL); this.cancel(Cr.NS_ERROR_UNEXPECTED); return; } @@ -4290,15 +4252,12 @@ Downloader.prototype = { "current fail: " + this.updateService._consecutiveSocketErrors + ", " + "max fail: " + maxFail + ", " + "retryTimeout: " + retryTimeout); if (Components.isSuccessCode(status)) { - recordInHealthReport( - this.isCompleteUpdate ? UpdaterHealthReportFields.COMPLETE_SUCCESS : - UpdaterHealthReportFields.PARTIAL_SUCCESS, 0); - if (this._verifyDownload()) { state = STATE_PENDING; if (this.background) { shouldShowPrompt = !getCanStageUpdates(); } + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, AUSTLMY.DWNLD_SUCCESS); // Tell the updater.exe we're ready to apply. writeStatusFile(getUpdatesDir(), state); @@ -4323,14 +4282,14 @@ Downloader.prototype = { cleanUpUpdatesDir(); } } else { - recordInHealthReport(UpdaterHealthReportFields.FAILED, status); - if (status == Cr.NS_ERROR_OFFLINE) { // Register an online observer to try again. // The online observer will continue the incremental download by // calling downloadUpdate on the active update which continues // downloading the file from where it was. LOG("Downloader:onStopRequest - offline, register online observer: true"); + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, + AUSTLMY.DWNLD_RETRY_OFFLINE); shouldRegisterOnlineObserver = true; deleteActiveUpdate = false; // Each of NS_ERROR_NET_TIMEOUT, ERROR_CONNECTION_REFUSED, and @@ -4342,12 +4301,27 @@ Downloader.prototype = { status == Cr.NS_ERROR_NET_RESET) && this.updateService._consecutiveSocketErrors < maxFail) { LOG("Downloader:onStopRequest - socket error, shouldRetrySoon: true"); + let dwnldCode = AUSTLMY.DWNLD_RETRY_CONNECTION_REFUSED; + if (status == Cr.NS_ERROR_NET_TIMEOUT) { + dwnldCode = AUSTLMY.DWNLD_RETRY_NET_TIMEOUT; + } else if (status == Cr.NS_ERROR_NET_RESET) { + dwnldCode = AUSTLMY.DWNLD_RETRY_NET_RESET; + } + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, dwnldCode); shouldRetrySoon = true; deleteActiveUpdate = false; } else if (status != Cr.NS_BINDING_ABORTED && status != Cr.NS_ERROR_ABORT && status != Cr.NS_ERROR_DOCUMENT_NOT_CACHED) { LOG("Downloader:onStopRequest - non-verification failure"); + let dwnldCode = AUSTLMY.DWNLD_ERR_DOCUMENT_NOT_CACHED; + if (status == Cr.NS_BINDING_ABORTED) { + dwnldCode = AUSTLMY.DWNLD_ERR_BINDING_ABORTED; + } else if (status == Cr.NS_ERROR_ABORT) { + dwnldCode = AUSTLMY.DWNLD_ERR_ABORT; + } + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, dwnldCode); + // Some sort of other failure, log this in the |statusText| property state = STATE_DOWNLOAD_FAILED; @@ -4357,12 +4331,12 @@ Downloader.prototype = { this._update.statusText = getStatusTextFromCode(status, Cr.NS_BINDING_FAILED); -#ifdef MOZ_WIDGET_GONK - // bug891009: On FirefoxOS, manaully retry OTA download will reuse - // the Update object. We need to remove selected patch so that download - // can be triggered again successfully. - this._update.selectedPatch.selected = false; -#endif + if (AppConstants.platform == "gonk") { + // bug891009: On FirefoxOS, manaully retry OTA download will reuse + // the Update object. We need to remove selected patch so that download + // can be triggered again successfully. + this._update.selectedPatch.selected = false; + } // Destroy the updates directory, since we're done with it. cleanUpUpdatesDir(); @@ -4379,8 +4353,9 @@ Downloader.prototype = { um.activeUpdate = null; } else { - if (um.activeUpdate) + if (um.activeUpdate) { um.activeUpdate.state = state; + } } um.saveUpdates(); @@ -4427,12 +4402,12 @@ Downloader.prototype = { } } -#ifdef MOZ_WIDGET_GONK - // We always forward errors in B2G, since Gaia controls the update UI - var prompter = Cc["@mozilla.org/updates/update-prompt;1"]. - createInstance(Ci.nsIUpdatePrompt); - prompter.showUpdateError(this._update); -#endif + if (AppConstants.platform == "gonk") { + // We always forward errors in B2G, since Gaia controls the update UI + let prompter = Cc["@mozilla.org/updates/update-prompt;1"]. + createInstance(Ci.nsIUpdatePrompt); + prompter.showUpdateError(this._update); + } // Prevent leaking the update object (bug 454964). this._update = null; @@ -4469,7 +4444,7 @@ Downloader.prototype = { // Notify the user that an update has been downloaded and is ready for // installation (i.e. that they should restart the application). We do // not notify on failed update attempts. - var prompter = Cc["@mozilla.org/updates/update-prompt;1"]. + let prompter = Cc["@mozilla.org/updates/update-prompt;1"]. createInstance(Ci.nsIUpdatePrompt); prompter.showUpdateDownloaded(this._update, true); } @@ -4609,14 +4584,10 @@ UpdatePrompt.prototype = { this._getAltUpdateWindow()) return; - // In some cases, we want to just show a simple alert dialog: + // In some cases, we want to just show a simple alert dialog. + // Replace with Array.prototype.includes when it has stabilized. if (update.state == STATE_FAILED && - (update.errorCode == WRITE_ERROR || - update.errorCode == WRITE_ERROR_ACCESS_DENIED || - update.errorCode == WRITE_ERROR_SHARING_VIOLATION_SIGNALED || - update.errorCode == WRITE_ERROR_SHARING_VIOLATION_NOPROCESSFORPID || - update.errorCode == WRITE_ERROR_SHARING_VIOLATION_NOPID || - update.errorCode == WRITE_ERROR_CALLBACK_APP || + (WRITE_ERRORS.indexOf(update.errorCode) != -1 || update.errorCode == FILESYSTEM_MOUNT_READWRITE_ERROR || update.errorCode == FOTA_GENERAL_ERROR || update.errorCode == FOTA_FILE_OPERATION_ERROR || @@ -4850,57 +4821,3 @@ UpdatePrompt.prototype = { var components = [UpdateService, Checker, UpdatePrompt, UpdateManager]; this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); - -#if 0 -/** - * Logs a message and stack trace to the console. - * @param string - * The string to write to the console. - */ -function STACK(string) { - dump("*** " + string + "\n"); - stackTrace(arguments.callee.caller.arguments, -1); -} - -function stackTraceFunctionFormat(aFunctionName) { - var classDelimiter = aFunctionName.indexOf("_"); - var className = aFunctionName.substr(0, classDelimiter); - if (!className) - className = ""; - var functionName = aFunctionName.substr(classDelimiter + 1, aFunctionName.length); - if (!functionName) - functionName = ""; - return className + "::" + functionName; -} - -function stackTraceArgumentsFormat(aArguments) { - arglist = ""; - for (var i = 0; i < aArguments.length; i++) { - arglist += aArguments[i]; - if (i < aArguments.length - 1) - arglist += ", "; - } - return arglist; -} - -function stackTrace(aArguments, aMaxCount) { - dump("=[STACKTRACE]=====================================================\n"); - dump("*** at: " + stackTraceFunctionFormat(aArguments.callee.name) + "(" + - stackTraceArgumentsFormat(aArguments) + ")\n"); - var temp = aArguments.callee.caller; - var count = 0; - while (temp) { - dump("*** " + stackTraceFunctionFormat(temp.name) + "(" + - stackTraceArgumentsFormat(temp.arguments) + ")\n"); - - temp = temp.arguments.callee.caller; - if (aMaxCount > 0 && ++count == aMaxCount) - break; - } - dump("==================================================================\n"); -} - -function dumpFile(file) { - dump("*** file = " + file.path + ", exists = " + file.exists() + "\n"); -} -#endif diff --git a/toolkit/mozapps/update/nsUpdateServiceStub.js b/toolkit/mozapps/update/nsUpdateServiceStub.js index 70f130f543..92d1267373 100644 --- a/toolkit/mozapps/update/nsUpdateServiceStub.js +++ b/toolkit/mozapps/update/nsUpdateServiceStub.js @@ -3,137 +3,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const Ci = Components.interfaces; -const Cc = Components.classes; -const Cu = Components.utils; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); +Cu.import("resource://gre/modules/FileUtils.jsm", this); const DIR_UPDATES = "updates"; -const FILE_UPDATES_DB = "updates.xml"; -const FILE_UPDATE_ACTIVE = "active-update.xml"; -const FILE_LAST_LOG = "last-update.log"; -const FILE_BACKUP_LOG = "backup-update.log"; const FILE_UPDATE_STATUS = "update.status"; const KEY_UPDROOT = "UpdRootD"; -#ifdef XP_WIN - -const PREF_APP_UPDATE_MIGRATE_APP_DIR = "app.update.migrated.updateDir"; - - -function getTaskbarIDHash(rootKey, exePath, appInfoName) { - let registry = Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(Ci.nsIWindowsRegKey); - try { - registry.open(rootKey, "Software\\Mozilla\\" + appInfoName + "\\TaskBarIDs", - Ci.nsIWindowsRegKey.ACCESS_READ); - if (registry.hasValue(exePath)) { - return registry.readStringValue(exePath); - } - } catch (ex) { - } finally { - registry.close(); - } - return undefined; -}; - -/* - * Migrates old update directory files to the new update directory - * which is based on a hash of the installation. - */ -function migrateOldUpdateDir() { - // Get the old udpate root leaf dir. It is based on the sub directory of - // program files, or if the exe path is not inside program files, the appname. - var appinfo = Components.classes["@mozilla.org/xre/app-info;1"]. - getService(Components.interfaces.nsIXULAppInfo). - QueryInterface(Components.interfaces.nsIXULRuntime); - var updateLeafName; - var programFiles = FileUtils.getFile("ProgF", []); - var exeFile = FileUtils.getFile("XREExeF", []); - if (exeFile.path.substring(0, programFiles.path.length).toLowerCase() == - programFiles.path.toLowerCase()) { - updateLeafName = exeFile.parent.leafName; - } else { - updateLeafName = appinfo.name; - } - - // Get the old update root dir - var oldUpdateRoot; - if (appinfo.vendor) { - oldUpdateRoot = FileUtils.getDir("LocalAppData", [appinfo.vendor, - appinfo.name, - updateLeafName], false); - } else { - oldUpdateRoot = FileUtils.getDir("LocalAppData", [appinfo.name, - updateLeafName], false); - } - - // Obtain the new update root - var newUpdateRoot = FileUtils.getDir("UpdRootD", [], true); - - // If there is no taskbar ID then we want to retry this migration - // at a later time if the application gets a taskbar ID. - var taskbarID = getTaskbarIDHash(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, - exeFile.parent.path, appinfo.name); - if (!taskbarID) { - taskbarID = getTaskbarIDHash(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, - exeFile.parent.path, appinfo.name); - if (!taskbarID) { - return; - } - } - - Services.prefs.setBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR, true); - - // Sanity checks only to ensure we don't delete something we don't mean to. - if (oldUpdateRoot.path.toLowerCase() == newUpdateRoot.path.toLowerCase() || - updateLeafName.length == 0) { - return; - } - - // If the old update root doesn't exist then we have already migrated - // or else there is no work to do. - if (!oldUpdateRoot.exists()) { - return; - } - - // Get an array of all of the files we want to migrate. - // We do this so we don't copy anything extra. - var filesToMigrate = [FILE_UPDATES_DB, FILE_UPDATE_ACTIVE, - ["updates", FILE_LAST_LOG], ["updates", FILE_BACKUP_LOG], - ["updates", "0", FILE_UPDATE_STATUS]]; - - // Move each of those files to the new directory - filesToMigrate.forEach(relPath => { - let oldFile = oldUpdateRoot.clone(); - let newFile = newUpdateRoot.clone(); - if (relPath instanceof Array) { - relPath.forEach(relPathPart => { - oldFile.append(relPathPart); - newFile.append(relPathPart); - }); - } else { - oldFile.append(relPath); - newFile.append(relPath); - } - - try { - if (!newFile.exists()) { - oldFile.moveTo(newFile.parent, newFile.leafName); - } - } catch (e) { - Components.utils.reportError(e); - } - }); - - oldUpdateRoot.remove(true); -} -#endif - /** * Gets the specified directory at the specified hierarchy under the update root * directory without creating it if it doesn't exist. @@ -147,28 +26,11 @@ function getUpdateDirNoCreate(pathArray) { } function UpdateServiceStub() { -#ifdef XP_WIN - // Don't attempt this migration more than once for perf reasons - var migrated = 0; - try { - migrated = Services.prefs.getBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR); - } catch (e) { - } - - if (!migrated) { - try { - migrateOldUpdateDir(); - } catch (e) { - Components.utils.reportError(e); - } - } -#endif - let statusFile = getUpdateDirNoCreate([DIR_UPDATES, "0"]); statusFile.append(FILE_UPDATE_STATUS); // If the update.status file exists then initiate post update processing. if (statusFile.exists()) { - let aus = Components.classes["@mozilla.org/updates/update-service;1"]. + let aus = Cc["@mozilla.org/updates/update-service;1"]. getService(Ci.nsIApplicationUpdateService). QueryInterface(Ci.nsIObserver); aus.observe(null, "post-update-processing", ""); diff --git a/toolkit/mozapps/update/nsUpdateTimerManager.js b/toolkit/mozapps/update/nsUpdateTimerManager.js index 184dd6fcf9..2f6041a795 100644 --- a/toolkit/mozapps/update/nsUpdateTimerManager.js +++ b/toolkit/mozapps/update/nsUpdateTimerManager.js @@ -2,8 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm", this); +Components.utils.import("resource://gre/modules/Services.jsm", this); const Cc = Components.classes; const Ci = Components.interfaces; diff --git a/toolkit/mozapps/update/tests/Makefile.in b/toolkit/mozapps/update/tests/Makefile.in index d3cd98c94a..371c55a16a 100644 --- a/toolkit/mozapps/update/tests/Makefile.in +++ b/toolkit/mozapps/update/tests/Makefile.in @@ -5,49 +5,40 @@ XPCSHELLTESTROOT = $(abspath $(DEPTH))/_tests/xpcshell/$(relativesrcdir) CHROMETESTROOT = $(abspath $(DEPTH))/_tests/testing/mochitest/chrome/$(relativesrcdir) -PP_TARGETS += aus-update-head -aus-update-head_FLAGS := -Fsubstitution $(DEFINES) $(ACDEFINES) -aus-update-head := $(srcdir)/unit_aus_update/head_update.js -aus-update-head_PATH := $(XPCSHELLTESTROOT)/unit_aus_update -aus-update-head_TARGET := misc +pp_const_file = $(srcdir)/data/xpcshellConstantsPP.js -INSTALL_TARGETS += xpcshell-data -xpcshell-data_TARGET := misc -xpcshell-data_DEST := $(XPCSHELLTESTROOT)/data -xpcshell-data_FILES := $(wildcard $(srcdir)/data/*) +PP_TARGETS += aus-test-const +aus-test-const := $(pp_const_file) +aus-test-const_PATH := $(XPCSHELLTESTROOT)/data +aus-test-const_FLAGS := -Fsubstitution $(DEFINES) $(ACDEFINES) +aus-test-const_TARGET := misc + +INSTALL_TARGETS += xpcshell-data +xpcshell-data_FILES := $(filter-out $(pp_const_file),$(wildcard $(srcdir)/data/*)) +xpcshell-data_DEST := $(XPCSHELLTESTROOT)/data +xpcshell-data_TARGET := misc # Android doesn't use the Mozilla updater or the toolkit update UI ifneq (android,$(MOZ_WIDGET_TOOLKIT)) -INSTALL_TARGETS += base-updater-head -base-updater-head_TARGET := misc -base-updater-head_DEST := $(XPCSHELLTESTROOT)/unit_base_updater -base-updater-head_FILES := $(XPCSHELLTESTROOT)/unit_aus_update/head_update.js ifndef MOZ_PROFILE_GENERATE ifdef COMPILE_ENVIRONMENT -INSTALL_TARGETS += xpcshell-test-helper -xpcshell-test-helper_TARGET := misc -xpcshell-test-helper_DEST := $(XPCSHELLTESTROOT)/data -xpcshell-test-helper_FILES := $(DIST)/bin/TestAUSHelper$(BIN_SUFFIX) +INSTALL_TARGETS += xpcshell-helper +xpcshell-helper_FILES := $(DIST)/bin/TestAUSHelper$(BIN_SUFFIX) +xpcshell-helper_DEST := $(XPCSHELLTESTROOT)/data +xpcshell-helper_TARGET := misc endif endif # Not MOZ_PROFILE_GENERATE -_CHROME_SHARED := \ - update.sjs \ - utils.js \ - $(NULL) -PP_TARGETS += chrome-shared -chrome-shared := $(addprefix $(srcdir)/chrome/,$(_CHROME_SHARED)) -chrome-shared_PATH := $(CHROMETESTROOT)/chrome -chrome-shared_TARGET := misc - _CHROME_DATA := \ + shared.js \ + sharedUpdateXML.js \ simple.mar \ $(NULL) -INSTALL_TARGETS += chrome-data -chrome-data_TARGET := misc -chrome-data_DEST := $(CHROMETESTROOT)/data -chrome-data_FILES := $(addprefix $(srcdir)/data/,$(_CHROME_DATA)) +INSTALL_TARGETS += chrome-data +chrome-data_FILES := $(addprefix $(srcdir)/data/,$(_CHROME_DATA)) +chrome-data_DEST := $(CHROMETESTROOT)/data +chrome-data_TARGET := misc INI_TEST_FILES = \ TestAUSReadStrings1.ini \ diff --git a/toolkit/mozapps/update/tests/TestAUSHelper.cpp b/toolkit/mozapps/update/tests/TestAUSHelper.cpp index 537701cfbb..e23c60589f 100644 --- a/toolkit/mozapps/update/tests/TestAUSHelper.cpp +++ b/toolkit/mozapps/update/tests/TestAUSHelper.cpp @@ -77,8 +77,9 @@ static void WriteMsg(const NS_tchar *path, const char *status) { FILE* outFP = NS_tfopen(path, NS_T("wb")); - if (!outFP) + if (!outFP) { return; + } fprintf(outFP, "%s\n", status); fclose(outFP); @@ -207,7 +208,7 @@ int NS_main(int argc, NS_tchar **argv) } else { return 1; } -#else +#else // Not implemented on non-Windows platforms return 1; #endif @@ -285,7 +286,7 @@ int NS_main(int argc, NS_tchar **argv) } else { return serviceState; } -#else +#else // Not implemented on non-Windows platforms return 1; #endif @@ -303,7 +304,7 @@ int NS_main(int argc, NS_tchar **argv) } else { return 2; } -#else +#else // Not implemented on non-Windows platforms return 1; #endif @@ -372,4 +373,4 @@ int NS_main(int argc, NS_tchar **argv) } return 0; -} +} diff --git a/toolkit/mozapps/update/tests/TestAUSReadStrings.cpp b/toolkit/mozapps/update/tests/TestAUSReadStrings.cpp index 64d46e3b13..c1de44f8ef 100644 --- a/toolkit/mozapps/update/tests/TestAUSReadStrings.cpp +++ b/toolkit/mozapps/update/tests/TestAUSReadStrings.cpp @@ -117,8 +117,7 @@ int NS_main(int argc, NS_tchar **argv) rv = 22; fail("%s | Info ini value incorrect (check 4)", TEST_NAME); } - } - else { + } else { fail("%s | ReadStrings returned %i (check 2)", TEST_NAME, retval); rv = 23; } @@ -157,8 +156,7 @@ int NS_main(int argc, NS_tchar **argv) rv = 27; fail("%s | Title ini value incorrect (check 9)", TEST_NAME); } - } - else { + } else { fail("%s | ReadStrings returned %i (check 8)", TEST_NAME, retval); rv = 28; } diff --git a/toolkit/mozapps/update/tests/chrome/chrome.ini b/toolkit/mozapps/update/tests/chrome/chrome.ini index 0846e1ef9f..f22f9ce5f2 100644 --- a/toolkit/mozapps/update/tests/chrome/chrome.ini +++ b/toolkit/mozapps/update/tests/chrome/chrome.ini @@ -7,9 +7,6 @@ skip-if = buildapp == 'mulet' support-files = utils.js update.sjs -generated-files = - utils.js - update.sjs ; mochitest-chrome tests must start with "test_" and are executed in sorted ; order and not in the order specified in the manifest. @@ -70,6 +67,8 @@ reason = Bug 918029 - timeout caused by copying too many files. [test_0103_background_restartNotification_stagingService.xul] skip-if = os != 'win' reason = only Windows has the maintenance service. +[test_0104_background_restartNotification_NoIncompatAddons.xul] +[test_0105_background_restartNotification_VersionCompatAddons.xul] [test_0111_neverButton_basic.xul] [test_0112_neverButton_billboard.xul] [test_0113_showNeverForVersionRemovedWithPref.xul] diff --git a/toolkit/mozapps/update/tests/chrome/test_0096_restartNotification_stagedBackground.xul b/toolkit/mozapps/update/tests/chrome/test_0096_restartNotification_stagedBackground.xul index 2efc983d59..ba43af8c4c 100644 --- a/toolkit/mozapps/update/tests/chrome/test_0096_restartNotification_stagedBackground.xul +++ b/toolkit/mozapps/update/tests/chrome/test_0096_restartNotification_stagedBackground.xul @@ -49,7 +49,7 @@ function runTest() { "update's promptWaitTime attribute value was set from the " + PREF_APP_UPDATE_PROMPTWAITTIME + " preference"); - gUpdateManager.refreshUpdateStatus(gUpdateManager.activeUpdate); + gUpdateManager.refreshUpdateStatus(); } ]]> diff --git a/toolkit/mozapps/update/tests/chrome/test_0097_restartNotification_stagedServiceBackground.xul b/toolkit/mozapps/update/tests/chrome/test_0097_restartNotification_stagedServiceBackground.xul index 568e7f0e5b..852a16f2ba 100644 --- a/toolkit/mozapps/update/tests/chrome/test_0097_restartNotification_stagedServiceBackground.xul +++ b/toolkit/mozapps/update/tests/chrome/test_0097_restartNotification_stagedServiceBackground.xul @@ -49,7 +49,7 @@ function runTest() { "update's promptWaitTime attribute value was set from the " + PREF_APP_UPDATE_PROMPTWAITTIME + " preference"); - gUpdateManager.refreshUpdateStatus(gUpdateManager.activeUpdate); + gUpdateManager.refreshUpdateStatus(); } ]]> diff --git a/toolkit/mozapps/update/tests/chrome/test_0104_background_restartNotification_NoIncompatAddons.xul b/toolkit/mozapps/update/tests/chrome/test_0104_background_restartNotification_NoIncompatAddons.xul new file mode 100644 index 0000000000..979df6db10 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0104_background_restartNotification_NoIncompatAddons.xul @@ -0,0 +1,51 @@ + + + + + + + + + + + + + +

+ +

+
+
diff --git a/toolkit/mozapps/update/tests/chrome/test_0105_background_restartNotification_VersionCompatAddons.xul b/toolkit/mozapps/update/tests/chrome/test_0105_background_restartNotification_VersionCompatAddons.xul
new file mode 100644
index 0000000000..6ee7acce2f
--- /dev/null
+++ b/toolkit/mozapps/update/tests/chrome/test_0105_background_restartNotification_VersionCompatAddons.xul
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+  

+ +

+
+
diff --git a/toolkit/mozapps/update/tests/chrome/test_0121_check_requireBuiltinCert.xul b/toolkit/mozapps/update/tests/chrome/test_0121_check_requireBuiltinCert.xul index cc9dfe64db..c0aebd1c47 100644 --- a/toolkit/mozapps/update/tests/chrome/test_0121_check_requireBuiltinCert.xul +++ b/toolkit/mozapps/update/tests/chrome/test_0121_check_requireBuiltinCert.xul @@ -26,7 +26,7 @@ const TESTS = [ { buttonClick: "finish" } ]; -Components.utils.import("resource://gre/modules/CertUtils.jsm"); +Cu.import("resource://gre/modules/CertUtils.jsm"); const CERT_ATTRS = ["nickname", "emailAddress", "subjectName", "commonName", "organization", "organizationalUnit", "sha1Fingerprint", @@ -39,8 +39,8 @@ var gRequest; function runTest() { debugDump("entering"); - gRequest = AUS_Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. - createInstance(AUS_Ci.nsIXMLHttpRequest); + gRequest = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. + createInstance(Ci.nsIXMLHttpRequest); gRequest.open("GET", "https://example.com/", true); gRequest.channel.notificationCallbacks = new BadCertHandler(true); gRequest.onload = function(event) { testXHRLoad(event); }; @@ -53,16 +53,17 @@ function testXHRError(aEvent) { ok(true, "Entering testXHRError - something went wrong"); - var request = aEvent.target; - var status = 0; + let request = aEvent.target; + let status = 0; try { status = request.status; } catch (e) { } - if (status == 0) - status = request.channel.QueryInterface(AUS_Ci.nsIRequest).status; + if (status == 0) { + status = request.channel.QueryInterface(Ci.nsIRequest).status; + } ok(false, "XHR onerror called: " + status); @@ -73,9 +74,9 @@ function testXHRError(aEvent) { function testXHRLoad(aEvent) { debugDump("entering"); - var channel = aEvent.target.channel; - var cert = channel.securityInfo.QueryInterface(AUS_Ci.nsISSLStatusProvider). - SSLStatus.QueryInterface(AUS_Ci.nsISSLStatus).serverCert; + let channel = aEvent.target.channel; + let cert = channel.securityInfo.QueryInterface(Ci.nsISSLStatusProvider). + SSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert; CERT_ATTRS.forEach(function(aCertAttrName) { Services.prefs.setCharPref(PREF_APP_UPDATE_CERTS_BRANCH + "1." + aCertAttrName, cert[aCertAttrName]); diff --git a/toolkit/mozapps/update/tests/chrome/test_0122_check_allowNonBuiltinCert_validCertAttrs.xul b/toolkit/mozapps/update/tests/chrome/test_0122_check_allowNonBuiltinCert_validCertAttrs.xul index f3e1d312c3..a9726de8ca 100644 --- a/toolkit/mozapps/update/tests/chrome/test_0122_check_allowNonBuiltinCert_validCertAttrs.xul +++ b/toolkit/mozapps/update/tests/chrome/test_0122_check_allowNonBuiltinCert_validCertAttrs.xul @@ -26,7 +26,7 @@ const TESTS = [ { buttonClick: "extra1" } ]; -Components.utils.import("resource://gre/modules/CertUtils.jsm"); +Cu.import("resource://gre/modules/CertUtils.jsm"); const CERT_ATTRS = ["nickname", "emailAddress", "subjectName", "commonName", "organization", "organizationalUnit", "sha1Fingerprint", @@ -39,8 +39,8 @@ var gRequest; function runTest() { debugDump("entering"); - gRequest = AUS_Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. - createInstance(AUS_Ci.nsIXMLHttpRequest); + gRequest = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. + createInstance(Ci.nsIXMLHttpRequest); gRequest.open("GET", "https://example.com/", true); gRequest.channel.notificationCallbacks = new BadCertHandler(true); gRequest.onload = function(event) { testXHRLoad(event); }; @@ -53,16 +53,17 @@ function testXHRError(aEvent) { ok(true, "Entering testXHRError - something went wrong"); - var request = aEvent.target; - var status = 0; + let request = aEvent.target; + let status = 0; try { status = request.status; } catch (e) { } - if (status == 0) - status = request.channel.QueryInterface(AUS_Ci.nsIRequest).status; + if (status == 0) { + status = request.channel.QueryInterface(Ci.nsIRequest).status; + } ok(false, "XHR onerror called: " + status); @@ -73,9 +74,9 @@ function testXHRError(aEvent) { function testXHRLoad(aEvent) { debugDump("entering"); - var channel = aEvent.target.channel; - var cert = channel.securityInfo.QueryInterface(AUS_Ci.nsISSLStatusProvider). - SSLStatus.QueryInterface(AUS_Ci.nsISSLStatus).serverCert; + let channel = aEvent.target.channel; + let cert = channel.securityInfo.QueryInterface(Ci.nsISSLStatusProvider). + SSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert; CERT_ATTRS.forEach(function(aCertAttrName) { Services.prefs.setCharPref(PREF_APP_UPDATE_CERTS_BRANCH + "1." + aCertAttrName, cert[aCertAttrName]); diff --git a/toolkit/mozapps/update/tests/chrome/test_0123_check_allowNonBuiltinCert_noCertAttrsCheck.xul b/toolkit/mozapps/update/tests/chrome/test_0123_check_allowNonBuiltinCert_noCertAttrsCheck.xul index 908c3ed0a3..1356aa038e 100644 --- a/toolkit/mozapps/update/tests/chrome/test_0123_check_allowNonBuiltinCert_noCertAttrsCheck.xul +++ b/toolkit/mozapps/update/tests/chrome/test_0123_check_allowNonBuiltinCert_noCertAttrsCheck.xul @@ -26,7 +26,7 @@ const TESTS = [ { buttonClick: "extra1" } ]; -Components.utils.import("resource://gre/modules/CertUtils.jsm"); +Cu.import("resource://gre/modules/CertUtils.jsm"); function runTest() { debugDump("entering"); diff --git a/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul b/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul index 430d0799af..2c5fd34945 100644 --- a/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul +++ b/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul @@ -68,7 +68,7 @@ function runTest() { ok(!file.exists(), file.path + " should not exist"); let addonPrepDir = Services.dirsvc.get(NS_APP_USER_PROFILE_50_DIR, - AUS_Ci.nsILocalFile); + Ci.nsILocalFile); addonPrepDir.append(ADDON_PREP_DIR); // Not being able to remove the directory used to create the test add-ons // will not adversely affect subsequent tests so wrap it in a try block and diff --git a/toolkit/mozapps/update/tests/chrome/update.sjs b/toolkit/mozapps/update/tests/chrome/update.sjs index 13fd8e0649..e74e547676 100644 --- a/toolkit/mozapps/update/tests/chrome/update.sjs +++ b/toolkit/mozapps/update/tests/chrome/update.sjs @@ -4,32 +4,51 @@ /** * Server side http server script for application update tests. - * - * !IMPORTANT - Since xpcshell used by the http server is launched with -v 170 - * this file must not use features greater than JavaScript 1.7. */ -const AUS_Cc = Components.classes; -const AUS_Ci = Components.interfaces; +const { classes: Cc, interfaces: Ci } = Components; -#include ../sharedUpdateXML.js +const REL_PATH_DATA = "chrome/toolkit/mozapps/update/tests/data/"; + +function getTestDataFile(aFilename) { + let file = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties).get("CurWorkD", Ci.nsILocalFile); + let pathParts = REL_PATH_DATA.split("/"); + for (let i = 0; i < pathParts.length; ++i) { + file.append(pathParts[i]); + } + if (aFilename) { + file.append(aFilename); + } + return file; +} + +function loadHelperScript() { + let scriptFile = getTestDataFile("sharedUpdateXML.js"); + let io = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService2); + let scriptSpec = io.newFileURI(scriptFile).spec; + let scriptloader = Cc["@mozilla.org/moz/jssubscript-loader;1"]. + getService(Ci.mozIJSSubScriptLoader); + scriptloader.loadSubScript(scriptSpec, this); +} +loadHelperScript(); const URL_HOST = "http://example.com"; const URL_PATH_UPDATE_XML = "/chrome/toolkit/mozapps/update/tests/chrome/update.sjs"; const URL_HTTP_UPDATE_SJS = URL_HOST + URL_PATH_UPDATE_XML; -const REL_PATH_DATA = "chrome/toolkit/mozapps/update/tests/data/"; const SERVICE_URL = URL_HOST + "/" + REL_PATH_DATA + FILE_SIMPLE_MAR; const SLOW_MAR_DOWNLOAD_INTERVAL = 100; var gTimer; function handleRequest(aRequest, aResponse) { - var params = { }; - if (aRequest.queryString) + let params = { }; + if (aRequest.queryString) { params = parseQueryString(aRequest.queryString); + } - var statusCode = params.statusCode ? parseInt(params.statusCode) : 200; - var statusReason = params.statusReason ? params.statusReason : "OK"; + let statusCode = params.statusCode ? parseInt(params.statusCode) : 200; + let statusReason = params.statusReason ? params.statusReason : "OK"; aResponse.setStatusLine(aRequest.httpVersion, statusCode, statusReason); aResponse.setHeader("Cache-Control", "no-cache", false); @@ -44,42 +63,25 @@ function handleRequest(aRequest, aResponse) { // mar will be downloaded asynchronously which will allow the ui to load // before the download completes. if (params.slowDownloadMar) { - var i; aResponse.processAsync(); aResponse.setHeader("Content-Type", "binary/octet-stream"); aResponse.setHeader("Content-Length", SIZE_SIMPLE_MAR); - var continueFile = AUS_Cc["@mozilla.org/file/directory_service;1"]. - getService(AUS_Ci.nsIProperties). - get("CurWorkD", AUS_Ci.nsILocalFile); - var continuePath = REL_PATH_DATA + "continue"; - var continuePathParts = continuePath.split("/"); - for (i = 0; i < continuePathParts.length; ++i) { - continueFile.append(continuePathParts[i]); - } - - var marFile = AUS_Cc["@mozilla.org/file/directory_service;1"]. - getService(AUS_Ci.nsIProperties). - get("CurWorkD", AUS_Ci.nsILocalFile); - var path = REL_PATH_DATA + FILE_SIMPLE_MAR; - var pathParts = path.split("/"); - for (i = 0; i < pathParts.length; ++i) { - marFile.append(pathParts[i]); - } - var contents = readFileBytes(marFile); - gTimer = AUS_Cc["@mozilla.org/timer;1"]. - createInstance(AUS_Ci.nsITimer); + var continueFile = getTestDataFile("continue"); + var contents = readFileBytes(getTestDataFile(FILE_SIMPLE_MAR)); + gTimer = Cc["@mozilla.org/timer;1"]. + createInstance(Ci.nsITimer); gTimer.initWithCallback(function(aTimer) { if (continueFile.exists()) { gTimer.cancel(); aResponse.write(contents); aResponse.finish(); } - }, SLOW_MAR_DOWNLOAD_INTERVAL, AUS_Ci.nsITimer.TYPE_REPEATING_SLACK); + }, SLOW_MAR_DOWNLOAD_INTERVAL, Ci.nsITimer.TYPE_REPEATING_SLACK); return; } if (params.uiURL) { - var remoteType = ""; + let remoteType = ""; if (!params.remoteNoTypeAttr && (params.uiURL == "BILLBOARD" || params.uiURL == "LICENSE")) { remoteType = " " + params.uiURL.toLowerCase() + "=\"1\""; @@ -110,8 +112,8 @@ function handleRequest(aRequest, aResponse) { return; } - var hash; - var patches = ""; + let hash; + let patches = ""; if (!params.partialPatchOnly) { hash = SHA512_HASH_SIMPLE_MAR + (params.invalidCompleteHash ? "e" : ""); patches += getRemotePatchString("complete", SERVICE_URL, "SHA512", @@ -124,31 +126,37 @@ function handleRequest(aRequest, aResponse) { hash, SIZE_SIMPLE_MAR); } - var type = params.type ? params.type : "major"; - var name = params.name ? params.name : "App Update Test"; - var appVersion = params.appVersion ? params.appVersion : "99.9"; - var displayVersion = params.displayVersion ? params.displayVersion + let type = params.type ? params.type : "major"; + let name = params.name ? params.name : "App Update Test"; + let appVersion = params.appVersion ? params.appVersion : "99.9"; + let displayVersion = params.displayVersion ? params.displayVersion : "version " + appVersion; - var platformVersion = params.platformVersion ? params.platformVersion : "99.8"; - var buildID = params.buildID ? params.buildID : "01234567890123"; + let platformVersion = params.platformVersion ? params.platformVersion : "99.8"; + let buildID = params.buildID ? params.buildID : "01234567890123"; // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244 -// var detailsURL = params.showDetails ? URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS" : null; - var detailsURL = URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS"; - var billboardURL = params.showBillboard ? URL_HTTP_UPDATE_SJS + "?uiURL=BILLBOARD" : null; - if (billboardURL && params.remoteNoTypeAttr) +// let detailsURL = params.showDetails ? URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS" : null; + let detailsURL = URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS"; + let billboardURL = params.showBillboard ? URL_HTTP_UPDATE_SJS + "?uiURL=BILLBOARD" : null; + if (billboardURL && params.remoteNoTypeAttr) { billboardURL += "&remoteNoTypeAttr=1"; - if (params.billboard404) + } + if (params.billboard404) { billboardURL = URL_HOST + "/missing.html"; - var licenseURL = params.showLicense ? URL_HTTP_UPDATE_SJS + "?uiURL=LICENSE" : null; - if (licenseURL && params.remoteNoTypeAttr) + } + let licenseURL = params.showLicense ? URL_HTTP_UPDATE_SJS + "?uiURL=LICENSE" : null; + if (licenseURL && params.remoteNoTypeAttr) { licenseURL += "&remoteNoTypeAttr=1"; - if (params.license404) + } + if (params.license404) { licenseURL = URL_HOST + "/missing.html"; - var showPrompt = params.showPrompt ? "true" : null; - var showNever = params.showNever ? "true" : null; - var promptWaitTime = params.promptWaitTime ? params.promptWaitTime : null; - var showSurvey = params.showSurvey ? "true" : null; + } + let showPrompt = params.showPrompt ? "true" : null; + let showNever = params.showNever ? "true" : null; + let promptWaitTime = params.promptWaitTime ? params.promptWaitTime : null; + let showSurvey = params.showSurvey ? "true" : null; + let extensionVersion; + let version; // For testing the deprecated update xml format if (params.oldFormat) { appVersion = null; @@ -158,14 +166,15 @@ function handleRequest(aRequest, aResponse) { showNever = null; showSurvey = null; detailsURL = URL_HTTP_UPDATE_SJS + "?uiURL=BILLBOARD"; - if (params.remoteNoTypeAttr) + if (params.remoteNoTypeAttr) { detailsURL += "&remoteNoTypeAttr=1"; - var extensionVersion = params.appVersion ? params.appVersion : "99.9"; - var version = params.displayVersion ? params.displayVersion - : "version " + extensionVersion; + } + extensionVersion = params.appVersion ? params.appVersion : "99.9"; + version = params.displayVersion ? params.displayVersion + : "version " + extensionVersion; } - var updates = getRemoteUpdateString(patches, type, "App Update Test", + let updates = getRemoteUpdateString(patches, type, "App Update Test", displayVersion, appVersion, platformVersion, buildID, detailsURL, billboardURL, licenseURL, showPrompt, @@ -185,13 +194,14 @@ function handleRequest(aRequest, aResponse) { * queryString. */ function parseQueryString(aQueryString) { - var paramArray = aQueryString.split("&"); - var regex = /^([^=]+)=(.*)$/; - var params = {}; - for (var i = 0, sz = paramArray.length; i < sz; i++) { - var match = regex.exec(paramArray[i]); - if (!match) + let paramArray = aQueryString.split("&"); + let regex = /^([^=]+)=(.*)$/; + let params = {}; + for (let i = 0, sz = paramArray.length; i < sz; i++) { + let match = regex.exec(paramArray[i]); + if (!match) { throw "Bad parameter in queryString! '" + paramArray[i] + "'"; + } params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]); } @@ -209,10 +219,10 @@ function parseQueryString(aQueryString) { * manifest file. */ function getUpdateRDF(aParams) { - var addonVersion; - var addonID = aParams.addonID; - var addonUpdateType = addonID.split("_")[0]; - var maxVersion = aParams.platformVersion; + let addonVersion; + let addonID = aParams.addonID; + let addonUpdateType = addonID.split("_")[0]; + let maxVersion = aParams.platformVersion; switch (addonUpdateType) { case "updatecompatibility": @@ -265,20 +275,21 @@ function getUpdateRDF(aParams) { * @return The contents of the file as a string. */ function readFileBytes(aFile) { - var fis = AUS_Cc["@mozilla.org/network/file-input-stream;1"]. - createInstance(AUS_Ci.nsIFileInputStream); + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); fis.init(aFile, -1, -1, false); - var bis = AUS_Cc["@mozilla.org/binaryinputstream;1"]. - createInstance(AUS_Ci.nsIBinaryInputStream); + let bis = Cc["@mozilla.org/binaryinputstream;1"]. + createInstance(Ci.nsIBinaryInputStream); bis.setInputStream(fis); - var data = []; - var count = fis.available(); + let data = []; + let count = fis.available(); while (count > 0) { - var bytes = bis.readByteArray(Math.min(65535, count)); + let bytes = bis.readByteArray(Math.min(65535, count)); data.push(String.fromCharCode.apply(null, bytes)); count -= bytes.length; - if (bytes.length == 0) + if (bytes.length == 0) { throw "Nothing read from input stream!"; + } } data.join(''); fis.close(); diff --git a/toolkit/mozapps/update/tests/chrome/utils.js b/toolkit/mozapps/update/tests/chrome/utils.js index 40a94f6d66..ca3fa544da 100644 --- a/toolkit/mozapps/update/tests/chrome/utils.js +++ b/toolkit/mozapps/update/tests/chrome/utils.js @@ -102,11 +102,17 @@ * updatecompatibility * the add-on is compatible with the current toolkit version and has a * compatibility update to make it compatible with the update's toolkit - * version. + * version. Tests that need to have add-ons compatible for the application + * update without updating the add-on's compatibility information can disable + * this add-on by setting the gDisableUpdateCompatibilityAddon variable to + * true. * * updateversion * the add-on is compatible with the current toolkit version and has a version - * update to make it compatible with the update's toolkit version. + * update to make it compatible with the update's toolkit version. Tests that + * need to have add-ons compatible for the application update without updating + * the add-on's to a new version that is compatible can disable this add-on by + * setting the gDisableUpdateVersionAddon variable to true. * * userdisabled * disabled by the user and compatible with the current toolkit version but @@ -116,7 +122,13 @@ 'use strict'; -Components.utils.import("resource://gre/modules/AddonManager.jsm"); +const { classes: Cc, interfaces: Ci, manager: Cm, results: Cr, + utils: Cu } = Components; + +Cu.import("resource://gre/modules/AddonManager.jsm", this); +Cu.import("resource://gre/modules/Services.jsm", this); + +const IS_MACOSX = ("nsILocalFileMac" in Ci); // The tests have to use the pageid instead of the pageIndex due to the // app update wizard's access method being random. @@ -145,6 +157,8 @@ const URL_HOST = "http://example.com"; const URL_PATH_UPDATE_XML = "/chrome/toolkit/mozapps/update/tests/chrome/update.sjs"; const REL_PATH_DATA = "chrome/toolkit/mozapps/update/tests/data"; +// These two URLs must not contain parameters since tests add their own +// test specific parameters. const URL_HTTP_UPDATE_XML = URL_HOST + URL_PATH_UPDATE_XML; const URL_HTTPS_UPDATE_XML = "https://example.com" + URL_PATH_UPDATE_XML; @@ -194,13 +208,16 @@ var gWin; var gDocElem; var gPrefToCheck; var gDisableNoUpdateAddon = false; +var gDisableUpdateCompatibilityAddon = false; +var gDisableUpdateVersionAddon = false; // Set to true to log additional information for debugging. To log additional // information for an individual test set DEBUG_AUS_TEST to true in the test's // onload function. var DEBUG_AUS_TEST = true; -#include ../shared.js +const DATA_URI_SPEC = "chrome://mochitests/content/chrome/toolkit/mozapps/update/tests/data/"; +Services.scriptloader.loadSubScript(DATA_URI_SPEC + "shared.js", this); /** * The current test in TESTS array. @@ -267,7 +284,7 @@ this.__defineGetter__("gIncompatibleListbox", function() { function runTestDefault() { debugDump("entering"); - if (!("@mozilla.org/zipwriter;1" in AUS_Cc)) { + if (!("@mozilla.org/zipwriter;1" in Cc)) { ok(false, "nsIZipWriter is required to run these tests"); return; } @@ -300,8 +317,7 @@ function runTestDefaultWaitForWindowClosed() { // |closeUpdateWindow| will close it and cause the test to fail. if (closeUpdateWindow()) { SimpleTest.executeSoon(runTestDefaultWaitForWindowClosed); - } - else { + } else { Services.ww.registerNotification(gWindowObserver); gCloseWindowTimeoutCounter = 0; @@ -386,8 +402,7 @@ function finishTestDefaultWaitForWindowClosed() { // |closeUpdateWindow| will close it and cause the test to fail. if (closeUpdateWindow()) { SimpleTest.executeSoon(finishTestDefaultWaitForWindowClosed); - } - else { + } else { SimpleTest.finish(); } } @@ -493,8 +508,7 @@ function delayedDefaultCallback() { throw("Tests cannot have a buttonClick and an extraDelayedFinishFunction property"); } gDocElem.getButton(gTest.buttonClick).click(); - } - else if (gTest.extraDelayedFinishFunction) { + } else if (gTest.extraDelayedFinishFunction) { debugDump("calling extraDelayedFinishFunction " + gTest.extraDelayedFinishFunction.name); gTest.extraDelayedFinishFunction(); @@ -508,9 +522,9 @@ function delayedDefaultCallback() { * @return nsILocalFile for the continue file. */ function getContinueFile() { - let continueFile = AUS_Cc["@mozilla.org/file/directory_service;1"]. - getService(AUS_Ci.nsIProperties). - get("CurWorkD", AUS_Ci.nsILocalFile); + let continueFile = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties). + get("CurWorkD", Ci.nsILocalFile); let continuePath = REL_PATH_DATA + "/continue"; let continuePathParts = continuePath.split("/"); for (let i = 0; i < continuePathParts.length; ++i) { @@ -938,12 +952,13 @@ function resetFiles() { // Not being able to remove the "updated" directory will not adversely affect // subsequent tests so wrap it in a try block and don't test whether its // removal was successful. -#ifdef XP_MACOSX - let updatedDir = getUpdatesDir(); - updatedDir.append(DIR_PATCH); -#else - let updatedDir = getAppBaseDir(); -#endif + let updatedDir; + if (IS_MACOSX) { + updatedDir = getUpdatesDir(); + updatedDir.append(DIR_PATCH); + } else { + updatedDir = getAppBaseDir(); + } updatedDir.append(DIR_UPDATED); if (updatedDir.exists()) { try { @@ -962,8 +977,7 @@ function resetFiles() { function resetPrefs() { if (gAppUpdateURL !== undefined) { Services.prefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, gAppUpdateURL); - } - else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_OVERRIDE)) { + } else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_OVERRIDE)) { Services.prefs.clearUserPref(PREF_APP_UPDATE_URL_OVERRIDE); } @@ -973,29 +987,25 @@ function resetPrefs() { if (gAppUpdateEnabled !== undefined) { Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, gAppUpdateEnabled); - } - else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ENABLED)) { + } else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ENABLED)) { Services.prefs.clearUserPref(PREF_APP_UPDATE_ENABLED); } if (gAppUpdateServiceEnabled !== undefined) { Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, gAppUpdateServiceEnabled); - } - else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SERVICE_ENABLED)) { + } else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SERVICE_ENABLED)) { Services.prefs.clearUserPref(PREF_APP_UPDATE_SERVICE_ENABLED); } if (gAppUpdateStagingEnabled !== undefined) { Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, gAppUpdateStagingEnabled); - } - else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_STAGING_ENABLED)) { + } else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_STAGING_ENABLED)) { Services.prefs.clearUserPref(PREF_APP_UPDATE_STAGING_ENABLED); } if (gExtUpdateURL !== undefined) { Services.prefs.setCharPref(PREF_EXTENSIONS_UPDATE_URL, gExtUpdateURL); - } - else if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_UPDATE_URL)) { + } else if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_UPDATE_URL)) { Services.prefs.clearUserPref(PREF_EXTENSIONS_UPDATE_URL); } @@ -1081,10 +1091,10 @@ function setupTimer(aTestTimeout) { gTimeoutTimer.cancel(); gTimeoutTimer = null; } - gTimeoutTimer = AUS_Cc["@mozilla.org/timer;1"]. - createInstance(AUS_Ci.nsITimer); + gTimeoutTimer = Cc["@mozilla.org/timer;1"]. + createInstance(Ci.nsITimer); gTimeoutTimer.initWithCallback(finishTestTimeout, gTestTimeout, - AUS_Ci.nsITimer.TYPE_ONE_SHOT); + Ci.nsITimer.TYPE_ONE_SHOT); } /** @@ -1106,17 +1116,26 @@ function setupAddons(aCallback) { function setNoUpdateAddonsDisabledState() { AddonManager.getAllAddons(function(aAddons) { aAddons.forEach(function(aAddon) { - if (aAddon.name.indexOf("noupdate") != 0) - return; - - if (gDisableNoUpdateAddon) { if (!aAddon.userDisabled) { aAddon.userDisabled = true; } } - else { - if (aAddon.userDisabled) { - aAddon.userDisabled = false; + + if (aAddon.name.startsWith("noupdate")) { + if (aAddon.userDisabled != gDisableNoUpdateAddon) { + aAddon.userDisabled = gDisableNoUpdateAddon; + } + } + + if (aAddon.name.startsWith("updatecompatibility")) { + if (aAddon.userDisabled != gDisableUpdateCompatibilityAddon) { + aAddon.userDisabled = gDisableUpdateCompatibilityAddon; + } + } + + if (aAddon.name.startsWith("updateversion")) { + if (aAddon.userDisabled != gDisableUpdateVersionAddon) { + aAddon.userDisabled = gDisableUpdateVersionAddon; } } }); @@ -1273,7 +1292,7 @@ function getAddonTestType(aName) { */ function getTestAddonXPIFiles() { let addonPrepDir = Services.dirsvc.get(NS_APP_USER_PROFILE_50_DIR, - AUS_Ci.nsILocalFile); + Ci.nsILocalFile); addonPrepDir.append(ADDON_PREP_DIR); let bootstrap = addonPrepDir.clone(); @@ -1295,15 +1314,16 @@ function getTestAddonXPIFiles() { let xpiFile = addonPrepDir.clone(); xpiFile.append(aName + ".xpi"); - if (installRDF.exists()) + if (installRDF.exists()) { installRDF.remove(false); + } writeFile(installRDF, getInstallRDFString(aName)); gZipW.open(xpiFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); gZipW.addEntryFile(installRDF.leafName, - AUS_Ci.nsIZipWriter.COMPRESSION_DEFAULT, installRDF, + Ci.nsIZipWriter.COMPRESSION_DEFAULT, installRDF, false); gZipW.addEntryFile(bootstrap.leafName, - AUS_Ci.nsIZipWriter.COMPRESSION_DEFAULT, bootstrap, + Ci.nsIZipWriter.COMPRESSION_DEFAULT, bootstrap, false); gZipW.close(); xpiFiles.push(xpiFile); @@ -1361,8 +1381,9 @@ function getInstallRDFString(aName) { */ function closeUpdateWindow() { let updateWindow = getUpdateWindow(); - if (!updateWindow) + if (!updateWindow) { return false; + } ok(false, "Found an existing Update Window from the current or a previous " + "test... attempting to close it."); @@ -1383,7 +1404,7 @@ function getUpdateWindow() { /** * Helper for background check errors. */ -var errorsPrefObserver = { +const errorsPrefObserver = { observedPref: null, maxErrorPref: null, @@ -1417,8 +1438,7 @@ var errorsPrefObserver = { if (errCount >= errMax) { debugDump("removing pref observer"); Services.prefs.removeObserver(this.observedPref, this); - } - else { + } else { debugDump("notifying AUS"); SimpleTest.executeSoon(function() { gAUS.notify(null); @@ -1431,9 +1451,9 @@ var errorsPrefObserver = { /** * nsIObserver for receiving window open and close notifications. */ -var gWindowObserver = { +const gWindowObserver = { observe: function WO_observe(aSubject, aTopic, aData) { - let win = aSubject.QueryInterface(AUS_Ci.nsIDOMEventTarget); + let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget); if (aTopic == "domwindowclosed") { if (win.location != URI_UPDATE_PROMPT_DIALOG) { diff --git a/toolkit/mozapps/update/tests/data/partial_log_failure b/toolkit/mozapps/update/tests/data/partial_log_failure index 8cea74a757..729da410eb 100644 --- a/toolkit/mozapps/update/tests/data/partial_log_failure +++ b/toolkit/mozapps/update/tests/data/partial_log_failure @@ -182,5 +182,5 @@ FINISH REMOVEFILE 3/3text1 backup_restore: backup file doesn't exist: 3/3text1.moz-backup FINISH REMOVEFILE 3/3text0 backup_restore: backup file doesn't exist: 3/3text0.moz-backup -failed: 42 +failed: 2 calling QuitProgressUI diff --git a/toolkit/mozapps/update/tests/data/partial_log_failure_mac b/toolkit/mozapps/update/tests/data/partial_log_failure_mac index e76115144a..8b0db834cf 100644 --- a/toolkit/mozapps/update/tests/data/partial_log_failure_mac +++ b/toolkit/mozapps/update/tests/data/partial_log_failure_mac @@ -182,5 +182,5 @@ FINISH REMOVEFILE Contents/Resources/3/3text1 backup_restore: backup file doesn't exist: Contents/Resources/3/3text1.moz-backup FINISH REMOVEFILE Contents/Resources/3/3text0 backup_restore: backup file doesn't exist: Contents/Resources/3/3text0.moz-backup -failed: 42 +failed: 2 calling QuitProgressUI diff --git a/toolkit/mozapps/update/tests/shared.js b/toolkit/mozapps/update/tests/data/shared.js similarity index 84% rename from toolkit/mozapps/update/tests/shared.js rename to toolkit/mozapps/update/tests/data/shared.js index 86aa7e91c5..3669f71ed0 100644 --- a/toolkit/mozapps/update/tests/shared.js +++ b/toolkit/mozapps/update/tests/data/shared.js @@ -4,13 +4,8 @@ /* Shared code for xpcshell and mochitests-chrome */ -// const Cc, Ci, and Cr are defined in netwerk/test/httpserver/httpd.js so we -// need to define unique ones. -const AUS_Cc = Components.classes; -const AUS_Ci = Components.interfaces; -const AUS_Cr = Components.results; -const AUS_Cu = Components.utils; -const AUS_Cm = Components.manager; +Cu.import("resource://gre/modules/FileUtils.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); const PREF_APP_UPDATE_AUTO = "app.update.auto"; const PREF_APP_UPDATE_BACKGROUNDERRORS = "app.update.backgroundErrors"; @@ -61,11 +56,7 @@ const WRITE_ERROR = 7; const DIR_PATCH = "0"; const DIR_TOBEDELETED = "tobedeleted"; const DIR_UPDATES = "updates"; -#ifdef XP_MACOSX -const DIR_UPDATED = "Updated.app"; -#else -const DIR_UPDATED = "updated"; -#endif +const DIR_UPDATED = IS_MACOSX ? "Updated.app" : "updated"; const FILE_APPLICATION_INI = "application.ini"; const FILE_BACKUP_LOG = "backup-update.log"; @@ -95,11 +86,7 @@ const DEFAULT_UPDATE_VERSION = "999999.0"; var gChannel; -#include sharedUpdateXML.js - -AUS_Cu.import("resource://gre/modules/FileUtils.jsm"); -AUS_Cu.import("resource://gre/modules/Services.jsm"); -AUS_Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Services.scriptloader.loadSubScript(DATA_URI_SPEC + "sharedUpdateXML.js", this); const PERMS_FILE = FileUtils.PERMS_FILE; const PERMS_DIRECTORY = FileUtils.PERMS_DIRECTORY; @@ -115,11 +102,11 @@ const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.propertie const gUpdateBundle = Services.strings.createBundle(URI_UPDATES_PROPERTIES); XPCOMUtils.defineLazyGetter(this, "gAUS", function test_gAUS() { - return AUS_Cc["@mozilla.org/updates/update-service;1"]. - getService(AUS_Ci.nsIApplicationUpdateService). - QueryInterface(AUS_Ci.nsITimerCallback). - QueryInterface(AUS_Ci.nsIObserver). - QueryInterface(AUS_Ci.nsIUpdateCheckListener); + return Cc["@mozilla.org/updates/update-service;1"]. + getService(Ci.nsIApplicationUpdateService). + QueryInterface(Ci.nsITimerCallback). + QueryInterface(Ci.nsIObserver). + QueryInterface(Ci.nsIUpdateCheckListener); }); XPCOMUtils.defineLazyServiceGetter(this, "gUpdateManager", @@ -127,13 +114,13 @@ XPCOMUtils.defineLazyServiceGetter(this, "gUpdateManager", "nsIUpdateManager"); XPCOMUtils.defineLazyGetter(this, "gUpdateChecker", function test_gUC() { - return AUS_Cc["@mozilla.org/updates/update-checker;1"]. - createInstance(AUS_Ci.nsIUpdateChecker); + return Cc["@mozilla.org/updates/update-checker;1"]. + createInstance(Ci.nsIUpdateChecker); }); XPCOMUtils.defineLazyGetter(this, "gUP", function test_gUP() { - return AUS_Cc["@mozilla.org/updates/update-prompt;1"]. - createInstance(AUS_Ci.nsIUpdatePrompt); + return Cc["@mozilla.org/updates/update-prompt;1"]. + createInstance(Ci.nsIUpdatePrompt); }); XPCOMUtils.defineLazyGetter(this, "gDefaultPrefBranch", function test_gDPB() { @@ -145,19 +132,19 @@ XPCOMUtils.defineLazyGetter(this, "gPrefRoot", function test_gPR() { }); XPCOMUtils.defineLazyGetter(this, "gZipW", function test_gZipW() { - return AUS_Cc["@mozilla.org/zipwriter;1"]. - createInstance(AUS_Ci.nsIZipWriter); + return Cc["@mozilla.org/zipwriter;1"]. + createInstance(Ci.nsIZipWriter); }); /* Initializes the update service stub */ function initUpdateServiceStub() { - AUS_Cc["@mozilla.org/updates/update-service-stub;1"]. - createInstance(AUS_Ci.nsISupports); + Cc["@mozilla.org/updates/update-service-stub;1"]. + createInstance(Ci.nsISupports); } /* Reloads the update metadata from disk */ function reloadUpdateManagerData() { - gUpdateManager.QueryInterface(AUS_Ci.nsIObserver). + gUpdateManager.QueryInterface(Ci.nsIObserver). observe(null, "um-reload-update-data", ""); } @@ -174,17 +161,17 @@ function setUpdateChannel(aChannel) { gPrefRoot.addObserver(PREF_APP_UPDATE_CHANNEL, observer, false); } -var observer = { +const observer = { observe: function(aSubject, aTopic, aData) { if (aTopic == "nsPref:changed" && aData == PREF_APP_UPDATE_CHANNEL) { - var channel = gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); + let channel = gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); if (channel != gChannel) { debugDump("Changing channel from " + channel + " to " + gChannel); gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, gChannel); } } }, - QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver]) + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) }; /** @@ -208,7 +195,7 @@ function setUpdateURLOverride(aURL) { * return the updates.xml file. */ function getUpdatesXMLFile(aIsActiveUpdate) { - var file = getUpdatesRootDir(); + let file = getUpdatesRootDir(); file.append(aIsActiveUpdate ? FILE_UPDATE_ACTIVE : FILE_UPDATES_DB); return file; } @@ -260,7 +247,7 @@ function writeVersionFile(aVersion) { * @return nsIFile for the updates root directory. */ function getUpdatesRootDir() { - return Services.dirsvc.get(XRE_UPDATE_ROOT_DIR, AUS_Ci.nsIFile); + return Services.dirsvc.get(XRE_UPDATE_ROOT_DIR, Ci.nsIFile); } /** @@ -269,7 +256,7 @@ function getUpdatesRootDir() { * @return nsIFile for the updates directory. */ function getUpdatesDir() { - var dir = getUpdatesRootDir(); + let dir = getUpdatesRootDir(); dir.append(DIR_UPDATES); return dir; } @@ -296,10 +283,11 @@ function getUpdatesPatchDir() { * replaced. */ function writeFile(aFile, aText) { - var fos = AUS_Cc["@mozilla.org/network/file-output-stream;1"]. - createInstance(AUS_Ci.nsIFileOutputStream); - if (!aFile.exists()) - aFile.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); + let fos = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + if (!aFile.exists()) { + aFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); + } fos.init(aFile, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0); fos.write(aText, aText.length); fos.close(); @@ -351,15 +339,16 @@ function readStatusFailedCode() { * @return The string of text read from the file. */ function readFile(aFile) { - var fis = AUS_Cc["@mozilla.org/network/file-input-stream;1"]. - createInstance(AUS_Ci.nsIFileInputStream); - if (!aFile.exists()) + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + if (!aFile.exists()) { return null; + } fis.init(aFile, MODE_RDONLY, PERMS_FILE, 0); - var sis = AUS_Cc["@mozilla.org/scriptableinputstream;1"]. - createInstance(AUS_Ci.nsIScriptableInputStream); + let sis = Cc["@mozilla.org/scriptableinputstream;1"]. + createInstance(Ci.nsIScriptableInputStream); sis.init(fis); - var text = sis.read(sis.available()); + let text = sis.read(sis.available()); sis.close(); return text; } @@ -372,20 +361,21 @@ function readFile(aFile) { * @return The contents of the file as a string. */ function readFileBytes(aFile) { - var fis = AUS_Cc["@mozilla.org/network/file-input-stream;1"]. - createInstance(AUS_Ci.nsIFileInputStream); + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); fis.init(aFile, -1, -1, false); - var bis = AUS_Cc["@mozilla.org/binaryinputstream;1"]. - createInstance(AUS_Ci.nsIBinaryInputStream); + let bis = Cc["@mozilla.org/binaryinputstream;1"]. + createInstance(Ci.nsIBinaryInputStream); bis.setInputStream(fis); - var data = []; - var count = fis.available(); + let data = []; + let count = fis.available(); while (count > 0) { - var bytes = bis.readByteArray(Math.min(65535, count)); + let bytes = bis.readByteArray(Math.min(65535, count)); data.push(String.fromCharCode.apply(null, bytes)); count -= bytes.length; - if (bytes.length == 0) + if (bytes.length == 0) { throw "Nothing read from input stream!"; + } } data.join(''); fis.close(); @@ -414,7 +404,7 @@ function getString(aName) { * @return The file extension. */ function getFileExtension(aFile) { - return Services.io.newFileURI(aFile).QueryInterface(AUS_Ci.nsIURL). + return Services.io.newFileURI(aFile).QueryInterface(Ci.nsIURL). fileExtension; } @@ -425,10 +415,11 @@ function getFileExtension(aFile) { * tests are interrupted. */ function removeUpdateDirsAndFiles() { - var file = getUpdatesXMLFile(true); + let file = getUpdatesXMLFile(true); try { - if (file.exists()) + if (file.exists()) { file.remove(false); + } } catch (e) { logTestInfo("Unable to remove file. Path: " + file.path + ", Exception: " + e); @@ -436,15 +427,16 @@ function removeUpdateDirsAndFiles() { file = getUpdatesXMLFile(false); try { - if (file.exists()) + if (file.exists()) { file.remove(false); + } } catch (e) { logTestInfo("Unable to remove file. Path: " + file.path + ", Exception: " + e); } // This fails sporadically on Mac OS X so wrap it in a try catch - var updatesDir = getUpdatesDir(); + let updatesDir = getUpdatesDir(); try { cleanUpdatesDir(updatesDir); } catch (e) { @@ -461,12 +453,13 @@ function removeUpdateDirsAndFiles() { * nsIFile for the directory to be deleted. */ function cleanUpdatesDir(aDir) { - if (!aDir.exists()) + if (!aDir.exists()) { return; + } - var dirEntries = aDir.directoryEntries; + let dirEntries = aDir.directoryEntries; while (dirEntries.hasMoreElements()) { - var entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile); + let entry = dirEntries.getNext().QueryInterface(Ci.nsIFile); if (entry.isDirectory()) { if (entry.leafName == DIR_PATCH && entry.parent.leafName == DIR_UPDATES) { @@ -522,9 +515,9 @@ function removeDirRecursive(aDir) { logTestInfo("non-fatal error removing directory. Exception: " + e); } - var dirEntries = aDir.directoryEntries; + let dirEntries = aDir.directoryEntries; while (dirEntries.hasMoreElements()) { - var entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile); + let entry = dirEntries.getNext().QueryInterface(Ci.nsIFile); if (entry.isDirectory()) { removeDirRecursive(entry); @@ -558,7 +551,7 @@ function removeDirRecursive(aDir) { * @return nsIFile for the current process directory. */ function getCurrentProcessDir() { - return Services.dirsvc.get(NS_XPCOM_CURRENT_PROCESS_DIR, AUS_Ci.nsIFile); + return Services.dirsvc.get(NS_XPCOM_CURRENT_PROCESS_DIR, Ci.nsIFile); } /** @@ -567,7 +560,7 @@ function getCurrentProcessDir() { * @return nsIFile object for the application base directory. */ function getAppBaseDir() { - return Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsIFile).parent; + return Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile).parent; } /** @@ -578,7 +571,7 @@ function getAppBaseDir() { * @return nsIFile for the Goanna Runtime Engine directory. */ function getGREDir() { - return Services.dirsvc.get(NS_GRE_DIR, AUS_Ci.nsIFile); + return Services.dirsvc.get(NS_GRE_DIR, Ci.nsIFile); } /** @@ -591,7 +584,7 @@ function getGREDir() { * @return nsIFile for the Goanna Runtime Engine Binary directory. */ function getGREBinDir() { - return Services.dirsvc.get(NS_GRE_BIN_DIR, AUS_Ci.nsIFile); + return Services.dirsvc.get(NS_GRE_BIN_DIR, Ci.nsIFile); } /** diff --git a/toolkit/mozapps/update/tests/sharedUpdateXML.js b/toolkit/mozapps/update/tests/data/sharedUpdateXML.js similarity index 97% rename from toolkit/mozapps/update/tests/sharedUpdateXML.js rename to toolkit/mozapps/update/tests/data/sharedUpdateXML.js index ad8aa16462..d930e84943 100644 --- a/toolkit/mozapps/update/tests/sharedUpdateXML.js +++ b/toolkit/mozapps/update/tests/data/sharedUpdateXML.js @@ -35,11 +35,12 @@ const STATE_SUCCEEDED = "succeeded"; const STATE_DOWNLOAD_FAILED = "download-failed"; const STATE_FAILED = "failed"; -const STATE_FAILED_READ_ERROR = STATE_FAILED + ": 6"; -const STATE_FAILED_WRITE_ERROR = STATE_FAILED + ": 7"; -const STATE_FAILED_CHANNEL_MISMATCH_ERROR = STATE_FAILED + ": 22"; -const STATE_FAILED_VERSION_DOWNGRADE_ERROR = STATE_FAILED + ": 23"; -const STATE_FAILED_UNEXPECTED_FILE_OPERATION_ERROR = STATE_FAILED + ": 42"; +const STATE_FAILED_LOADSOURCE_ERROR_WRONG_SIZE = STATE_FAILED + ": 2"; +const STATE_FAILED_READ_ERROR = STATE_FAILED + ": 6"; +const STATE_FAILED_WRITE_ERROR = STATE_FAILED + ": 7"; +const STATE_FAILED_CHANNEL_MISMATCH_ERROR = STATE_FAILED + ": 22"; +const STATE_FAILED_VERSION_DOWNGRADE_ERROR = STATE_FAILED + ": 23"; +const STATE_FAILED_WRITE_ERROR_FILE_COPY = STATE_FAILED + ": 61"; /** * Constructs a string representing a remote update xml file. @@ -97,8 +98,9 @@ function getRemotePatchString(aType, aURL, aHashFunction, aHashValue, aSize) { * @return The string representing a local update xml file. */ function getLocalUpdatesXMLString(aUpdates) { - if (!aUpdates || aUpdates == "") + if (!aUpdates || aUpdates == "") { return "" + } return ("" + aUpdates + "").replace(/>\s+\n*<'); diff --git a/toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js b/toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js new file mode 100644 index 0000000000..4e54e4066e --- /dev/null +++ b/toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js @@ -0,0 +1,65 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Preprocessed constants used by xpcshell tests */ + +const INSTALL_LOCALE = "@AB_CD@"; +const MOZ_APP_NAME = "@MOZ_APP_NAME@"; +const BIN_SUFFIX = "@BIN_SUFFIX@"; + +// MOZ_APP_VENDOR is optional. +#ifdef MOZ_APP_VENDOR +const MOZ_APP_VENDOR = "@MOZ_APP_VENDOR@"; +#else +const MOZ_APP_VENDOR = ""; +#endif + +// MOZ_APP_BASENAME is not optional for tests. +const MOZ_APP_BASENAME = "@MOZ_APP_BASENAME@"; +const APP_BIN_SUFFIX = "@BIN_SUFFIX@"; + +const APP_INFO_NAME = "XPCShell"; +const APP_INFO_VENDOR = "Mozilla"; + +#ifdef XP_WIN +const IS_WIN = true; +#else +const IS_WIN = false; +#endif + +#ifdef XP_MACOSX +const IS_MACOSX = true; +#else +const IS_MACOSX = false; +#endif + +#ifdef XP_UNIX +const IS_UNIX = true; +#else +const IS_UNIX = false; +#endif + +#ifdef ANDROID +const IS_ANDROID = true; +#else +const IS_ANDROID = false; +#endif + +#ifdef MOZ_WIDGET_GONK +const IS_TOOLKIT_GONK = true; +#else +const IS_TOOLKIT_GONK = false; +#endif + +#ifdef MOZ_VERIFY_MAR_SIGNATURE +const IS_MAR_CHECKS_ENABLED = true; +#else +const IS_MAR_CHECKS_ENABLED = false; +#endif + +#ifdef DISABLE_UPDATER_AUTHENTICODE_CHECK + const IS_AUTHENTICODE_CHECK_ENABLED = false; +#else + const IS_AUTHENTICODE_CHECK_ENABLED = true; +#endif diff --git a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js new file mode 100644 index 0000000000..84a4a40921 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js @@ -0,0 +1,3710 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +const { classes: Cc, interfaces: Ci, manager: Cm, results: Cr, + utils: Cu } = Components; + +load("../data/xpcshellConstantsPP.js"); + +Cu.import("resource://gre/modules/Services.jsm", this); +Cu.import("resource://gre/modules/ctypes.jsm", this); + +const DIR_MACOS = IS_MACOSX ? "Contents/MacOS/" : ""; +const DIR_RESOURCES = IS_MACOSX ? "Contents/Resources/" : ""; +const TEST_FILE_SUFFIX = IS_MACOSX ? "_mac" : ""; +const FILE_COMPLETE_MAR = "complete" + TEST_FILE_SUFFIX + ".mar"; +const FILE_PARTIAL_MAR = "partial" + TEST_FILE_SUFFIX + ".mar"; +const LOG_COMPLETE_SUCCESS = "complete_log_success" + TEST_FILE_SUFFIX; +const LOG_PARTIAL_SUCCESS = "partial_log_success" + TEST_FILE_SUFFIX; +const LOG_PARTIAL_FAILURE = "partial_log_failure" + TEST_FILE_SUFFIX; +const FILE_COMPLETE_PRECOMPLETE = "complete_precomplete" + TEST_FILE_SUFFIX; +const FILE_PARTIAL_PRECOMPLETE = "partial_precomplete" + TEST_FILE_SUFFIX; +const FILE_COMPLETE_REMOVEDFILES = "complete_removed-files" + TEST_FILE_SUFFIX; +const FILE_PARTIAL_REMOVEDFILES = "partial_removed-files" + TEST_FILE_SUFFIX; + +const USE_EXECV = IS_UNIX && !IS_MACOSX; + +const URL_HOST = "http://localhost"; + +const FILE_APP_BIN = MOZ_APP_NAME + APP_BIN_SUFFIX; +const FILE_COMPLETE_EXE = "complete.exe"; +const FILE_HELPER_BIN = "TestAUSHelper" + BIN_SUFFIX; +const FILE_MAINTENANCE_SERVICE_BIN = "maintenanceservice.exe"; +const FILE_MAINTENANCE_SERVICE_INSTALLER_BIN = "maintenanceservice_installer.exe"; +const FILE_OLD_VERSION_MAR = "old_version.mar"; +const FILE_PARTIAL_EXE = "partial.exe"; +const FILE_UPDATER_BIN = "updater" + BIN_SUFFIX; +const FILE_WRONG_CHANNEL_MAR = "wrong_product_channel.mar"; + +const LOG_SWITCH_SUCCESS = "rename_file: proceeding to rename the directory\n" + + "rename_file: proceeding to rename the directory\n" + + "Now, remove the tmpDir\n" + + "succeeded\n" + + "calling QuitProgressUI"; + +const ERR_RENAME_FILE = "rename_file: failed to rename file"; +const ERR_UNABLE_OPEN_DEST = "unable to open destination file"; +const ERR_BACKUP_DISCARD = "backup_discard: unable to remove"; + +const LOG_SVC_SUCCESSFUL_LAUNCH = "Process was started... waiting on result."; + +// All we care about is that the last modified time has changed so that Mac OS +// X Launch Services invalidates its cache so the test allows up to one minute +// difference in the last modified time. +const MAC_MAX_TIME_DIFFERENCE = 60000; + +// Time to wait for the test helper process before continuing the test +const TEST_HELPER_TIMEOUT = 100; + +// Time to wait for a check in the test before continuing the test +const TEST_CHECK_TIMEOUT = 100; + +// How many of TEST_CHECK_TIMEOUT to wait before we abort the test. +const MAX_TIMEOUT_RUNS = 2000; + +// Time in seconds the helper application should sleep.the helper's input and output files +const HELPER_SLEEP_TIMEOUT = 180; + +// Maximum number of milliseconds the process that is launched can run before +// the test will try to kill it. +const APP_TIMER_TIMEOUT = 120000; + +const PIPE_TO_NULL = IS_WIN ? ">nul" : "> /dev/null 2>&1"; + +const LOG_FUNCTION = do_print; + +// This default value will be overridden when using the http server. +var gURLData = URL_HOST + "/"; + +var gTestID; + +var gTestserver; + +var gRegisteredServiceCleanup; + +var gXHR; +var gXHRCallback; + +var gUpdatePrompt; +var gUpdatePromptCallback; + +var gCheckFunc; +var gResponseBody; +var gResponseStatusCode = 200; +var gRequestURL; +var gUpdateCount; +var gUpdates; +var gStatusCode; +var gStatusText; +var gStatusResult; + +var gProcess; +var gAppTimer; +var gHandle; + +var gGREDirOrig; +var gGREBinDirOrig; +var gAppDirOrig; + +var gServiceLaunchedCallbackLog = null; +var gServiceLaunchedCallbackArgs = null; + +// Variables are used instead of contants so tests can override these values if +// necessary. +var gCallbackBinFile = "callback_app" + BIN_SUFFIX; +var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"]; +var gPostUpdateBinFile = "postup_app" + BIN_SUFFIX; +var gStageUpdate = false; +var gSwitchApp = false; +var gDisableReplaceFallback = false; +var gUseTestAppDir = true; + +var gTimeoutRuns = 0; + +// Environment related globals +var gShouldResetEnv = undefined; +var gAddedEnvXRENoWindowsCrashDialog = false; +var gEnvXPCOMDebugBreak; +var gEnvXPCOMMemLeakLog; +var gEnvDyldLibraryPath; +var gEnvLdLibraryPath; + +// Set to true to log additional information for debugging. To log additional +// information for an individual test set DEBUG_AUS_TEST to true in the test's +// run_test function. +var DEBUG_AUS_TEST = true; +// Never set DEBUG_TEST_LOG to true except when running tests locally or on the +// try server since this will force a test that failed a parallel run to fail +// when the same test runs non-parallel so the log from parallel test run can +// be displayed in the log. +var DEBUG_TEST_LOG = false; +// Set to false to keep the log file from the failed parallel test run. +var gDeleteLogFile = true; +var gRealDump; +var gTestLogText = ""; +var gPassed; + +const DATA_URI_SPEC = Services.io.newFileURI(do_get_file("../data", false)).spec; +Services.scriptloader.loadSubScript(DATA_URI_SPEC + "shared.js", this); + +var gTestFiles = []; +var gTestDirs = []; + +// Common files for both successful and failed updates. +var gTestFilesCommon = [ +{ + description : "Should never change", + fileName : FILE_UPDATE_SETTINGS_INI, + relPathDir : DIR_RESOURCES, + originalContents : UPDATE_SETTINGS_CONTENTS, + compareContents : UPDATE_SETTINGS_CONTENTS, + originalFile : null, + compareFile : null, + originalPerms : 0o767, + comparePerms : 0o767 +}, { + description : "Should never change", + fileName : "channel-prefs.js", + relPathDir : DIR_RESOURCES + "defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null, + originalPerms : 0o767, + comparePerms : 0o767 +}]; + +// Files for a complete successful update. This can be used for a complete +// failed update by calling setTestFilesAndDirsForFailure. +var gTestFilesCompleteSuccess = [ +{ + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : DIR_RESOURCES, + originalContents : null, + compareContents : null, + originalFile : FILE_PARTIAL_PRECOMPLETE, + compareFile : FILE_COMPLETE_PRECOMPLETE, + originalPerms : 0o666, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : DIR_RESOURCES + "searchplugins/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0o775, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng1.png", + relPathDir : DIR_RESOURCES + "searchplugins/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "complete.png", + originalPerms : null, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng0.png", + relPathDir : DIR_RESOURCES + "searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "partial.png", + compareFile : "complete.png", + originalPerms : 0o666, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "removed-files", + relPathDir : DIR_RESOURCES, + originalContents : null, + compareContents : null, + originalFile : FILE_PARTIAL_REMOVEDFILES, + compareFile : FILE_COMPLETE_REMOVEDFILES, + originalPerms : 0o666, + comparePerms : 0o644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents : null, + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0o644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png1.png", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "partial.png", + compareFile : "complete.png", + originalPerms : 0o666, + comparePerms : 0o644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png0.png", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "complete.png", + originalPerms : null, + comparePerms : 0o644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0o644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png1.png", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "complete.png", + originalPerms : null, + comparePerms : 0o644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png0.png", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "complete.png", + originalPerms : null, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "exe0.exe", + relPathDir : DIR_MACOS, + originalContents : null, + compareContents : null, + originalFile : FILE_HELPER_BIN, + compareFile : FILE_COMPLETE_EXE, + originalPerms : 0o777, + comparePerms : 0o755 +}, { + description : "Added by update.manifest (add)", + fileName : "10text0", + relPathDir : DIR_RESOURCES + "1/10/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0o767, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "0exe0.exe", + relPathDir : DIR_RESOURCES + "0/", + originalContents : null, + compareContents : null, + originalFile : FILE_HELPER_BIN, + compareFile : FILE_COMPLETE_EXE, + originalPerms : 0o777, + comparePerms : 0o755 +}, { + description : "Added by update.manifest (add)", + fileName : "00text1", + relPathDir : DIR_RESOURCES + "0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0o677, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : DIR_RESOURCES + "0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0o775, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "00png0.png", + relPathDir : DIR_RESOURCES + "0/00/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "complete.png", + originalPerms : 0o776, + comparePerms : 0o644 +}, { + description : "Removed by precomplete (remove)", + fileName : "20text0", + relPathDir : DIR_RESOURCES + "2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Removed by precomplete (remove)", + fileName : "20png0.png", + relPathDir : DIR_RESOURCES + "2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}]; + +// Concatenate the common files to the end of the array. +gTestFilesCompleteSuccess = gTestFilesCompleteSuccess.concat(gTestFilesCommon); + +// Files for a partial successful update. This can be used for a partial failed +// update by calling setTestFilesAndDirsForFailure. +var gTestFilesPartialSuccess = [ +{ + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : DIR_RESOURCES, + originalContents : null, + compareContents : null, + originalFile : FILE_COMPLETE_PRECOMPLETE, + compareFile : FILE_PARTIAL_PRECOMPLETE, + originalPerms : 0o666, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : DIR_RESOURCES + "searchplugins/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : 0o775, + comparePerms : 0o644 +}, { + description : "Patched by update.manifest if the file exists " + + "(patch-if)", + fileName : "searchpluginspng1.png", + relPathDir : DIR_RESOURCES + "searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "complete.png", + compareFile : "partial.png", + originalPerms : 0o666, + comparePerms : 0o666 +}, { + description : "Patched by update.manifest if the file exists " + + "(patch-if)", + fileName : "searchpluginspng0.png", + relPathDir : DIR_RESOURCES + "searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "complete.png", + compareFile : "partial.png", + originalPerms : 0o666, + comparePerms : 0o666 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0o644 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions1png1.png", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "complete.png", + compareFile : "partial.png", + originalPerms : 0o666, + comparePerms : 0o666 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions1png0.png", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "complete.png", + compareFile : "partial.png", + originalPerms : 0o666, + comparePerms : 0o666 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : 0o644, + comparePerms : 0o644 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions0png1.png", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "complete.png", + compareFile : "partial.png", + originalPerms : 0o644, + comparePerms : 0o644 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions0png0.png", + relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "complete.png", + compareFile : "partial.png", + originalPerms : 0o644, + comparePerms : 0o644 +}, { + description : "Patched by update.manifest (patch)", + fileName : "exe0.exe", + relPathDir : DIR_MACOS, + originalContents : null, + compareContents : null, + originalFile : FILE_COMPLETE_EXE, + compareFile : FILE_PARTIAL_EXE, + originalPerms : 0o755, + comparePerms : 0o755 +}, { + description : "Patched by update.manifest (patch)", + fileName : "0exe0.exe", + relPathDir : DIR_RESOURCES + "0/", + originalContents : null, + compareContents : null, + originalFile : FILE_COMPLETE_EXE, + compareFile : FILE_PARTIAL_EXE, + originalPerms : 0o755, + comparePerms : 0o755 +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : DIR_RESOURCES + "0/00/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : 0o644, + comparePerms : 0o644 +}, { + description : "Patched by update.manifest (patch)", + fileName : "00png0.png", + relPathDir : DIR_RESOURCES + "0/00/", + originalContents : null, + compareContents : null, + originalFile : "complete.png", + compareFile : "partial.png", + originalPerms : 0o666, + comparePerms : 0o666 +}, { + description : "Added by update.manifest (add)", + fileName : "20text0", + relPathDir : DIR_RESOURCES + "2/20/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "20png0.png", + relPathDir : DIR_RESOURCES + "2/20/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "partial.png", + originalPerms : null, + comparePerms : 0o644 +}, { + description : "Added by update.manifest (add)", + fileName : "00text2", + relPathDir : DIR_RESOURCES + "0/00/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0o644 +}, { + description : "Removed by update.manifest (remove)", + fileName : "10text0", + relPathDir : DIR_RESOURCES + "1/10/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Removed by update.manifest (remove)", + fileName : "00text1", + relPathDir : DIR_RESOURCES + "0/00/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}]; + +// Concatenate the common files to the end of the array. +gTestFilesPartialSuccess = gTestFilesPartialSuccess.concat(gTestFilesCommon); + +var gTestDirsCommon = [ +{ + relPathDir : DIR_RESOURCES + "3/", + dirRemoved : false, + files : ["3text0", "3text1"], + filesRemoved : true +}, { + relPathDir : DIR_RESOURCES + "4/", + dirRemoved : true, + files : ["4text0", "4text1"], + filesRemoved : true +}, { + relPathDir : DIR_RESOURCES + "5/", + dirRemoved : true, + files : ["5test.exe", "5text0", "5text1"], + filesRemoved : true +}, { + relPathDir : DIR_RESOURCES + "6/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "7/", + dirRemoved : true, + files : ["7text0", "7text1"], + subDirs : ["70/", "71/"], + subDirFiles : ["7xtest.exe", "7xtext0", "7xtext1"] +}, { + relPathDir : DIR_RESOURCES + "8/", + dirRemoved : false +}, { + relPathDir : DIR_RESOURCES + "8/80/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "8/81/", + dirRemoved : false, + files : ["81text0", "81text1"] +}, { + relPathDir : DIR_RESOURCES + "8/82/", + dirRemoved : false, + subDirs : ["820/", "821/"] +}, { + relPathDir : DIR_RESOURCES + "8/83/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "8/84/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "8/85/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "8/86/", + dirRemoved : true, + files : ["86text0", "86text1"] +}, { + relPathDir : DIR_RESOURCES + "8/87/", + dirRemoved : true, + subDirs : ["870/", "871/"], + subDirFiles : ["87xtext0", "87xtext1"] +}, { + relPathDir : DIR_RESOURCES + "8/88/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "8/89/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "9/90/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "9/91/", + dirRemoved : false, + files : ["91text0", "91text1"] +}, { + relPathDir : DIR_RESOURCES + "9/92/", + dirRemoved : false, + subDirs : ["920/", "921/"] +}, { + relPathDir : DIR_RESOURCES + "9/93/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "9/94/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "9/95/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "9/96/", + dirRemoved : true, + files : ["96text0", "96text1"] +}, { + relPathDir : DIR_RESOURCES + "9/97/", + dirRemoved : true, + subDirs : ["970/", "971/"], + subDirFiles : ["97xtext0", "97xtext1"] +}, { + relPathDir : DIR_RESOURCES + "9/98/", + dirRemoved : true +}, { + relPathDir : DIR_RESOURCES + "9/99/", + dirRemoved : true +}]; + +// Directories for a complete successful update. This array can be used for a +// complete failed update by calling setTestFilesAndDirsForFailure. +var gTestDirsCompleteSuccess = [ +{ + description : "Removed by precomplete (rmdir)", + relPathDir : DIR_RESOURCES + "2/20/", + dirRemoved : true +}, { + description : "Removed by precomplete (rmdir)", + relPathDir : DIR_RESOURCES + "2/", + dirRemoved : true +}]; + +// Concatenate the common files to the beginning of the array. +gTestDirsCompleteSuccess = gTestDirsCommon.concat(gTestDirsCompleteSuccess); + +// Directories for a partial successful update. This array can be used for a +// partial failed update by calling setTestFilesAndDirsForFailure. +var gTestDirsPartialSuccess = [ +{ + description : "Removed by update.manifest (rmdir)", + relPathDir : DIR_RESOURCES + "1/10/", + dirRemoved : true +}, { + description : "Removed by update.manifest (rmdir)", + relPathDir : DIR_RESOURCES + "1/", + dirRemoved : true +}]; + +// Concatenate the common files to the beginning of the array. +gTestDirsPartialSuccess = gTestDirsCommon.concat(gTestDirsPartialSuccess); + +// This makes it possible to run most tests on xulrunner where the update +// channel default preference is not set. +if (MOZ_APP_NAME == "xulrunner") { + try { + gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); + } catch (e) { + setUpdateChannel("test_channel"); + } +} + +/** + * Helper function for setting up the test environment. + */ +function setupTestCommon() { + logTestInfo("start - general test setup"); + + do_test_pending(); + + if (gTestID) { + do_throw("setupTestCommon should only be called once!"); + } + + let caller = Components.stack.caller; + gTestID = caller.filename.toString().split("/").pop().split(".")[0]; + + if (DEBUG_TEST_LOG) { + let logFile = do_get_file(gTestID + ".log", true); + if (logFile.exists()) { + gPassed = false; + logTestInfo("start - dumping previous test run log"); + logTestInfo("\n" + readFile(logFile) + "\n"); + logTestInfo("finish - dumping previous test run log"); + if (gDeleteLogFile) { + logFile.remove(false); + } + do_throw("The parallel run of this test failed. Failing non-parallel " + + "test so the log from the parallel run can be displayed in " + + "non-parallel log.") + } else { + gRealDump = dump; + dump = dumpOverride; + } + } + + // Don't attempt to show a prompt when an update finishes. + Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true); + + gGREDirOrig = getGREDir(); + gGREBinDirOrig = getGREBinDir(); + gAppDirOrig = getAppBaseDir(); + + let applyDir = getApplyDirFile(null, true).parent; + + // Try to remove the directory used to apply updates and the updates directory + // on platforms other than Windows. Since the test hasn't ran yet and the + // directory shouldn't exist finished this is non-fatal for the test. + if (applyDir.exists()) { + logTestInfo("attempting to remove directory. Path: " + applyDir.path); + try { + removeDirRecursive(applyDir); + } catch (e) { + logTestInfo("non-fatal error removing directory. Path: " + + applyDir.path + ", Exception: " + e); + } + } + + // adjustGeneralPaths registers a cleanup function that calls end_test when + // it is defined as a function. + adjustGeneralPaths(); + + // Remove the updates directory on Windows and Mac OS X which is located + // outside of the application directory after the call to adjustGeneralPaths + // has set it up. Since the test hasn't ran yet and the directory shouldn't + // exist this is non-fatal for the test. + if (IS_WIN || IS_MACOSX) { + let updatesDir = getMockUpdRootD(); + if (updatesDir.exists()) { + logTestInfo("attempting to remove directory. Path: " + updatesDir.path); + try { + removeDirRecursive(updatesDir); + } catch (e) { + logTestInfo("non-fatal error removing directory. Path: " + + updatesDir.path + ", Exception: " + e); + } + } + } + + logTestInfo("finish - general test setup"); +} + +/** + * Nulls out the most commonly used global vars used by tests to prevent leaks + * as needed and attempts to restore the system to its original state. + */ +function cleanupTestCommon() { + logTestInfo("start - general test cleanup"); + + // Force the update manager to reload the update data to prevent it from + // writing the old data to the files that have just been removed. + reloadUpdateManagerData(); + + if (gChannel) { + gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer); + } + + // Call app update's observe method passing xpcom-shutdown to test that the + // shutdown of app update runs without throwing or leaking. The observer + // method is used directly instead of calling notifyObservers so components + // outside of the scope of this test don't assert and thereby cause app update + // tests to fail. + gAUS.observe(null, "xpcom-shutdown", ""); + + if (gXHR) { + gXHRCallback = null; + + gXHR.responseXML = null; + // null out the event handlers to prevent a mFreeCount leak of 1 + gXHR.onerror = null; + gXHR.onload = null; + gXHR.onprogress = null; + + gXHR = null; + } + + gTestserver = null; + + if (IS_UNIX) { + // This will delete the launch script if it exists. + getLaunchScript(); + } + + if (IS_WIN && MOZ_APP_BASENAME) { + let appDir = getApplyDirFile(null, true); + let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla"; + const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME + + "\\TaskBarIDs"; + let key = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); + try { + key.open(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, + Ci.nsIWindowsRegKey.ACCESS_ALL); + if (key.hasValue(appDir.path)) { + key.removeValue(appDir.path); + } + } catch (e) { + } + try { + key.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH, + Ci.nsIWindowsRegKey.ACCESS_ALL); + if (key.hasValue(appDir.path)) { + key.removeValue(appDir.path); + } + } catch (e) { + } + } + + // The updates directory is located outside of the application directory on + // Windows and Mac OS X so it also needs to be removed. + if (IS_WIN || IS_MACOSX) { + let updatesDir = getMockUpdRootD(); + // Try to remove the directory used to apply updates. Since the test has + // already finished this is non-fatal for the test. + if (updatesDir.exists()) { + logTestInfo("attempting to remove directory. Path: " + updatesDir.path); + try { + removeDirRecursive(updatesDir); + } catch (e) { + logTestInfo("non-fatal error removing directory. Path: " + + updatesDir.path + ", Exception: " + e); + } + if (IS_MACOSX) { + let updatesRootDir = gUpdatesRootDir.clone(); + while (updatesRootDir.path != updatesDir.path) { + if (updatesDir.exists()) { + logTestInfo("attempting to remove directory. Path: " + + updatesDir.path); + try { + // Try to remove the directory without the recursive flag set + // since the top level directory has already had its contents + // removed and the parent directory might still be used by a + // different test. + updatesDir.remove(false); + } catch (e) { + logTestInfo("non-fatal error removing directory. Path: " + + updatesDir.path + ", Exception: " + e); + } + } + updatesDir = updatesDir.parent; + } + } + } + } + + let applyDir = getApplyDirFile(null, true).parent; + + // Try to remove the directory used to apply updates. Since the test has + // already finished this is non-fatal for the test. + if (applyDir.exists()) { + logTestInfo("attempting to remove directory. Path: " + applyDir.path); + try { + removeDirRecursive(applyDir); + } catch (e) { + logTestInfo("non-fatal error removing directory. Path: " + + applyDir.path + ", Exception: " + e); + } + } + + resetEnvironment(); + + logTestInfo("finish - general test cleanup"); + + if (gRealDump) { + dump = gRealDump; + gRealDump = null; + } + + if (DEBUG_TEST_LOG && !gPassed) { + let fos = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + let logFile = do_get_file(gTestID + ".log", true); + if (!logFile.exists()) { + logFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); + } + fos.init(logFile, MODE_WRONLY | MODE_CREATE | MODE_APPEND, PERMS_FILE, 0); + fos.write(gTestLogText, gTestLogText.length); + fos.close(); + } + + if (DEBUG_TEST_LOG) { + gTestLogText = null; + } else { + let logFile = do_get_file(gTestID + ".log", true); + if (logFile.exists()) { + logFile.remove(false); + } + } +} + +/** + * Helper function to store the log output of calls to dump in a variable so the + * values can be written to a file for a parallel run of a test and printed to + * the log file when the test runs synchronously. + */ +function dumpOverride(aText) { + gTestLogText += aText; + gRealDump(aText); +} + +/** + * Helper function that calls do_test_finished that tracks whether a parallel + * run of a test passed when it runs synchronously so the log output can be + * inspected. + */ +function doTestFinish() { + if (gPassed === undefined) { + gPassed = true; + } + do_test_finished(); +} + +/** + * Sets the most commonly used preferences used by tests + */ +function setDefaultPrefs() { + Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true); + // Don't display UI for a successful installation. Some apps may not set this + // pref to false like Firefox does. + Services.prefs.setBoolPref(PREF_APP_UPDATE_SHOW_INSTALLED_UI, false); + // Enable Update logging + Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true); +} + +/** + * Helper function for updater binary tests that sets the appropriate values + * to check for update failures. + */ +function setTestFilesAndDirsForFailure() { + gTestFiles.forEach(function STFADFF_Files(aTestFile) { + aTestFile.compareContents = aTestFile.originalContents; + aTestFile.compareFile = aTestFile.originalFile; + aTestFile.comparePerms = aTestFile.originalPerms; + }); + + gTestDirs.forEach(function STFADFF_Dirs(aTestDir) { + aTestDir.dirRemoved = false; + if (aTestDir.filesRemoved) { + aTestDir.filesRemoved = false; + } + }); +} + +/** + * Helper function for updater binary tests that prevents the distribution + * directory files from being created. + */ +function preventDistributionFiles() { + gTestFiles = gTestFiles.filter(function(aTestFile) { + return aTestFile.relPathDir.indexOf("distribution/") == -1; + }); + + gTestDirs = gTestDirs.filter(function(aTestDir) { + return aTestDir.relPathDir.indexOf("distribution/") == -1; + }); +} + + +/** + * Initializes the most commonly used settings and creates an instance of the + * update service stub. + */ +function standardInit() { + createAppInfo("xpcshell@tests.mozilla.org", APP_INFO_NAME, "1.0", "2.0"); + setDefaultPrefs(); + // Initialize the update service stub component + initUpdateServiceStub(); +} + +/** + * Custom path handler for the http server + * + * @param aMetadata + * The http metadata for the request. + * @param aResponse + * The http response for the request. + */ +function pathHandler(aMetadata, aResponse) { + aResponse.setHeader("Content-Type", "text/xml", false); + aResponse.setStatusLine(aMetadata.httpVersion, gResponseStatusCode, "OK"); + aResponse.bodyOutputStream.write(gResponseBody, gResponseBody.length); +} + +/** + * Helper function for getting the application version from the application.ini + * file. This will look in both the GRE and the application directories for the + * application.ini file. + * + * @return The version string from the application.ini file. + * @throws If the application.ini file is not found. + */ +function getAppVersion() { + // Read the application.ini and use its application version. + let iniFile = gGREDirOrig.clone(); + iniFile.append(FILE_APPLICATION_INI); + if (!iniFile.exists()) { + iniFile = gGREBinDirOrig.clone(); + iniFile.append(FILE_APPLICATION_INI); + if (!iniFile.exists()) { + do_throw("Unable to find application.ini!"); + } + } + let iniParser = Cc["@mozilla.org/xpcom/ini-parser-factory;1"]. + getService(Ci.nsIINIParserFactory). + createINIParser(iniFile); + return iniParser.getString("App", "Version"); +} + +/** + * Helper function for getting the relative path to the directory where the + * application binary is located (e.g. /dir.app/). + * + * Note: The dir.app subdirectory under is needed for + * platforms other than Mac OS X so the tests can run in parallel due to + * update staging creating a lock file named moz_update_in_progress.lock in + * the parent directory of the installation directory. + * + * @return The relative path to the directory where application binary is + * located. + */ +function getApplyDirPath() { + return gTestID + "/dir.app/"; +} + +/** + * Helper function for getting the nsIFile for a file in the directory where the + * update will be applied. + * + * The files for the update are located two directories below the apply to + * directory since Mac OS X sets the last modified time for the root directory + * to the current time and if the update changes any files in the root directory + * then it wouldn't be possible to test (bug 600098). + * + * @param aRelPath (optional) + * The relative path to the file or directory to get from the root of + * the test's directory. If not specified the test's directory will be + * returned. + * @param aAllowNonexistent (optional) + * Whether the file must exist. If false or not specified the file must + * exist or the function will throw. + * @return The nsIFile for the file in the directory where the update will be + * applied. + * @throws If aAllowNonexistent is not specified or is false and the file or + * directory does not exist. + */ +function getApplyDirFile(aRelPath, aAllowNonexistent) { + let relpath = getApplyDirPath() + (aRelPath ? aRelPath : ""); + return do_get_file(relpath, aAllowNonexistent); +} + +/** + * Helper function for getting the nsIFile for a file in the directory where the + * update will be staged. + * + * The files for the update are located two directories below the stage + * directory since Mac OS X sets the last modified time for the root directory + * to the current time and if the update changes any files in the root directory + * then it wouldn't be possible to test (bug 600098). + * + * @param aRelPath (optional) + * The relative path to the file or directory to get from the root of + * the stage directory. If not specified the stage directory will be + * returned. + * @param aAllowNonexistent (optional) + * Whether the file must exist. If false or not specified the file must + * exist or the function will throw. + * @return The nsIFile for the file in the directory where the update will be + * staged. + * @throws If aAllowNonexistent is not specified or is false and the file or + * directory does not exist. + */ +function getStageDirFile(aRelPath, aAllowNonexistent) { + if (IS_MACOSX) { + let file = getMockUpdRootD(); + file.append(DIR_UPDATES); + file.append(DIR_PATCH); + file.append(DIR_UPDATED); + if (aRelPath) { + let pathParts = aRelPath.split("/"); + for (let i = 0; i < pathParts.length; i++) { + if (pathParts[i]) { + file.append(pathParts[i]); + } + } + } + if (!aAllowNonexistent && !file.exists()) { + do_throw(file.path + " does not exist"); + } + return file; + } + + let relpath = getApplyDirPath() + DIR_UPDATED + "/" + (aRelPath ? aRelPath : ""); + return do_get_file(relpath, aAllowNonexistent); +} + +/** + * Helper function for getting the relative path to the directory where the + * test data files are located. + * + * @return The relative path to the directory where the test data files are + * located. + */ +function getTestDirPath() { + return "../data/"; +} + +/** + * Helper function for getting the nsIFile for a file in the test data + * directory. + * + * @param aRelPath (optional) + * The relative path to the file or directory to get from the root of + * the test's data directory. If not specified the test's data + * directory will be returned. + * @return The nsIFile for the file in the test data directory. + * @throws If the file or directory does not exist. + */ +function getTestDirFile(aRelPath) { + let relpath = getTestDirPath() + (aRelPath ? aRelPath : ""); + return do_get_file(relpath, false); +} + +/** + * Helper function for getting the nsIFile for the maintenance service + * directory on Windows. + * + * @return The nsIFile for the maintenance service directory. + */ +function getMaintSvcDir() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + const CSIDL_PROGRAM_FILES = 0x26; + const CSIDL_PROGRAM_FILESX86 = 0x2A; + // This will return an empty string on our Win XP build systems. + let maintSvcDir = getSpecialFolderDir(CSIDL_PROGRAM_FILESX86); + if (maintSvcDir) { + maintSvcDir.append("Mozilla Maintenance Service"); + debugDump("using CSIDL_PROGRAM_FILESX86 - maintenance service install " + + "directory path: " + maintSvcDir.path); + } + if (!maintSvcDir || !maintSvcDir.exists()) { + maintSvcDir = getSpecialFolderDir(CSIDL_PROGRAM_FILES); + if (maintSvcDir) { + maintSvcDir.append("Mozilla Maintenance Service"); + debugDump("using CSIDL_PROGRAM_FILES - maintenance service install " + + "directory path: " + maintSvcDir.path); + } + } + if (!maintSvcDir) { + do_throw("Unable to find the maintenance service install directory"); + } + + return maintSvcDir; +} + +function getSpecialFolderDir(aCSIDL) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let lib = ctypes.open("shell32"); + let SHGetSpecialFolderPath = lib.declare("SHGetSpecialFolderPathW", + ctypes.winapi_abi, + ctypes.bool, /* bool(return) */ + ctypes.int32_t, /* HWND hwndOwner */ + ctypes.char16_t.ptr, /* LPTSTR lpszPath */ + ctypes.int32_t, /* int csidl */ + ctypes.bool /* BOOL fCreate */); + + let aryPath = ctypes.char16_t.array()(260); + let rv = SHGetSpecialFolderPath(0, aryPath, aCSIDL, false); + lib.close(); + + let path = aryPath.readString(); // Convert the c-string to js-string + if (!path) { + return null; + } + logTestInfo("SHGetSpecialFolderPath returned path: " + path); + let dir = Cc["@mozilla.org/file/local;1"]. + createInstance(Ci.nsILocalFile); + dir.initWithPath(path); + return dir; +} + +XPCOMUtils.defineLazyGetter(this, "gInstallDirPathHash", + function test_gInstallDirPathHash() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + // Figure out where we should check for a cached hash value + if (!MOZ_APP_BASENAME) { + return null; + } + + let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla"; + let appDir = getApplyDirFile(null, true); + + const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME + + "\\TaskBarIDs"; + let regKey = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); + try { + regKey.open(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, + Ci.nsIWindowsRegKey.ACCESS_ALL); + regKey.writeStringValue(appDir.path, gTestID); + return gTestID; + } catch (e) { + } + + try { + regKey.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH, + Ci.nsIWindowsRegKey.ACCESS_ALL); + regKey.writeStringValue(appDir.path, gTestID); + return gTestID; + } catch (e) { + logTestInfo("failed to create registry key. Registry Path: " + REG_PATH + + ", Key Name: " + appDir.path + ", Key Value: " + gTestID + + ", Exception " + e); + } + return null; +}); + +XPCOMUtils.defineLazyGetter(this, "gLocalAppDataDir", + function test_gLocalAppDataDir() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + const CSIDL_LOCAL_APPDATA = 0x1c; + return getSpecialFolderDir(CSIDL_LOCAL_APPDATA); +}); + +XPCOMUtils.defineLazyGetter(this, "gProgFilesDir", + function test_gProgFilesDir() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + const CSIDL_PROGRAM_FILES = 0x26; + return getSpecialFolderDir(CSIDL_PROGRAM_FILES); +}); + +/** + * Helper function for getting the update root directory used by the tests. This + * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir + * in nsXREDirProvider.cpp so an application will be able to find the update + * when running a test that launches the application. + */ +function getMockUpdRootD() { + if (IS_WIN) { + return getMockUpdRootDWin(); + } + + if (IS_MACOSX) { + return getMockUpdRootDMac(); + } + + return getApplyDirFile(DIR_MACOS, true); +} + +/** + * Helper function for getting the update root directory used by the tests. This + * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir + * in nsXREDirProvider.cpp so an application will be able to find the update + * when running a test that launches the application. + */ +function getMockUpdRootDWin() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let localAppDataDir = gLocalAppDataDir.clone(); + let progFilesDir = gProgFilesDir.clone(); + let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile).parent; + + let appDirPath = appDir.path; + let relPathUpdates = ""; + if (gInstallDirPathHash && (MOZ_APP_VENDOR || MOZ_APP_BASENAME)) { + relPathUpdates += (MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME) + + "\\" + DIR_UPDATES + "\\" + gInstallDirPathHash; + } + + if (!relPathUpdates && progFilesDir) { + if (appDirPath.length > progFilesDir.path.length) { + if (appDirPath.substr(0, progFilesDir.path.length) == progFilesDir.path) { + if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) { + relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME; + } else { + relPathUpdates += MOZ_APP_BASENAME; + } + relPathUpdates += appDirPath.substr(progFilesDir.path.length); + } + } + } + + if (!relPathUpdates) { + if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) { + relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME; + } else { + relPathUpdates += MOZ_APP_BASENAME; + } + relPathUpdates += "\\" + MOZ_APP_NAME; + } + + let updatesDir = Cc["@mozilla.org/file/local;1"]. + createInstance(Ci.nsILocalFile); + updatesDir.initWithPath(localAppDataDir.path + "\\" + relPathUpdates); + logTestInfo("returning UpdRootD Path: " + updatesDir.path); + return updatesDir; +} + +XPCOMUtils.defineLazyGetter(this, "gUpdatesRootDir", + function test_gUpdatesRootDir() { + if (!IS_MACOSX) { + do_throw("Mac OS X only function called by a different platform!"); + } + + let dir = Services.dirsvc.get("ULibDir", Ci.nsILocalFile); + dir.append("Caches"); + if (MOZ_APP_VENDOR || MOZ_APP_BASENAME) { + dir.append(MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME); + } else { + dir.append("Mozilla"); + } + dir.append(DIR_UPDATES); + return dir; +}); + +/** + * Helper function for getting the update root directory used by the tests. This + * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir + * in nsXREDirProvider.cpp so an application will be able to find the update + * when running a test that launches the application. + */ +function getMockUpdRootDMac() { + if (!IS_MACOSX) { + do_throw("Mac OS X only function called by a different platform!"); + } + + let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile). + parent.parent.parent; + let appDirPath = appDir.path; + appDirPath = appDirPath.substr(0, appDirPath.length - 4); + + let pathUpdates = gUpdatesRootDir.path + appDirPath; + let updatesDir = Cc["@mozilla.org/file/local;1"]. + createInstance(Ci.nsILocalFile); + updatesDir.initWithPath(pathUpdates); + logTestInfo("returning UpdRootD Path: " + updatesDir.path); + return updatesDir; +} + +const kLockFileName = "updated.update_in_progress.lock"; +/** + * Helper function for locking a directory on Windows. + * + * @param aDir + * The nsIFile for the directory to lock. + */ +function lockDirectory(aDir) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let file = aDir.clone(); + file.append(kLockFileName); + file.create(file.NORMAL_FILE_TYPE, 0o444); + file.QueryInterface(Ci.nsILocalFileWin); + file.fileAttributesWin |= file.WFA_READONLY; + file.fileAttributesWin &= ~file.WFA_READWRITE; + logTestInfo("testing the successful creation of the lock file"); + do_check_true(file.exists()); + do_check_false(file.isWritable()); +} +/** + * Helper function for unlocking a directory on Windows. + * + * @param aDir + * The nsIFile for the directory to unlock. + */ +function unlockDirectory(aDir) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + let file = aDir.clone(); + file.append(kLockFileName); + file.QueryInterface(Ci.nsILocalFileWin); + file.fileAttributesWin |= file.WFA_READWRITE; + file.fileAttributesWin &= ~file.WFA_READONLY; + logTestInfo("removing and testing the successful removal of the lock file"); + file.remove(false); + do_check_false(file.exists()); +} + +/** + * Helper function for updater tests for launching the updater binary to apply + * a mar file. + * + * @param aExpectedExitValue + * The expected exit value from the updater binary. + * @param aExpectedStatus + * The expected value of update.status when the test finishes. + * @param aCallback (optional) + * A callback function that will be called when this function finishes. + * If null no function will be called when this function finishes. + * If not specified the checkUpdateApplied function will be called when + * this function finishes. + */ +function runUpdate(aExpectedExitValue, aExpectedStatus, aCallback) { + // Copy the updater binary to the updates directory. + let binDir = gGREBinDirOrig.clone(); + let updater = binDir.clone(); + updater.append("updater.app"); + if (!updater.exists()) { + updater = binDir.clone(); + updater.append(FILE_UPDATER_BIN); + if (!updater.exists()) { + do_throw("Unable to find updater binary!"); + } + } + + let updatesDir = getUpdatesPatchDir(); + let updateBin; + if (IS_WIN) { + updateBin = updater.clone(); + } else { + updater.copyToFollowingLinks(updatesDir, updater.leafName); + updateBin = updatesDir.clone(); + updateBin.append(updater.leafName); + if (updateBin.leafName == "updater.app") { + updateBin.append("Contents"); + updateBin.append("MacOS"); + updateBin.append("updater"); + } + } + if (!updateBin.exists()) { + do_throw("Unable to find the updater executable!"); + } + + let applyToDir = getApplyDirFile(null, true); + let applyToDirPath = applyToDir.path; + + let stageDir = getStageDirFile(null, true); + let stageDirPath = stageDir.path; + + if (IS_WIN) { + // Convert to native path + applyToDirPath = applyToDirPath.replace(/\//g, "\\"); + stageDirPath = stageDirPath.replace(/\//g, "\\"); + } + + let callbackApp = getApplyDirFile(DIR_RESOURCES + gCallbackBinFile); + callbackApp.permissions = PERMS_DIRECTORY; + + let args = [updatesDir.path, applyToDirPath]; + if (gStageUpdate) { + args[2] = stageDirPath; + args[3] = -1; + } else { + if (gSwitchApp) { + args[2] = stageDirPath; + args[3] = "0/replace"; + } else { + args[2] = applyToDirPath; + args[3] = "0"; + } + args = args.concat([callbackApp.parent.path, callbackApp.path]); + args = args.concat(gCallbackArgs); + } + logTestInfo("running the updater: " + updateBin.path + " " + args.join(" ")); + + let env = Cc["@mozilla.org/process/environment;1"]. + getService(Ci.nsIEnvironment); + if (gDisableReplaceFallback) { + env.set("MOZ_NO_REPLACE_FALLBACK", "1"); + } + + let process = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + process.init(updateBin); + process.run(true, args, args.length); + + if (gDisableReplaceFallback) { + env.set("MOZ_NO_REPLACE_FALLBACK", ""); + } + + let status = readStatusFile(); + if (process.exitValue != aExpectedExitValue || status != aExpectedStatus) { + if (process.exitValue != aExpectedExitValue) { + logTestInfo("updater exited with unexpected value! Got: " + + process.exitValue + ", Expected: " + aExpectedExitValue); + } + if (status != aExpectedStatus) { + logTestInfo("update status is not the expected status! Got: " + status + + ", Expected: " + aExpectedStatus); + } + let updateLog = getUpdatesPatchDir(); + updateLog.append(FILE_UPDATE_LOG); + // xpcshell tests won't display the entire contents so log each line. + let contents = readFileBytes(updateLog).replace(/\r\n/g, "\n"); + let aryLogContents = contents.split("\n"); + logTestInfo("contents of " + updateLog.path + ":"); + aryLogContents.forEach(function RU_LC_FE(aLine) { + logTestInfo(aLine); + }); + } + logTestInfo("testing updater binary process exitValue against expected " + + "exit value"); + do_check_eq(process.exitValue, aExpectedExitValue); + logTestInfo("testing update status against expected status"); + do_check_eq(status, aExpectedStatus); + + if (aCallback !== null) { + if (typeof(aCallback) == typeof(Function)) { + aCallback(); + } else { + checkUpdateApplied(); + } + } +} + +/** + * Helper function for updater tests to stage an update. + */ +function stageUpdate() { + logTestInfo("start - attempting to stage update"); + Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false); + + setEnvironment(); + // Stage the update. + Cc["@mozilla.org/updates/update-processor;1"]. + createInstance(Ci.nsIUpdateProcessor). + processUpdate(gUpdateManager.activeUpdate); + resetEnvironment(); + + logTestInfo("finish - attempting to stage update"); +} + +/** + * Helper function to check whether the maintenance service updater tests should + * run. See bug 711660 for more details. + * + * @param aFirstTest + * Whether this is the first test within the test. + * @param aSkipTest + * Whether to skip this test if the installed maintenance service + * isn't the same as the build's maintenance service. This is a + * temporary workaround until all build systems grant write access to + * the maintenance service install directory so the tests can copy the + * version of the maintenance service that should be tests. + * @return true if the test should run and false if it shouldn't. + */ +function shouldRunServiceTest(aFirstTest, aSkipTest) { + let binDir = getGREBinDir(); + let updaterBin = binDir.clone(); + updaterBin.append(FILE_UPDATER_BIN); + if (!updaterBin.exists()) { + do_throw("Unable to find updater binary!"); + } + + let updaterBinPath = updaterBin.path; + if (/ /.test(updaterBinPath)) { + updaterBinPath = '"' + updaterBinPath + '"'; + } + + const REG_PATH = "SOFTWARE\\Mozilla\\MaintenanceService\\" + + "3932ecacee736d366d6436db0f55bce4"; + + let key = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); + try { + key.open(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, + Ci.nsIWindowsRegKey.ACCESS_READ | key.WOW64_64); + } catch (e) { + // The build system could sign the files and not have the test registry key + // in which case we should fail the test by throwing so it can be fixed. + if (IS_AUTHENTICODE_CHECK_ENABLED && isBinarySigned(updaterBinPath)) { + do_throw("binary is signed but the test registry key does not exists!"); + } + + logTestInfo("this test can only run on the buildbot build system at this " + + "time."); + return false; + } + + // Check to make sure the service is installed + let helperBin = getTestDirFile(FILE_HELPER_BIN); + let args = ["wait-for-service-stop", "MozillaMaintenance", "10"]; + let process = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + process.init(helperBin); + logTestInfo("checking if the service exists on this machine."); + process.run(true, args, args.length); + if (process.exitValue == 0xEE) { + do_throw("test registry key exists but this test can only run on systems " + + "with the maintenance service installed."); + } else { + logTestInfo("service exists, return value: " + process.exitValue); + } + + // If this is the first test in the series, then there is no reason the + // service should be anything but stopped, so be strict here and throw + // an error. + if (aFirstTest && process.exitValue != 0) { + do_throw("First test, check for service stopped state returned error " + + process.exitValue); + } + + if (IS_AUTHENTICODE_CHECK_ENABLED && !isBinarySigned(updaterBinPath)) { + logTestInfo("test registry key exists but this test can only run on " + + "builds with signed binaries when " + + "DISABLE_UPDATER_AUTHENTICODE_CHECK is not defined"); + do_throw("this test can only run on builds with signed binaries."); + } + + // In case the machine is running an old maintenance service or if it + // is not installed, and permissions exist to install it. Then install + // the newer bin that we have since all of the other checks passed. + return attemptServiceInstall(aSkipTest); +} + +/** + * Helper function to check whether the a binary is signed. + * + * @param aBinPath The path to the file to check if it is signed. + * @return true if the file is signed and false if it isn't. + */ +function isBinarySigned(aBinPath) { + let helperBin = getTestDirFile(FILE_HELPER_BIN); + let args = ["check-signature", aBinPath]; + let process = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + process.init(helperBin); + process.run(true, args, args.length); + if (process.exitValue != 0) { + logTestInfo("binary is not signed. " + FILE_HELPER_BIN + " returned " + + process.exitValue + " for file " + aBinPath); + return false; + } + return true; +} + +/** + * Helper function for asynchronously setting up the application files required + * to launch the application for the updater tests by either copying or creating + * symlinks for the files. This is needed for Windows debug builds which can + * lock a file that is being copied so that the tests can run in parallel. After + * the files have been copied the setupAppFilesFinished function will be called. + */ +function setupAppFilesAsync() { + gTimeoutRuns++; + try { + setupAppFiles(); + } catch (e) { + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while trying to setup application " + + "files. Exception: " + e); + } + do_timeout(TEST_CHECK_TIMEOUT, setupAppFilesAsync); + return; + } + + setupAppFilesFinished(); +} + +/** + * Helper function for setting up the application files required to launch the + * application for the updater tests by either copying or creating symlinks to + * the files. + */ +function setupAppFiles() { + logTestInfo("start - copying or creating symlinks to application files " + + "for the test"); + + let destDir = getApplyDirFile(null, true); + if (!destDir.exists()) { + try { + destDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } catch (e) { + logTestInfo("unable to create directory, Path: " + destDir.path + + ", Exception: " + e); + do_throw(e); + } + } + + // Required files for the application or the test that aren't listed in the + // dependentlibs.list file. + let appFiles = [ { relPath : FILE_APP_BIN, + inGreDir : false }, + { relPath : FILE_UPDATER_BIN, + inGreDir : false }, + { relPath : FILE_APPLICATION_INI, + inGreDir : true }, + { relPath : "dependentlibs.list", + inGreDir : true } ]; + + // On Linux the updater.png must also be copied + if (IS_UNIX && !IS_MACOSX) { + appFiles.push( { relPath : "icons/updater.png", + inGreDir : true } ); + } + + // Read the dependent libs file leafnames from the dependentlibs.list file + // into the array. + let deplibsFile = gGREDirOrig.clone(); + deplibsFile.append("dependentlibs.list"); + let istream = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + istream.init(deplibsFile, 0x01, 0o444, 0); + istream.QueryInterface(Ci.nsILineInputStream); + + let hasMore; + let line = {}; + do { + hasMore = istream.readLine(line); + appFiles.push( { relPath : line.value, + inGreDir : false } ); + } while(hasMore); + + istream.close(); + + appFiles.forEach(function CMAF_FLN_FE(aAppFile) { + copyFileToTestAppDir(aAppFile.relPath, aAppFile.inGreDir); + }); + + logTestInfo("finish - copying or creating symlinks to application files " + + "for the test"); +} + +/** + * Copies the specified files from the dist/bin directory into the test's + * application directory. + * + * @param aFileRelPath + * The relative path to the source and the destination of the file to + * copy. + * @param aInGreDir + * Whether the file is located in the GRE directory which is + * /Contents/Resources on Mac OS X and is the installation + * directory on all other platforms. If false the file must be in the + * GRE Binary directory which is /Contents/MacOS on Mac OS X and + * is the installation directory on on all other platforms. + */ +function copyFileToTestAppDir(aFileRelPath, aInGreDir) { + // gGREDirOrig and gGREBinDirOrig must always be cloned when changing its + // properties + let srcFile = aInGreDir ? gGREDirOrig.clone() : gGREBinDirOrig.clone(); + let destFile = aInGreDir ? getGREDir() : getGREBinDir(); + let fileRelPath = aFileRelPath; + let pathParts = fileRelPath.split("/"); + for (let i = 0; i < pathParts.length; i++) { + if (pathParts[i]) { + srcFile.append(pathParts[i]); + destFile.append(pathParts[i]); + } + } + + if (IS_MACOSX && !srcFile.exists()) { + logTestInfo("unable to copy file since it doesn't exist! Checking if " + + fileRelPath + ".app exists. Path: " + + srcFile.path); + // gGREDirOrig and gGREBinDirOrig must always be cloned when changing its + // properties + srcFile = aInGreDir ? gGREDirOrig.clone() : gGREBinDirOrig.clone(); + destFile = aInGreDir ? getGREDir() : getGREBinDir(); + for (let i = 0; i < pathParts.length; i++) { + if (pathParts[i]) { + srcFile.append(pathParts[i] + (pathParts.length - 1 == i ? ".app" : "")); + destFile.append(pathParts[i] + (pathParts.length - 1 == i ? ".app" : "")); + } + } + fileRelPath = fileRelPath + ".app"; + } + + if (!srcFile.exists()) { + do_throw("Unable to copy file since it doesn't exist! Path: " + + srcFile.path); + } + + // Symlink libraries. Note that the XUL library on Mac OS X doesn't have a + // file extension and shouldSymlink will always be false on Windows. + let shouldSymlink = (pathParts[pathParts.length - 1] == "XUL" || + fileRelPath.substr(fileRelPath.length - 3) == ".so" || + fileRelPath.substr(fileRelPath.length - 6) == ".dylib"); + if (!shouldSymlink) { + if (!destFile.exists()) { + try { + srcFile.copyToFollowingLinks(destFile.parent, destFile.leafName); + } catch (e) { + // Just in case it is partially copied + if (destFile.exists()) { + try { + destFile.remove(true); + } catch (e) { + logTestInfo("unable to remove file that failed to copy! Path: " + + destFile.path); + } + } + do_throw("Unable to copy file! Path: " + srcFile.path + + ", Exception: " + e); + } + } + } else { + try { + if (destFile.exists()) { + destFile.remove(false); + } + let ln = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); + ln.initWithPath("/bin/ln"); + let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); + process.init(ln); + let args = ["-s", srcFile.path, destFile.path]; + process.run(true, args, args.length); + logTestInfo("verifying symlink. Path: " + destFile.path); + do_check_true(destFile.isSymlink()); + } catch (e) { + do_throw("Unable to create symlink for file! Path: " + srcFile.path + + ", Exception: " + e); + } + } +} + +/** + * Attempts to upgrade the maintenance service if permissions are allowed. + * This is useful for XP where we have permission to upgrade in case an + * older service installer exists. Also if the user manually installed into + * a unprivileged location. + * + * @param aSkipTest + * Whether to skip this test if the installed maintenance service + * isn't the same as the build's maintenance service. This is a + * temporary workaround until all build systems grant write access to + * the maintenance service install directory so the tests can copy the + * version of the maintenance service that should be tests. + */ +function attemptServiceInstall(aSkipTest) { + let maintSvcDir = getMaintSvcDir(); + if (!maintSvcDir || !maintSvcDir.exists()) { + do_throw("maintenance service install directory doesn't exist!"); + } + let oldMaintSvcBin = maintSvcDir.clone(); + oldMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); + if (!oldMaintSvcBin.exists()) { + do_throw("maintenance service install directory binary doesn't exist! " + + "Path: " + oldMaintSvcBin.path); + } + let buildMaintSvcBin = getGREBinDir(); + buildMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); + if (readFileBytes(oldMaintSvcBin) == readFileBytes(buildMaintSvcBin)) { + logTestInfo("installed maintenance service binary is the same as the " + + "build's maintenance service binary"); + return true; + } + let backupMaintSvcBin = maintSvcDir.clone(); + backupMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN + ".backup"); + try { + if (backupMaintSvcBin.exists()) { + backupMaintSvcBin.remove(false); + } + oldMaintSvcBin.moveTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN + ".backup"); + buildMaintSvcBin.copyTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN); + backupMaintSvcBin.remove(false); + return true; + } catch (e) { + // Restore the original file in case the moveTo was successful. + if (backupMaintSvcBin.exists()) { + oldMaintSvcBin = maintSvcDir.clone(); + oldMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); + if (!oldMaintSvcBin.exists()) { + backupMaintSvcBin.moveTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN); + } + } + logTestInfo("unable to copy new maintenance service into the " + + "maintenance service directory: " + maintSvcDir.path + ", " + + "Exception: " + e); + } + + let version = Cc["@mozilla.org/system-info;1"]. + getService(Ci.nsIPropertyBag2). + getProperty("version"); + // The account running the tests on Win XP and Win 7 build systems have write + // access to the maintenance service directory so throw if copying the + // maintenance service binary fails. This should always throw after write + // access is provided on all Windows build slaves in bug 1067756. + if ((parseFloat(version) <= 6.1)) { + do_throw("The account running the tests on Win 7 and below build systems " + + "should have write access to the maintenance service directory!"); + } + + return aSkipTest ? false : true; +} + +/** + * Helper function for updater tests for launching the updater using the + * maintenance service to apply a mar file. + * + * @param aInitialStatus + * The initial value of update.status. + * @param aExpectedStatus + * The expected value of update.status when the test finishes. + * @param aCheckSvcLog (optional) + * Whether the service log should be checked. + */ +function runUpdateUsingService(aInitialStatus, aExpectedStatus, aCheckSvcLog) { + // Check the service logs for a successful update + function checkServiceLogs(aOriginalContents) { + let contents = readServiceLogFile(); + logTestInfo("the contents of maintenanceservice.log:\n" + contents + "\n"); + do_check_neq(contents, aOriginalContents); + do_check_neq(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1); + } + function readServiceLogFile() { + let file = getMaintSvcDir(); + file.append("logs"); + file.append("maintenanceservice.log"); + return readFile(file); + } + function waitServiceApps() { + // maintenanceservice_installer.exe is started async during updates. + waitForApplicationStop("maintenanceservice_installer.exe"); + // maintenanceservice_tmp.exe is started async from the service installer. + waitForApplicationStop("maintenanceservice_tmp.exe"); + // In case the SCM thinks the service is stopped, but process still exists. + waitForApplicationStop("maintenanceservice.exe"); + } + function waitForServiceStop(aFailTest) { + waitServiceApps(); + logTestInfo("waiting for service to stop if necessary..."); + // Use the helper bin to ensure the service is stopped. If not + // stopped then wait for the service to be stopped (at most 120 seconds) + let helperBin = getTestDirFile(FILE_HELPER_BIN); + let helperBinArgs = ["wait-for-service-stop", + "MozillaMaintenance", + "120"]; + let helperBinProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + helperBinProcess.init(helperBin); + logTestInfo("stopping service..."); + helperBinProcess.run(true, helperBinArgs, helperBinArgs.length); + if (helperBinProcess.exitValue == 0xEE) { + do_throw("The service does not exist on this machine. Return value: " + + helperBinProcess.exitValue); + } else if (helperBinProcess.exitValue != 0) { + if (aFailTest) { + do_throw("maintenance service did not stop, last state: " + + helperBinProcess.exitValue + ". Forcing test failure."); + } else { + logTestInfo("maintenance service did not stop, last state: " + + helperBinProcess.exitValue + ". May cause failures."); + } + } else { + logTestInfo("service stopped."); + } + waitServiceApps(); + } + function waitForApplicationStop(aApplication) { + logTestInfo("waiting for " + aApplication + " to stop if " + + "necessary..."); + // Use the helper bin to ensure the application is stopped. + // If not, then wait for it to be stopped (at most 120 seconds) + let helperBin = getTestDirFile(FILE_HELPER_BIN); + let helperBinArgs = ["wait-for-application-exit", + aApplication, + "120"]; + let helperBinProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + helperBinProcess.init(helperBin); + helperBinProcess.run(true, helperBinArgs, helperBinArgs.length); + if (helperBinProcess.exitValue != 0) { + do_throw(aApplication + " did not stop, last state: " + + helperBinProcess.exitValue + ". Forcing test failure."); + } + } + + // Make sure the service from the previous test is already stopped. + waitForServiceStop(true); + + // Prevent the cleanup function from begin run more than once + if (gRegisteredServiceCleanup === undefined) { + gRegisteredServiceCleanup = true; + + do_register_cleanup(function RUUS_cleanup() { + resetEnvironment(); + + // This will delete the app arguments log file if it exists. + try { + getAppArgsLogPath(); + } catch (e) { + logTestInfo("unable to remove file during cleanup. Exception: " + e); + } + }); + } + + let svcOriginalLog; + // Default to checking the service log if the parameter is not specified. + if (aCheckSvcLog === undefined || aCheckSvcLog) { + svcOriginalLog = readServiceLogFile(); + } + + let appArgsLogPath = getAppArgsLogPath(); + gServiceLaunchedCallbackLog = appArgsLogPath.replace(/^"|"$/g, ""); + + let updatesDir = getUpdatesPatchDir(); + writeStatusFile(aInitialStatus); + + // sanity check + do_check_eq(readStatusState(), aInitialStatus); + + writeVersionFile(DEFAULT_UPDATE_VERSION); + + gServiceLaunchedCallbackArgs = [ + "-no-remote", + "-process-updates", + "-dump-args", + appArgsLogPath + ]; + + if (gSwitchApp) { + // We want to set the env vars again + gShouldResetEnv = undefined; + } + + setEnvironment(); + + // There is a security check done by the service to make sure the updater + // we are executing is the same as the one in the apply-to dir. + // To make sure they match from tests we copy updater.exe to the apply-to dir. + copyFileToTestAppDir(FILE_UPDATER_BIN, false); + + // The service will execute maintenanceservice_installer.exe and + // will copy maintenanceservice.exe out of the same directory from + // the installation directory. So we need to make sure both of those + // bins always exist in the installation directory. + copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN, false); + copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, false); + + let launchBin = getLaunchBin(); + let args = getProcessArgs(["-dump-args", appArgsLogPath]); + + let process = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + process.init(launchBin); + logTestInfo("launching " + launchBin.path + " " + args.join(" ")); + // Firefox does not wait for the service command to finish, but + // we still launch the process sync to avoid intermittent failures with + // the log file not being written out yet. + // We will rely on watching the update.status file and waiting for the service + // to stop to know the service command is done. + process.run(true, args, args.length); + + resetEnvironment(); + + function timerCallback(aTimer) { + // Wait for the expected status + let status = readStatusFile(); + // status will probably always be equal to STATE_APPLYING but there is a + // race condition where it would be possible on slower machines where status + // could be equal to STATE_PENDING_SVC. + if (status == STATE_APPLYING || + status == STATE_PENDING_SVC) { + logTestInfo("still waiting to see the " + aExpectedStatus + + " status, got " + status + " for now..."); + return; + } + + // Make sure all of the logs are written out. + waitForServiceStop(false); + + aTimer.cancel(); + aTimer = null; + + if (status != aExpectedStatus) { + logTestInfo("update status is not the expected status! Got: " + status + + ", Expected: " + aExpectedStatus); + logTestInfo("update.status contents: " + readStatusFile()); + let updateLog = getUpdatesPatchDir(); + updateLog.append(FILE_UPDATE_LOG); + // xpcshell tests won't display the entire contents so log each line. + let contents = readFileBytes(updateLog).replace(/\r\n/g, "\n"); + let aryLogContents = contents.split("\n"); + logTestInfo("contents of " + updateLog.path + ":"); + aryLogContents.forEach(function RUUS_TC_LC_FE(aLine) { + logTestInfo(aLine); + }); + } + logTestInfo("testing update status against expected status"); + do_check_eq(status, aExpectedStatus); + + if (aCheckSvcLog) { + checkServiceLogs(svcOriginalLog); + } + + checkUpdateFinished(); + } + + let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + timer.initWithCallback(timerCallback, 1000, timer.TYPE_REPEATING_SLACK); +} + +/** + * Gets the platform specific shell binary that is launched using nsIProcess and + * in turn launches a binary used for the test (e.g. application, updater, + * etc.). A shell is used so debug console output can be redirected to a file so + * it doesn't end up in the test log. + * + * @return nsIFile for the shell binary to launch using nsIProcess. + * @throws if the shell binary doesn't exist. + */ +function getLaunchBin() { + let launchBin; + if (IS_WIN) { + launchBin = Services.dirsvc.get("WinD", Ci.nsIFile); + launchBin.append("System32"); + launchBin.append("cmd.exe"); + } else { + launchBin = Cc["@mozilla.org/file/local;1"]. + createInstance(Ci.nsILocalFile); + launchBin.initWithPath("/bin/sh"); + } + + if (!launchBin.exists()) { + do_throw(launchBin.path + " must exist to run this test!"); + } + + return launchBin; +} + +/** + * Helper function that waits until the helper has completed its operations and + * is in a sleep state before performing an update by calling doUpdate. + */ +function waitForHelperSleep() { + gTimeoutRuns++; + // Give the lock file process time to lock the file before updating otherwise + // this test can fail intermittently on Windows debug builds. + let output = getApplyDirFile(DIR_RESOURCES + "output", true); + if (readFile(output) != "sleeping\n") { + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper to " + + "finish its operation. Path: " + output.path); + } + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); + return; + } + try { + output.remove(false); + } + catch (e) { + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper " + + "message file to no longer be in use. Path: " + output.path); + } + logTestInfo("failed to remove file. Path: " + output.path); + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); + return; + } + doUpdate(); +} + +/** + * Helper function that waits until the helper has finished its operations + * before calling waitForHelperFinishFileUnlock to verify that the helper's + * input and output directories are no longer in use. + */ +function waitForHelperFinished() { + // Give the lock file process time to lock the file before updating otherwise + // this test can fail intermittently on Windows debug builds. + let output = getApplyDirFile(DIR_RESOURCES + "output", true); + if (readFile(output) != "finished\n") { + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperFinished); + return; + } + // Give the lock file process time to unlock the file before deleting the + // input and output files. + waitForHelperFinishFileUnlock(); +} + +/** + * Helper function that waits until the helper's input and output files are no + * longer in use before calling checkUpdate. + */ +function waitForHelperFinishFileUnlock() { + try { + let output = getApplyDirFile(DIR_RESOURCES + "output", true); + if (output.exists()) { + output.remove(false); + } + let input = getApplyDirFile(DIR_RESOURCES + "input", true); + if (input.exists()) { + input.remove(false); + } + } catch (e) { + // Give the lock file process time to unlock the file before deleting the + // input and output files. + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperFinishFileUnlock); + return; + } + checkUpdate(); +} + +/** + * Helper function to tell the helper to finish and exit its sleep state. + */ +function setupHelperFinish() { + let input = getApplyDirFile(DIR_RESOURCES + "input", true); + writeFile(input, "finish\n"); + waitForHelperFinished(); +} + +/** + * Helper function for updater binary tests that creates the files and + * directories used by the test. + * + * @param aMarFile + * The mar file for the update test. + */ +function setupUpdaterTest(aMarFile) { + let updatesPatchDir = getUpdatesPatchDir(); + if (!updatesPatchDir.exists()) { + updatesPatchDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } + // Copy the mar that will be applied + let mar = getTestDirFile(aMarFile); + mar.copyToFollowingLinks(updatesPatchDir, FILE_UPDATE_ARCHIVE); + + let helperBin = getTestDirFile(FILE_HELPER_BIN); + let afterApplyBinDir = getApplyDirFile(DIR_RESOURCES, true); + helperBin.copyToFollowingLinks(afterApplyBinDir, gCallbackBinFile); + helperBin.copyToFollowingLinks(afterApplyBinDir, gPostUpdateBinFile); + + let applyToDir = getApplyDirFile(null, true); + gTestFiles.forEach(function SUT_TF_FE(aTestFile) { + if (aTestFile.originalFile || aTestFile.originalContents) { + let testDir = getApplyDirFile(aTestFile.relPathDir, true); + if (!testDir.exists()) { + testDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } + + let testFile; + if (aTestFile.originalFile) { + testFile = getTestDirFile(aTestFile.originalFile); + testFile.copyToFollowingLinks(testDir, aTestFile.fileName); + testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName); + } else { + testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName, + true); + writeFile(testFile, aTestFile.originalContents); + } + + // Skip these tests on Windows and OS/2 since their + // implementaions of chmod doesn't really set permissions. + if (!IS_WIN && aTestFile.originalPerms) { + testFile.permissions = aTestFile.originalPerms; + // Store the actual permissions on the file for reference later after + // setting the permissions. + if (!aTestFile.comparePerms) { + aTestFile.comparePerms = testFile.permissions; + } + } + } + }); + + // Add the test directory that will be updated for a successful update or left + // in the initial state for a failed update. + gTestDirs.forEach(function SUT_TD_FE(aTestDir) { + let testDir = getApplyDirFile(aTestDir.relPathDir, true); + if (!testDir.exists()) { + testDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } + + if (aTestDir.files) { + aTestDir.files.forEach(function SUT_TD_F_FE(aTestFile) { + let testFile = getApplyDirFile(aTestDir.relPathDir + aTestFile, true); + if (!testFile.exists()) { + testFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); + } + }); + } + + if (aTestDir.subDirs) { + aTestDir.subDirs.forEach(function SUT_TD_SD_FE(aSubDir) { + let testSubDir = getApplyDirFile(aTestDir.relPathDir + aSubDir, true); + if (!testSubDir.exists()) { + testSubDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } + + if (aTestDir.subDirFiles) { + aTestDir.subDirFiles.forEach(function SUT_TD_SDF_FE(aTestFile) { + let testFile = getApplyDirFile(aTestDir.relPathDir + aSubDir + aTestFile, true); + if (!testFile.exists()) { + testFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); + } + }); + } + }); + } + }); +} + +/** + * Helper function for updater binary tests that creates the update-settings.ini + * file. + */ +function createUpdateSettingsINI() { + let updateSettingsIni = getApplyDirFile(null, true); + if (IS_MACOSX) { + updateSettingsIni.append("Contents"); + updateSettingsIni.append("Resources"); + } + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); + writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS); +} + +/** + * Helper function for updater binary tests that creates the updater.ini + * file. + * + * @param aIsExeAsync + * True or undefined if the post update process should be async. If + * undefined ExeAsync will not be added to the updater.ini file in + * order to test the default launch behavior which is async. + */ +function createUpdaterINI(aIsExeAsync) { + let exeArg = "ExeArg=post-update-async\n"; + let exeAsync = ""; + if (aIsExeAsync !== undefined) { + if (aIsExeAsync) { + exeAsync = "ExeAsync=true\n"; + } else { + exeArg = "ExeArg=post-update-sync\n"; + exeAsync = "ExeAsync=false\n"; + } + } + + let updaterIniContents = "[Strings]\n" + + "Title=Update Test\n" + + "Info=Running update test " + gTestID + "\n\n" + + "[PostUpdateMac]\n" + + "ExeRelPath=" + DIR_RESOURCES + gPostUpdateBinFile + "\n" + + exeArg + + exeAsync + + "\n" + + "[PostUpdateWin]\n" + + "ExeRelPath=" + gPostUpdateBinFile + "\n" + + exeArg + + exeAsync; + let updaterIni = getApplyDirFile(DIR_RESOURCES + FILE_UPDATER_INI, true); + writeFile(updaterIni, updaterIniContents); +} + +/** + * Helper function for updater binary tests for verifying the contents of the + * update log after a successful update. + * + * @param aCompareLogFile + * The log file to compare the update log with. + * @param aExcludeDistributionDir + * Removes lines containing the distribution directory from the log + * file to compare the update log with. + */ +function checkUpdateLogContents(aCompareLogFile, aExcludeDistributionDir) { + if (IS_UNIX && !IS_MACOSX) { + // Sorting on Linux is different so skip checking the logs for now. + return; + } + let updateLog = getUpdatesPatchDir(); + updateLog.append(FILE_UPDATE_LOG); + let updateLogContents = readFileBytes(updateLog); + + // The channel-prefs.js is defined in gTestFilesCommon which will always be + // located to the end of gTestFiles. + if (gTestFiles.length > 1 && + gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" && + !gTestFiles[gTestFiles.length - 1].originalContents) { + updateLogContents = updateLogContents.replace(/.*defaults\/.*/g, ""); + } + if (gTestFiles.length > 2 && + gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI && + !gTestFiles[gTestFiles.length - 2].originalContents) { + updateLogContents = updateLogContents.replace(/.*update-settings.ini.*/g, ""); + } + if (gStageUpdate) { + // Skip the staged update messages + updateLogContents = updateLogContents.replace(/Performing a staged update/, ""); + } else if (gSwitchApp) { + // Skip the switch app request messages + updateLogContents = updateLogContents.replace(/Performing a staged update/, ""); + updateLogContents = updateLogContents.replace(/Performing a replace request/, ""); + } + // Skip the source/destination lines since they contain absolute paths. + updateLogContents = updateLogContents.replace(/PATCH DIRECTORY.*/g, ""); + updateLogContents = updateLogContents.replace(/INSTALLATION DIRECTORY.*/g, ""); + updateLogContents = updateLogContents.replace(/WORKING DIRECTORY.*/g, ""); + // Skip lines that log failed attempts to open the callback executable. + updateLogContents = updateLogContents.replace(/NS_main: callback app file .*/g, ""); + if (IS_MACOSX) { + // Skip lines that log moving the distribution directory for Mac v2 signing. + updateLogContents = updateLogContents.replace(/Moving old [^\n]*\nrename_file: .*/g, ""); + updateLogContents = updateLogContents.replace(/New distribution directory .*/g, ""); + } + if (gSwitchApp) { + // Remove the lines which contain absolute paths + updateLogContents = updateLogContents.replace(/^Begin moving.*$/mg, ""); + updateLogContents = updateLogContents.replace(/^ensure_remove: failed to remove file: .*$/mg, ""); + updateLogContents = updateLogContents.replace(/^ensure_remove_recursive: unable to remove directory: .*$/mg, ""); + updateLogContents = updateLogContents.replace(/^Removing tmpDir failed, err: -1$/mg, ""); + updateLogContents = updateLogContents.replace(/^remove_recursive_on_reboot: .*$/mg, ""); + } + updateLogContents = updateLogContents.replace(/\r/g, ""); + // Replace error codes since they are different on each platform. + updateLogContents = updateLogContents.replace(/, err:.*\n/g, "\n"); + // Replace to make the log parsing happy. + updateLogContents = updateLogContents.replace(/non-fatal error /g, ""); + // The FindFile results when enumerating the filesystem on Windows is not + // determistic so the results matching the following need to be ignored. + updateLogContents = updateLogContents.replace(/.*7\/7text.*\n/g, ""); + // Remove consecutive newlines + updateLogContents = updateLogContents.replace(/\n+/g, "\n"); + // Remove leading and trailing newlines + updateLogContents = updateLogContents.replace(/^\n|\n$/g, ""); + // The update log when running the service tests sometimes starts with data + // from the previous launch of the updater. + updateLogContents = updateLogContents.replace(/^calling QuitProgressUI\n[^\n]*\nUPDATE TYPE/g, "UPDATE TYPE"); + + let compareLogContents = ""; + if (aCompareLogFile) { + compareLogContents = readFileBytes(getTestDirFile(aCompareLogFile)); + } + if (gSwitchApp) { + compareLogContents += LOG_SWITCH_SUCCESS; + } + // The channel-prefs.js is defined in gTestFilesCommon which will always be + // located to the end of gTestFiles. + if (gTestFiles.length > 1 && + gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" && + !gTestFiles[gTestFiles.length - 1].originalContents) { + compareLogContents = compareLogContents.replace(/.*defaults\/.*/g, ""); + } + if (gTestFiles.length > 2 && + gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI && + !gTestFiles[gTestFiles.length - 2].originalContents) { + compareLogContents = compareLogContents.replace(/.*update-settings.ini.*/g, ""); + } + if (aExcludeDistributionDir) { + compareLogContents = compareLogContents.replace(/.*distribution\/.*/g, ""); + } + // Remove leading and trailing newlines + compareLogContents = compareLogContents.replace(/\n+/g, "\n"); + // Remove leading and trailing newlines + compareLogContents = compareLogContents.replace(/^\n|\n$/g, ""); + + // Don't write the contents of the file to the log to reduce log spam + // unless there is a failure. + if (compareLogContents == updateLogContents) { + logTestInfo("log contents are correct"); + do_check_true(true); + } else { + logTestInfo("log contents are not correct"); + let aryLog = updateLogContents.split("\n"); + let aryCompare = compareLogContents.split("\n"); + // Pushing an empty string to both arrays makes it so either array's length + // can be used in the for loop below without going out of bounds. + aryLog.push(""); + aryCompare.push(""); + // xpcshell tests won't display the entire contents so log the incorrect + // line. + for (let i = 0; i < aryLog.length; ++i) { + if (aryCompare[i] != aryLog[i]) { + logTestInfo("the first incorrect line in the log is: " + aryLog[i]); + do_check_eq(aryCompare[i], aryLog[i]); + } + } + // This should never happen! + do_throw("Unable to find incorrect log contents!"); + } +} + +/** + * Helper function to check if the update log contains a string. + * + * @param aCheckString + * The string to check if the update log contains. + */ +function checkUpdateLogContains(aCheckString) { + let updateLog = getUpdatesPatchDir(); + updateLog.append(FILE_UPDATE_LOG); + let updateLogContents = readFileBytes(updateLog); + if (updateLogContents.indexOf(aCheckString) != -1) { + logTestInfo("log file does contain: " + aCheckString); + do_check_true(true); + } else { + logTestInfo("log file does not contain: " + aCheckString); + do_check_true(false); + } +} + +/** + * Helper function for updater binary tests for verifying the state of files and + * directories after a successful update. + * + * @param aGetFileFunc + * The function used to get the files in the directory to be checked. + * @param aStageDirExists + * If true the staging directory will be tested for existence and if + * false the staging directory will be tested for non-existence. + * @param aToBeDeletedDirExists + * On Windows, if true the tobedeleted directory will be tested for + * existence and if false the tobedeleted directory will be tested for + * non-existence. On all othere platforms it will be tested for + * non-existence. + */ +function checkFilesAfterUpdateSuccess(aGetFileFunc, aStageDirExists, + aToBeDeletedDirExists) { + logTestInfo("testing contents of files after a successful update"); + gTestFiles.forEach(function CFAUS_TF_FE(aTestFile) { + let testFile = aGetFileFunc(aTestFile.relPathDir + aTestFile.fileName, true); + logTestInfo("testing file: " + testFile.path); + if (aTestFile.compareFile || aTestFile.compareContents) { + do_check_true(testFile.exists()); + + // Skip these tests on Windows and OS/2 since their + // implementaions of chmod doesn't really set permissions. + if (!IS_WIN && aTestFile.comparePerms) { + // Check if the permssions as set in the complete mar file are correct. + let logPerms = "testing file permissions - "; + if (aTestFile.originalPerms) { + logPerms += "original permissions: " + + aTestFile.originalPerms.toString(8) + ", "; + } + logPerms += "compare permissions : " + + aTestFile.comparePerms.toString(8) + ", "; + logPerms += "updated permissions : " + testFile.permissions.toString(8); + logTestInfo(logPerms); + do_check_eq(testFile.permissions & 0xfff, aTestFile.comparePerms & 0xfff); + } + + let fileContents1 = readFileBytes(testFile); + let fileContents2 = aTestFile.compareFile ? + readFileBytes(getTestDirFile(aTestFile.compareFile)) : + aTestFile.compareContents; + // Don't write the contents of the file to the log to reduce log spam + // unless there is a failure. + if (fileContents1 == fileContents2) { + logTestInfo("file contents are correct"); + do_check_true(true); + } else { + logTestInfo("file contents are not correct"); + do_check_eq(fileContents1, fileContents2); + } + } else { + do_check_false(testFile.exists()); + } + }); + + logTestInfo("testing operations specified in removed-files were performed " + + "after a successful update"); + gTestDirs.forEach(function CFAUS_TD_FE(aTestDir) { + let testDir = aGetFileFunc(aTestDir.relPathDir, true); + logTestInfo("testing directory: " + testDir.path); + if (aTestDir.dirRemoved) { + do_check_false(testDir.exists()); + } else { + do_check_true(testDir.exists()); + + if (aTestDir.files) { + aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) { + let testFile = aGetFileFunc(aTestDir.relPathDir + aTestFile, true); + logTestInfo("testing directory file: " + testFile.path); + if (aTestDir.filesRemoved) { + do_check_false(testFile.exists()); + } else { + do_check_true(testFile.exists()); + } + }); + } + + if (aTestDir.subDirs) { + aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) { + let testSubDir = aGetFileFunc(aTestDir.relPathDir + aSubDir, true); + logTestInfo("testing sub-directory: " + testSubDir.path); + do_check_true(testSubDir.exists()); + if (aTestDir.subDirFiles) { + aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) { + let testFile = aGetFileFunc(aTestDir.relPathDir + + aSubDir + aTestFile, true); + logTestInfo("testing sub-directory file: " + testFile.path); + do_check_true(testFile.exists()); + }); + } + }); + } + } + }); + + checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, + aToBeDeletedDirExists); +} + +/** + * Helper function for updater binary tests for verifying the state of files and + * directories after a failed update. + * + * @param aGetFileFunc + * the function used to get the files in the directory to be checked. + * @param aStageDirExists + * If true the staging directory will be tested for existence and if + * false the staging directory will be tested for non-existence. + * @param aToBeDeletedDirExists + * On Windows, if true the tobedeleted directory will be tested for + * existence and if false the tobedeleted directory will be tested for + * non-existence. On all othere platforms it will be tested for + * non-existence. + */ +function checkFilesAfterUpdateFailure(aGetFileFunc, aStageDirExists, + aToBeDeletedDirExists) { + logTestInfo("testing contents of files after a failed update"); + gTestFiles.forEach(function CFAUF_TF_FE(aTestFile) { + let testFile = aGetFileFunc(aTestFile.relPathDir + aTestFile.fileName, true); + logTestInfo("testing file: " + testFile.path); + if (aTestFile.compareFile || aTestFile.compareContents) { + do_check_true(testFile.exists()); + + // Skip these tests on Windows and OS/2 since their + // implementaions of chmod doesn't really set permissions. + if (!IS_WIN && aTestFile.comparePerms) { + // Check the original permssions are retained on the file. + let logPerms = "testing file permissions - "; + if (aTestFile.originalPerms) { + logPerms += "original permissions: " + + aTestFile.originalPerms.toString(8) + ", "; + } + logPerms += "compare permissions : " + + aTestFile.comparePerms.toString(8) + ", "; + logPerms += "updated permissions : " + testFile.permissions.toString(8); + logTestInfo(logPerms); + do_check_eq(testFile.permissions & 0xfff, aTestFile.comparePerms & 0xfff); + } + + let fileContents1 = readFileBytes(testFile); + let fileContents2 = aTestFile.compareFile ? + readFileBytes(getTestDirFile(aTestFile.compareFile)) : + aTestFile.compareContents; + // Don't write the contents of the file to the log to reduce log spam + // unless there is a failure. + if (fileContents1 == fileContents2) { + logTestInfo("file contents are correct"); + do_check_true(true); + } else { + logTestInfo("file contents are not correct"); + do_check_eq(fileContents1, fileContents2); + } + } else { + do_check_false(testFile.exists()); + } + }); + + logTestInfo("testing operations specified in removed-files were not " + + "performed after a failed update"); + gTestDirs.forEach(function CFAUF_TD_FE(aTestDir) { + let testDir = aGetFileFunc(aTestDir.relPathDir, true); + logTestInfo("testing directory: " + testDir.path); + do_check_true(testDir.exists()); + + if (aTestDir.files) { + aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) { + let testFile = aGetFileFunc(aTestDir.relPathDir + aTestFile, true); + logTestInfo("testing directory file: " + testFile.path); + do_check_true(testFile.exists()); + }); + } + + if (aTestDir.subDirs) { + aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) { + let testSubDir = aGetFileFunc(aTestDir.relPathDir + aSubDir, true); + logTestInfo("testing sub-directory: " + testSubDir.path); + do_check_true(testSubDir.exists()); + if (aTestDir.subDirFiles) { + aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) { + let testFile = aGetFileFunc(aTestDir.relPathDir + + aSubDir + aTestFile, true); + logTestInfo("testing sub-directory file: " + testFile.path); + do_check_true(testFile.exists()); + }); + } + }); + } + }); + + checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, + aToBeDeletedDirExists); +} + +/** + * Helper function for updater binary tests for verifying the state of common + * files and directories after a successful or failed update. + * + * @param aGetFileFunc + * the function used to get the files in the directory to be checked. + * @param aStageDirExists + * If true the staging directory will be tested for existence and if + * false the staging directory will be tested for non-existence. + * @param aToBeDeletedDirExists + * On Windows, if true the tobedeleted directory will be tested for + * existence and if false the tobedeleted directory will be tested for + * non-existence. On all othere platforms it will be tested for + * non-existence. + */ +function checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, + aToBeDeletedDirExists) { + logTestInfo("testing extra directories"); + + let stageDir = getStageDirFile(null, true); + logTestInfo("testing directory should " + + (aStageDirExists ? "" : "not ") + + "exist: " + stageDir.path); + do_check_eq(stageDir.exists(), aStageDirExists); + + let toBeDeletedDirExists = IS_WIN ? aToBeDeletedDirExists : false; + let toBeDeletedDir = getApplyDirFile(DIR_TOBEDELETED, true); + logTestInfo("testing directory should " + + (toBeDeletedDirExists ? "" : "not ") + + "exist: " + toBeDeletedDir.path); + do_check_eq(toBeDeletedDir.exists(), toBeDeletedDirExists); + + logTestInfo("testing updating directory doesn't exist in the application " + + "directory"); + let updatingDir = getApplyDirFile("updating", true); + do_check_false(updatingDir.exists()); + + if (stageDir.exists()) { + logTestInfo("testing updating directory doesn't exist in the staging " + + "directory"); + updatingDir = stageDir.clone(); + updatingDir.append("updating"); + do_check_false(updatingDir.exists()); + } + + logTestInfo("testing backup files should not be left behind in the " + + "application directory"); + let applyToDir = getApplyDirFile(null, true); + checkFilesInDirRecursive(applyToDir, checkForBackupFiles); + + if (stageDir.exists()) { + logTestInfo("testing backup files should not be left behind in the " + + "staging directory"); + let applyToDir = getApplyDirFile(null, true); + checkFilesInDirRecursive(stageDir, checkForBackupFiles); + } + + logTestInfo("testing patch files should not be left behind"); + let updatesDir = getUpdatesPatchDir(); + let entries = updatesDir.QueryInterface(Ci.nsIFile).directoryEntries; + while (entries.hasMoreElements()) { + let entry = entries.getNext().QueryInterface(Ci.nsIFile); + do_check_neq(getFileExtension(entry), "patch"); + } +} + +/** + * Helper function for updater binary tests for verifying the contents of the + * updater callback application log which should contain the arguments passed to + * the callback application. + */ +function checkCallbackAppLog() { + let appLaunchLog = getApplyDirFile(DIR_RESOURCES + gCallbackArgs[1], true); + if (!appLaunchLog.exists()) { + do_timeout(TEST_HELPER_TIMEOUT, checkCallbackAppLog); + return; + } + + let expectedLogContents = gCallbackArgs.join("\n") + "\n"; + let logContents = readFile(appLaunchLog); + // It is possible for the log file contents check to occur before the log file + // contents are completely written so wait until the contents are the expected + // value. If the contents are never the expected value then the test will + // fail by timing out. + if (logContents != expectedLogContents) { + do_timeout(TEST_HELPER_TIMEOUT, checkCallbackAppLog); + return; + } + + if (logContents == expectedLogContents) { + logTestInfo("callback log file contents are correct"); + do_check_true(true); + } else { + logTestInfo("callback log file contents are not correct"); + do_check_eq(logContents, expectedLogContents); + } + + waitForFilesInUse(); +} + +/** + * Helper function for updater binary tests for getting the log and running + * files created by the test helper binary file when called with the post-update + * command line argument. + * + * @param aSuffix + * The string to append to the post update test helper binary path. + */ +function getPostUpdateFile(aSuffix) { + return getApplyDirFile(DIR_RESOURCES + gPostUpdateBinFile + aSuffix, true); +} + +/** + * Helper function for updater binary tests for verifying the contents of the + * updater post update binary log. + */ +function checkPostUpdateAppLog() { + gTimeoutRuns++; + let postUpdateLog = getPostUpdateFile(".log"); + if (!postUpdateLog.exists()) { + logTestInfo("postUpdateLog does not exist. Path: " + postUpdateLog.path); + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the post update " + + "process to create the post update log. Path: " + + postUpdateLog.path); + } + do_timeout(TEST_HELPER_TIMEOUT, checkPostUpdateAppLog); + return; + } + + let logContents = readFile(postUpdateLog); + // It is possible for the log file contents check to occur before the log file + // contents are completely written so wait until the contents are the expected + // value. If the contents are never the expected value then the test will + // fail by timing out. + if (logContents != "post-update\n") { + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the post update " + + "process to create the expected contents in the post update log. Path: " + + postUpdateLog.path); + } + do_timeout(TEST_HELPER_TIMEOUT, checkPostUpdateAppLog); + return; + } + + logTestInfo("post update app log file contents are correct"); + do_check_true(true); + + gCheckFunc(); +} + +/** + * Helper function for updater service tests for verifying the contents of the + * updater callback application log which should contain the arguments passed to + * the callback application. + */ +function checkCallbackServiceLog() { + do_check_neq(gServiceLaunchedCallbackLog, null); + + let expectedLogContents = gServiceLaunchedCallbackArgs.join("\n") + "\n"; + let logFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); + logFile.initWithPath(gServiceLaunchedCallbackLog); + let logContents = readFile(logFile); + // It is possible for the log file contents check to occur before the log file + // contents are completely written so wait until the contents are the expected + // value. If the contents are never the expected value then the test will + // fail by timing out. + if (logContents != expectedLogContents) { + logTestInfo("callback service log not expected value, waiting longer"); + do_timeout(TEST_HELPER_TIMEOUT, checkCallbackServiceLog); + return; + } + + logTestInfo("testing that the callback application successfully launched " + + "and the expected command line arguments were passed to it"); + do_check_eq(logContents, expectedLogContents); + + waitForFilesInUse(); +} + +// Waits until files that are in use that break tests are no longer in use and +// then calls do_test_finished. +function waitForFilesInUse() { + if (IS_WIN) { + let appBin = getApplyDirFile(FILE_APP_BIN, true); + let maintSvcInstaller = getApplyDirFile(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, true); + let helper = getApplyDirFile("uninstall/helper.exe", true); + let updater = getUpdatesPatchDir(); + updater.append(FILE_UPDATER_BIN); + + let files = [appBin, updater, maintSvcInstaller, helper]; + + for (let i = 0; i < files.length; ++i) { + let file = files[i]; + let fileBak = file.parent.clone(); + if (file.exists()) { + fileBak.append(file.leafName + ".bak"); + try { + if (fileBak.exists()) { + fileBak.remove(false); + } + file.copyTo(fileBak.parent, fileBak.leafName); + file.remove(false); + fileBak.moveTo(file.parent, file.leafName); + logTestInfo("file is not in use. Path: " + file.path); + } catch (e) { + logTestInfo("file in use, will try again after " + TEST_CHECK_TIMEOUT + + " ms, Path: " + file.path + ", Exception: " + e); + try { + if (fileBak.exists()) { + fileBak.remove(false); + } + } catch (e) { + logTestInfo("unable to remove file, this should never happen! " + + "Path: " + fileBak.path + ", Exception: " + e); + } + do_timeout(TEST_CHECK_TIMEOUT, waitForFilesInUse); + return; + } + } + } + } + + logTestInfo("calling doTestFinish"); + doTestFinish(); +} + +/** + * Helper function for updater binary tests for verifying there are no update + * backup files left behind after an update. + * + * @param aFile + * An nsIFile to check if it has moz-backup for its extension. + */ +function checkForBackupFiles(aFile) { + do_check_neq(getFileExtension(aFile), "moz-backup"); +} + +/** + * Helper function for updater binary tests for recursively enumerating a + * directory and calling a callback function with the file as a parameter for + * each file found. + * + * @param aDir + * A nsIFile for the directory to be deleted + * @param aCallback + * A callback function that will be called with the file as a + * parameter for each file found. + */ +function checkFilesInDirRecursive(aDir, aCallback) { + if (!aDir.exists()) { + do_throw("Directory must exist!"); + } + + let dirEntries = aDir.directoryEntries; + while (dirEntries.hasMoreElements()) { + let entry = dirEntries.getNext().QueryInterface(Ci.nsIFile); + + if (entry.isDirectory()) { + checkFilesInDirRecursive(entry, aCallback); + } else { + aCallback(entry); + } + } +} + +/** + * Sets up the bare bones XMLHttpRequest implementation below. + * + * @param aCallback + * The callback function that will call the nsIDomEventListener's + * handleEvent method. + * + * Example of the callback function + * + * function callHandleEvent() { + * gXHR.status = gExpectedStatus; + * let e = { target: gXHR }; + * gXHR.onload.handleEvent(e); + * } + */ +function overrideXHR(aCallback) { + gXHRCallback = aCallback; + gXHR = new xhr(); + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); + registrar.registerFactory(gXHR.classID, gXHR.classDescription, + gXHR.contractID, gXHR); +} + + +/** + * Bare bones XMLHttpRequest implementation for testing onprogress, onerror, + * and onload nsIDomEventListener handleEvent. + */ +function makeHandler(aVal) { + if (typeof aVal == "function") { + return { handleEvent: aVal }; + } + return aVal; +} +function xhr() { +} +xhr.prototype = { + overrideMimeType: function(aMimetype) { }, + setRequestHeader: function(aHeader, aValue) { }, + status: null, + channel: { set notificationCallbacks(aVal) { } }, + _url: null, + _method: null, + open: function(aMethod, aUrl) { + gXHR.channel.originalURI = Services.io.newURI(aUrl, null, null); + gXHR._method = aMethod; gXHR._url = aUrl; + }, + responseXML: null, + responseText: null, + send: function(aBody) { + do_execute_soon(gXHRCallback); // Use a timeout so the XHR completes + }, + _onprogress: null, + set onprogress(aValue) { gXHR._onprogress = makeHandler(aValue); }, + get onprogress() { return gXHR._onprogress; }, + _onerror: null, + set onerror(aValue) { gXHR._onerror = makeHandler(aValue); }, + get onerror() { return gXHR._onerror; }, + _onload: null, + set onload(aValue) { gXHR._onload = makeHandler(aValue); }, + get onload() { return gXHR._onload; }, + addEventListener: function(aEvent, aValue, aCapturing) { + eval("gXHR._on" + aEvent + " = aValue"); + }, + flags: Ci.nsIClassInfo.SINGLETON, + implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT, + getHelperForLanguage: function(aLanguage) null, + getInterfaces: function(aCount) { + let interfaces = [Ci.nsISupports]; + aCount.value = interfaces.length; + return interfaces; + }, + classDescription: "XMLHttpRequest", + contractID: "@mozilla.org/xmlextras/xmlhttprequest;1", + classID: Components.ID("{c9b37f43-4278-4304-a5e0-600991ab08cb}"), + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gXHR.QueryInterface(aIID); + } + throw Cr.NS_ERROR_NO_AGGREGATION; + }, + get wrappedJSObject() { return this; }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIClassInfo]) +}; + +/** + * Helper function to override the update prompt component to verify whether it + * is called or not. + * + * @param aCallback + * The callback to call if the update prompt component is called. + */ +function overrideUpdatePrompt(aCallback) { + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); + gUpdatePrompt = new UpdatePrompt(); + gUpdatePromptCallback = aCallback; + registrar.registerFactory(gUpdatePrompt.classID, gUpdatePrompt.classDescription, + gUpdatePrompt.contractID, gUpdatePrompt); +} + +function UpdatePrompt() { + let fns = ["checkForUpdates", "showUpdateAvailable", "showUpdateDownloaded", + "showUpdateError", "showUpdateHistory", "showUpdateInstalled"]; + + fns.forEach(function(aPromptFn) { + UpdatePrompt.prototype[aPromptFn] = function() { + if (!gUpdatePromptCallback) { + return; + } + + let callback = gUpdatePromptCallback[aPromptFn]; + if (!callback) { + return; + } + + callback.apply(gUpdatePromptCallback, + Array.prototype.slice.call(arguments)); + } + }); +} + +UpdatePrompt.prototype = { + flags: Ci.nsIClassInfo.SINGLETON, + implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT, + getHelperForLanguage: function(aLanguage) null, + getInterfaces: function(aCount) { + let interfaces = [Ci.nsISupports, Ci.nsIUpdatePrompt]; + aCount.value = interfaces.length; + return interfaces; + }, + classDescription: "UpdatePrompt", + contractID: "@mozilla.org/updates/update-prompt;1", + classID: Components.ID("{8c350a15-9b90-4622-93a1-4d320308664b}"), + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gUpdatePrompt.QueryInterface(aIID); + } + throw Cr.NS_ERROR_NO_AGGREGATION; + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIClassInfo, Ci.nsIUpdatePrompt]) +}; + +/* Update check listener */ +const updateCheckListener = { + onProgress: function UCL_onProgress(aRequest, aPosition, aTotalSize) { + }, + + onCheckComplete: function UCL_onCheckComplete(aRequest, aUpdates, aUpdateCount) { + gRequestURL = aRequest.channel.originalURI.spec; + gUpdateCount = aUpdateCount; + gUpdates = aUpdates; + logTestInfo("url = " + gRequestURL + ", " + + "request.status = " + aRequest.status + ", " + + "update.statusText = " + aRequest.statusText + ", " + + "updateCount = " + aUpdateCount); + // Use a timeout to allow the XHR to complete + do_execute_soon(gCheckFunc); + }, + + onError: function UCL_onError(aRequest, aUpdate) { + gRequestURL = aRequest.channel.originalURI.spec; + gStatusCode = aRequest.status; + + gStatusText = aUpdate.statusText; + logTestInfo("url = " + gRequestURL + ", " + + "request.status = " + gStatusCode + ", " + + "update.statusText = " + gStatusText); + // Use a timeout to allow the XHR to complete + do_execute_soon(gCheckFunc.bind(null, aRequest, aUpdate)); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateCheckListener]) +}; + +/* Update download listener - nsIRequestObserver */ +const downloadListener = { + onStartRequest: function DL_onStartRequest(aRequest, aContext) { + }, + + onProgress: function DL_onProgress(aRequest, aContext, aProgress, aMaxProgress) { + }, + + onStatus: function DL_onStatus(aRequest, aContext, aStatus, aStatusText) { + }, + + onStopRequest: function DL_onStopRequest(aRequest, aContext, aStatus) { + gStatusResult = aStatus; + // Use a timeout to allow the request to complete + do_execute_soon(gCheckFunc); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver, + Ci.nsIProgressEventSink]) +}; + +/** + * Helper for starting the http server used by the tests + */ +function start_httpserver() { + let dir = getTestDirFile(); + logTestInfo("http server directory path: " + dir.path); + + if (!dir.isDirectory()) { + do_throw("A file instead of a directory was specified for HttpServer " + + "registerDirectory! Path: " + dir.path); + } + + let { HttpServer } = Cu.import("resource://testing-common/httpd.js", {}); + gTestserver = new HttpServer(); + gTestserver.registerDirectory("/", dir); + gTestserver.start(-1); + let testserverPort = gTestserver.identity.primaryPort; + gURLData = URL_HOST + ":" + testserverPort + "/"; + logTestInfo("http server port = " + testserverPort); +} + +/** + * Helper for stopping the http server used by the tests + * + * @param aCallback + * The callback to call after stopping the http server. + */ +function stop_httpserver(aCallback) { + do_check_true(!!aCallback); + gTestserver.stop(aCallback); +} + +/** + * Creates an nsIXULAppInfo + * + * @param aID + * The ID of the test application + * @param aName + * A name for the test application + * @param aVersion + * The version of the application + * @param aPlatformVersion + * The goanna version of the application + */ +function createAppInfo(aID, aName, aVersion, aPlatformVersion) { + const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1"; + const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}"); + let ifaces = [Ci.nsIXULAppInfo, Ci.nsIXULRuntime]; + if (IS_WIN) { + ifaces.push(Ci.nsIWinAppHelper); + } + const XULAppInfo = { + vendor: APP_INFO_VENDOR, + name: aName, + ID: aID, + version: aVersion, + appBuildID: "2007010101", + platformVersion: aPlatformVersion, + platformBuildID: "2007010101", + inSafeMode: false, + logConsoleErrors: true, + OS: "XPCShell", + XPCOMABI: "noarch-spidermonkey", + + QueryInterface: XPCOMUtils.generateQI(ifaces) + }; + + const XULAppInfoFactory = { + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return XULAppInfo.QueryInterface(aIID); + } + throw Cr.NS_ERROR_NO_AGGREGATION; + } + }; + + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); + registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo", + XULAPPINFO_CONTRACTID, XULAppInfoFactory); +} + +/** + * Returns the platform specific arguments used by nsIProcess when launching + * the application. + * + * @param aExtraArgs (optional) + * An array of extra arguments to append to the default arguments. + * @return an array of arguments to be passed to nsIProcess. + * + * Note: a shell is necessary to pipe the application's console output which + * would otherwise pollute the xpcshell log. + * + * Command line arguments used when launching the application: + * -no-remote prevents shell integration from being affected by an existing + * application process. + * -process-updates makes the application exits after being relaunched by the + * updater. + * the platform specific string defined by PIPE_TO_NULL to output both stdout + * and stderr to null. This is needed to prevent output from the application + * from ending up in the xpchsell log. + */ +function getProcessArgs(aExtraArgs) { + if (!aExtraArgs) { + aExtraArgs = []; + } + + let appBinPath = getApplyDirFile(DIR_MACOS + FILE_APP_BIN, false).path; + if (/ /.test(appBinPath)) { + appBinPath = '"' + appBinPath + '"'; + } + + let args; + if (IS_UNIX) { + let launchScript = getLaunchScript(); + // Precreate the script with executable permissions + launchScript.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY); + + let scriptContents = "#! /bin/sh\n"; + scriptContents += appBinPath + " -no-remote -process-updates " + + aExtraArgs.join(" ") + " " + PIPE_TO_NULL; + writeFile(launchScript, scriptContents); + logTestInfo("created " + launchScript.path + " containing:\n" + + scriptContents); + args = [launchScript.path]; + } else { + args = ["/D", "/Q", "/C", appBinPath, "-no-remote", "-process-updates"]. + concat(aExtraArgs).concat([PIPE_TO_NULL]); + } + return args; +} + +/** + * Gets a file path for the application to dump its arguments into. This is used + * to verify that a callback application is launched. + * + * @return the file for the application to dump its arguments into. + */ +function getAppArgsLogPath() { + let appArgsLog = do_get_file("/", true); + appArgsLog.append(gTestID + "_app_args_log"); + if (appArgsLog.exists()) { + appArgsLog.remove(false); + } + let appArgsLogPath = appArgsLog.path; + if (/ /.test(appArgsLogPath)) { + appArgsLogPath = '"' + appArgsLogPath + '"'; + } + return appArgsLogPath; +} + +/** + * Gets the nsIFile reference for the shell script to launch the application. If + * the file exists it will be removed by this function. + * + * @return the nsIFile for the shell script to launch the application. + */ +function getLaunchScript() { + let launchScript = do_get_file("/", true); + launchScript.append(gTestID + "_launch.sh"); + if (launchScript.exists()) { + launchScript.remove(false); + } + return launchScript; +} + +/** + * Makes GreD, XREExeF, and UpdRootD point to unique file system locations so + * xpcshell tests can run in parallel and to keep the environment clean. + */ +function adjustGeneralPaths() { + let dirProvider = { + getFile: function AGP_DP_getFile(aProp, aPersistent) { + aPersistent.value = true; + switch (aProp) { + case NS_GRE_DIR: + if (gUseTestAppDir) { + return getApplyDirFile(DIR_RESOURCES, true); + } + break; + case NS_GRE_BIN_DIR: + if (gUseTestAppDir) { + return getApplyDirFile(DIR_MACOS, true); + } + break; + case XRE_EXECUTABLE_FILE: + if (gUseTestAppDir) { + return getApplyDirFile(DIR_MACOS + FILE_APP_BIN, true); + } + break; + case XRE_UPDATE_ROOT_DIR: + return getMockUpdRootD(); + } + return null; + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]) + }; + let ds = Services.dirsvc.QueryInterface(Ci.nsIDirectoryService); + ds.QueryInterface(Ci.nsIProperties).undefine(NS_GRE_DIR); + ds.QueryInterface(Ci.nsIProperties).undefine(NS_GRE_BIN_DIR); + ds.QueryInterface(Ci.nsIProperties).undefine(XRE_EXECUTABLE_FILE); + ds.registerProvider(dirProvider); + do_register_cleanup(function AGP_cleanup() { + logTestInfo("start - unregistering directory provider"); + + if (gAppTimer) { + logTestInfo("start - cancel app timer"); + gAppTimer.cancel(); + gAppTimer = null; + logTestInfo("finish - cancel app timer"); + } + + if (gProcess && gProcess.isRunning) { + logTestInfo("start - kill process"); + try { + gProcess.kill(); + } catch (e) { + logTestInfo("kill process failed. Exception: " + e); + } + gProcess = null; + logTestInfo("finish - kill process"); + } + + if (gHandle) { + try { + logTestInfo("start - closing handle"); + let kernel32 = ctypes.open("kernel32"); + let CloseHandle = kernel32.declare("CloseHandle", ctypes.default_abi, + ctypes.bool, /*return*/ + ctypes.voidptr_t /*handle*/); + if (!CloseHandle(gHandle)) { + logTestInfo("call to CloseHandle failed"); + } + kernel32.close(); + gHandle = null; + logTestInfo("finish - closing handle"); + } catch (e) { + logTestInfo("call to CloseHandle failed. Exception: " + e); + } + } + + // Call end_test first before the directory provider is unregistered + if (typeof(end_test) == typeof(Function)) { + logTestInfo("calling end_test"); + end_test(); + } + + ds.unregisterProvider(dirProvider); + cleanupTestCommon(); + + logTestInfo("finish - unregistering directory provider"); + }); +} + + +/** + * Helper function for launching the application to apply an update. + */ +function launchAppToApplyUpdate() { + logTestInfo("start - launching application to apply update"); + + let appBin = getApplyDirFile(DIR_MACOS + FILE_APP_BIN, false); + + if (typeof(customLaunchAppToApplyUpdate) == typeof(Function)) { + customLaunchAppToApplyUpdate(); + } + + let launchBin = getLaunchBin(); + let args = getProcessArgs(); + logTestInfo("launching " + launchBin.path + " " + args.join(" ")); + + gProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + gProcess.init(launchBin); + + gAppTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT, + Ci.nsITimer.TYPE_ONE_SHOT); + + setEnvironment(); + logTestInfo("launching application"); + gProcess.runAsync(args, args.length, gProcessObserver); + resetEnvironment(); + + logTestInfo("finish - launching application to apply update"); +} + +/** + * The observer for the call to nsIProcess:runAsync. + */ +const gProcessObserver = { + observe: function PO_observe(aSubject, aTopic, aData) { + logTestInfo("topic: " + aTopic + ", process exitValue: " + + gProcess.exitValue); + if (gAppTimer) { + gAppTimer.cancel(); + gAppTimer = null; + } + if (aTopic != "process-finished" || gProcess.exitValue != 0) { + do_throw("Failed to launch application"); + } + do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished); + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) +}; + +/** + * The timer callback to kill the process if it takes too long. + */ +const gTimerCallback = { + notify: function TC_notify(aTimer) { + gAppTimer = null; + if (gProcess.isRunning) { + logTestInfo("attempt to kill process"); + gProcess.kill(); + } + do_throw("launch application timer expired"); + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) +}; + +/** + * The update-staged observer for the call to nsIUpdateProcessor:processUpdate. + */ +const gUpdateStagedObserver = { + observe: function(aSubject, aTopic, aData) { + if (aTopic == "update-staged") { + Services.obs.removeObserver(gUpdateStagedObserver, "update-staged"); + checkUpdateApplied(); + } + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) +}; + +/** + * Sets the environment that will be used by the application process when it is + * launched. + */ +function setEnvironment() { + // Prevent setting the environment more than once. + if (gShouldResetEnv !== undefined) { + return; + } + + gShouldResetEnv = true; + + let env = Cc["@mozilla.org/process/environment;1"]. + getService(Ci.nsIEnvironment); + if (IS_WIN && !env.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) { + gAddedEnvXRENoWindowsCrashDialog = true; + logTestInfo("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " + + "variable to 1... previously it didn't exist"); + env.set("XRE_NO_WINDOWS_CRASH_DIALOG", "1"); + } + + if (IS_UNIX) { + let appGreBinDir = gGREBinDirOrig.clone(); + let envGreBinDir = Cc["@mozilla.org/file/local;1"]. + createInstance(Ci.nsILocalFile); + let shouldSetEnv = true; + if (IS_MACOSX) { + if (env.exists("DYLD_LIBRARY_PATH")) { + gEnvDyldLibraryPath = env.get("DYLD_LIBRARY_PATH"); + envGreBinDir.initWithPath(gEnvDyldLibraryPath); + if (envGreBinDir.path == appGreBinDir.path) { + gEnvDyldLibraryPath = null; + shouldSetEnv = false; + } + } + + if (shouldSetEnv) { + logTestInfo("setting DYLD_LIBRARY_PATH environment variable value to " + + appGreBinDir.path); + env.set("DYLD_LIBRARY_PATH", appGreBinDir.path); + } + } else { + if (env.exists("LD_LIBRARY_PATH")) { + gEnvLdLibraryPath = env.get("LD_LIBRARY_PATH"); + envGreBinDir.initWithPath(gEnvLdLibraryPath); + if (envGreBinDir.path == appGreBinDir.path) { + gEnvLdLibraryPath = null; + shouldSetEnv = false; + } + } + + if (shouldSetEnv) { + logTestInfo("setting LD_LIBRARY_PATH environment variable value to " + + appGreBinDir.path); + env.set("LD_LIBRARY_PATH", appGreBinDir.path); + } + } + } + + if (env.exists("XPCOM_MEM_LEAK_LOG")) { + gEnvXPCOMMemLeakLog = env.get("XPCOM_MEM_LEAK_LOG"); + logTestInfo("removing the XPCOM_MEM_LEAK_LOG environment variable... " + + "previous value " + gEnvXPCOMMemLeakLog); + env.set("XPCOM_MEM_LEAK_LOG", ""); + } + + if (env.exists("XPCOM_DEBUG_BREAK")) { + gEnvXPCOMDebugBreak = env.get("XPCOM_DEBUG_BREAK"); + logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " + + "warn... previous value " + gEnvXPCOMDebugBreak); + } else { + logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " + + "warn... previously it didn't exist"); + } + + env.set("XPCOM_DEBUG_BREAK", "warn"); + + if (gStageUpdate) { + logTestInfo("setting the MOZ_UPDATE_STAGING environment variable to 1"); + env.set("MOZ_UPDATE_STAGING", "1"); + } + + logTestInfo("setting MOZ_NO_SERVICE_FALLBACK environment variable to 1"); + env.set("MOZ_NO_SERVICE_FALLBACK", "1"); +} + +/** + * Sets the environment back to the original values after launching the + * application. + */ +function resetEnvironment() { + // Prevent resetting the environment more than once. + if (gShouldResetEnv !== true) { + return; + } + + gShouldResetEnv = false; + + let env = Cc["@mozilla.org/process/environment;1"]. + getService(Ci.nsIEnvironment); + + if (gEnvXPCOMMemLeakLog) { + logTestInfo("setting the XPCOM_MEM_LEAK_LOG environment variable back to " + + gEnvXPCOMMemLeakLog); + env.set("XPCOM_MEM_LEAK_LOG", gEnvXPCOMMemLeakLog); + } + + if (gEnvXPCOMDebugBreak) { + logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable back to " + + gEnvXPCOMDebugBreak); + env.set("XPCOM_DEBUG_BREAK", gEnvXPCOMDebugBreak); + } else { + logTestInfo("clearing the XPCOM_DEBUG_BREAK environment variable"); + env.set("XPCOM_DEBUG_BREAK", ""); + } + + if (IS_UNIX) { + if (IS_MACOSX) { + if (gEnvDyldLibraryPath) { + logTestInfo("setting DYLD_LIBRARY_PATH environment variable value " + + "back to " + gEnvDyldLibraryPath); + env.set("DYLD_LIBRARY_PATH", gEnvDyldLibraryPath); + } else { + logTestInfo("removing DYLD_LIBRARY_PATH environment variable"); + env.set("DYLD_LIBRARY_PATH", ""); + } + } else { + if (gEnvLdLibraryPath) { + logTestInfo("setting LD_LIBRARY_PATH environment variable value back " + + "to " + gEnvLdLibraryPath); + env.set("LD_LIBRARY_PATH", gEnvLdLibraryPath); + } else { + logTestInfo("removing LD_LIBRARY_PATH environment variable"); + env.set("LD_LIBRARY_PATH", ""); + } + } + } + + if (IS_WIN && gAddedEnvXRENoWindowsCrashDialog) { + logTestInfo("removing the XRE_NO_WINDOWS_CRASH_DIALOG environment " + + "variable"); + env.set("XRE_NO_WINDOWS_CRASH_DIALOG", ""); + } + + if (gStageUpdate) { + logTestInfo("removing the MOZ_UPDATE_STAGING environment variable"); + env.set("MOZ_UPDATE_STAGING", ""); + } + + logTestInfo("removing MOZ_NO_SERVICE_FALLBACK environment variable"); + env.set("MOZ_NO_SERVICE_FALLBACK", ""); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js b/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js index 191a18a03b..96a85f2ee8 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js @@ -10,7 +10,7 @@ function run_test() { logTestInfo("testing write access to the application directory"); let testFile = getCurrentProcessDir(); testFile.append("update_write_access_test"); - testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); + testFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); do_check_true(testFile.exists()); testFile.remove(false); do_check_false(testFile.exists()); @@ -22,8 +22,8 @@ function run_test() { logTestInfo("attempting to create mutex"); let handle = createMutex(getPerInstallationMutexName()); - logTestInfo("testing that the mutex was successfully created"); - do_check_neq(handle, null); + debugDump("testing that the mutex was successfully created"); + do_check_true(!!handle); // Check if available updates cannot be checked for when there is a mutex // for this installation. @@ -71,14 +71,14 @@ function getPerInstallationMutexName() { do_throw("Windows only function called by a different platform!"); } - let hasher = AUS_Cc["@mozilla.org/security/hash;1"]. - createInstance(AUS_Ci.nsICryptoHash); + let hasher = Cc["@mozilla.org/security/hash;1"]. + createInstance(Ci.nsICryptoHash); hasher.init(hasher.SHA1); - let exeFile = Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsILocalFile); + let exeFile = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsILocalFile); - let converter = AUS_Cc["@mozilla.org/intl/scriptableunicodeconverter"]. - createInstance(AUS_Ci.nsIScriptableUnicodeConverter); + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]. + createInstance(Ci.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; let data = converter.convertToByteArray(exeFile.path.toLowerCase()); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js index 1401336418..f542901afc 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js @@ -11,10 +11,9 @@ function run_test() { logTestInfo("testing removal of an active update for a channel that is not" + "valid due to switching channels (Bug 486275)."); - var patches, updates, update; - patches = getLocalPatchString(null, null, null, null, null, null, - STATE_DOWNLOADING); - updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0"); + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0"); writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); writeStatusFile(STATE_DOWNLOADING); @@ -30,7 +29,7 @@ function run_test() { standardInit(); do_check_eq(gUpdateManager.updateCount, 1); - update = gUpdateManager.getUpdateAt(0); + let update = gUpdateManager.getUpdateAt(0); do_check_eq(update.name, "Existing"); do_check_eq(gUpdateManager.activeUpdate, null); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js index bff4b6b47f..f1cb63461f 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js @@ -10,11 +10,9 @@ function run_test() { logTestInfo("testing cleanup of an update download in progress for an " + "older version of the application on startup (Bug 485624)"); - var patches, updates; - - patches = getLocalPatchString(null, null, null, null, null, null, - STATE_DOWNLOADING); - updates = getLocalUpdateString(patches, null, null, "version 0.9", "0.9"); + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches, null, null, "version 0.9", "0.9"); writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); writeStatusFile(STATE_DOWNLOADING); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js index 2d957c22f3..d33230451e 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js @@ -10,12 +10,10 @@ function run_test() { "same version of the application with the same application " + "build id on startup (Bug 536547)"); - var patches, updates; - - patches = getLocalPatchString(null, null, null, null, null, null, - STATE_DOWNLOADING); - updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0", null, - "2007010101"); + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0", + null, "2007010101"); writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); writeStatusFile(STATE_DOWNLOADING); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js index 9ba640975b..2038f7ab33 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js @@ -10,20 +10,20 @@ function run_test() { "STATE_DOWNLOADING (Bug 539717)."); writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); - var patches = getLocalPatchString(null, null, null, null, null, null, + let patches = getLocalPatchString(null, null, null, null, null, null, STATE_DOWNLOADING); - var updates = getLocalUpdateString(patches); + let updates = getLocalUpdateString(patches); writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); writeStatusFile(STATE_NONE); standardInit(); - var dir = getUpdatesDir(); + let dir = getUpdatesDir(); dir.append("0"); logTestInfo("testing " + dir.path + " should exist"); do_check_true(dir.exists()); - var statusFile = dir.clone(); + let statusFile = dir.clone(); statusFile.append(FILE_UPDATE_STATUS); logTestInfo("testing " + statusFile.path + " should not exist"); do_check_false(statusFile.exists()); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js index 3f8aae6c6f..58c532ad8c 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js @@ -10,9 +10,9 @@ function run_test() { "update xml has an update with STATE_PENDING (Bug 601701)."); writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); - var patches = getLocalPatchString(null, null, null, null, null, null, + let patches = getLocalPatchString(null, null, null, null, null, null, STATE_PENDING); - var updates = getLocalUpdateString(patches); + let updates = getLocalUpdateString(patches); writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); writeVersionFile("99.9"); @@ -25,12 +25,12 @@ function run_test() { logTestInfo("testing updateCount == 0"); do_check_eq(gUpdateManager.updateCount, 0); - var dir = getUpdatesDir(); + let dir = getUpdatesDir(); dir.append("0"); logTestInfo("testing " + dir.path + " should exist"); do_check_true(dir.exists()); - var versionFile = dir.clone(); + let versionFile = dir.clone(); versionFile.append(FILE_UPDATE_VERSION); logTestInfo("testing " + versionFile.path + " should not exist"); do_check_false(versionFile.exists()); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js index 09858461cc..8ae2ec2093 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js @@ -9,14 +9,14 @@ function run_test() { logTestInfo("testing that the update.log is moved after a successful update"); writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); - var patches = getLocalPatchString(null, null, null, null, null, null, + let patches = getLocalPatchString(null, null, null, null, null, null, STATE_PENDING); - var updates = getLocalUpdateString(patches); + let updates = getLocalUpdateString(patches); writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); writeStatusFile(STATE_SUCCEEDED); - var dir = getUpdatesDir(); - var log = dir.clone(); + let dir = getUpdatesDir(); + let log = dir.clone(); log.append("0"); log.append(FILE_UPDATE_LOG); writeFile(log, "Last Update Log"); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js index 4991561fbc..378139f4f7 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js @@ -9,14 +9,14 @@ function run_test() { logTestInfo("testing update logs are first in first out deleted"); writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); - var patches = getLocalPatchString(null, null, null, null, null, null, + let patches = getLocalPatchString(null, null, null, null, null, null, STATE_PENDING); - var updates = getLocalUpdateString(patches); + let updates = getLocalUpdateString(patches); writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); writeStatusFile(STATE_SUCCEEDED); - var dir = getUpdatesDir(); - var log = dir.clone(); + let dir = getUpdatesDir(); + let log = dir.clone(); log.append(FILE_LAST_LOG); writeFile(log, "Backup Update Log"); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js index f42a6e30ce..f1c9560d39 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js @@ -32,12 +32,12 @@ function callHandleEvent() { gXHR.status = 400; gXHR.responseText = gResponseBody; try { - var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"]. - createInstance(AUS_Ci.nsIDOMParser); + let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml"); } catch(e) { } - var e = { target: gXHR }; + let e = { target: gXHR }; gXHR.onload(e); } @@ -57,10 +57,11 @@ function run_test_helper_pt1(aMsg, aExpectedStatusResult, aNextRunFunc) { function check_test_helper_pt1_1() { do_check_eq(gUpdateCount, 1); gCheckFunc = check_test_helper_pt1_2; - var bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); - var state = gAUS.downloadUpdate(bestUpdate, false); - if (state == STATE_NONE || state == STATE_FAILED) + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); + let state = gAUS.downloadUpdate(bestUpdate, false); + if (state == STATE_NONE || state == STATE_FAILED) { do_throw("nsIApplicationUpdateService:downloadUpdate returned " + state); + } gAUS.addDownloadListener(downloadListener); } @@ -87,16 +88,17 @@ function run_test_helper_bug828858_pt1(aMsg, aExpectedStatusResult, aNextRunFunc function check_test_helper_bug828858_pt1_1() { do_check_eq(gUpdateCount, 1); gCheckFunc = check_test_helper_bug828858_pt1_2; - var bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); - var state = gAUS.downloadUpdate(bestUpdate, false); - if (state == STATE_NONE || state == STATE_FAILED) + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); + let state = gAUS.downloadUpdate(bestUpdate, false); + if (state == STATE_NONE || state == STATE_FAILED) { do_throw("nsIApplicationUpdateService:downloadUpdate returned " + state); + } gAUS.addDownloadListener(downloadListener); } function check_test_helper_bug828858_pt1_2() { - if (gStatusResult == AUS_Cr.NS_ERROR_CONTENT_CORRUPTED) { - do_check_eq(gStatusResult, AUS_Cr.NS_ERROR_CONTENT_CORRUPTED); + if (gStatusResult == Cr.NS_ERROR_CONTENT_CORRUPTED) { + do_check_eq(gStatusResult, Cr.NS_ERROR_CONTENT_CORRUPTED); } else { do_check_eq(gStatusResult, gExpectedStatusResult); } @@ -105,9 +107,9 @@ function check_test_helper_bug828858_pt1_2() { } function setResponseBody(aHashFunction, aHashValue, aSize) { - var patches = getRemotePatchString(null, null, + let patches = getRemotePatchString(null, null, aHashFunction, aHashValue, aSize); - var updates = getRemoteUpdateString(patches); + let updates = getRemoteUpdateString(patches); gResponseBody = getRemoteUpdatesXMLString(updates); } @@ -115,79 +117,79 @@ function setResponseBody(aHashFunction, aHashValue, aSize) { function run_test_pt1() { setResponseBody("MD5", MD5_HASH_SIMPLE_MAR); run_test_helper_pt1("mar download with a valid MD5 hash", - AUS_Cr.NS_OK, run_test_pt2); + Cr.NS_OK, run_test_pt2); } // mar download with an invalid MD5 hash function run_test_pt2() { setResponseBody("MD5", MD5_HASH_SIMPLE_MAR + "0"); run_test_helper_pt1("mar download with an invalid MD5 hash", - AUS_Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt3); + Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt3); } // mar download with a valid SHA1 hash function run_test_pt3() { setResponseBody("SHA1", SHA1_HASH_SIMPLE_MAR); run_test_helper_pt1("mar download with a valid SHA1 hash", - AUS_Cr.NS_OK, run_test_pt4); + Cr.NS_OK, run_test_pt4); } // mar download with an invalid SHA1 hash function run_test_pt4() { setResponseBody("SHA1", SHA1_HASH_SIMPLE_MAR + "0"); run_test_helper_pt1("mar download with an invalid SHA1 hash", - AUS_Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt5); + Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt5); } // mar download with a valid SHA256 hash function run_test_pt5() { setResponseBody("SHA256", SHA256_HASH_SIMPLE_MAR); run_test_helper_pt1("mar download with a valid SHA256 hash", - AUS_Cr.NS_OK, run_test_pt6); + Cr.NS_OK, run_test_pt6); } // mar download with an invalid SHA256 hash function run_test_pt6() { setResponseBody("SHA256", SHA256_HASH_SIMPLE_MAR + "0"); run_test_helper_pt1("mar download with an invalid SHA256 hash", - AUS_Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt7); + Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt7); } // mar download with a valid SHA384 hash function run_test_pt7() { setResponseBody("SHA384", SHA384_HASH_SIMPLE_MAR); run_test_helper_pt1("mar download with a valid SHA384 hash", - AUS_Cr.NS_OK, run_test_pt8); + Cr.NS_OK, run_test_pt8); } // mar download with an invalid SHA384 hash function run_test_pt8() { setResponseBody("SHA384", SHA384_HASH_SIMPLE_MAR + "0"); run_test_helper_pt1("mar download with an invalid SHA384 hash", - AUS_Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt9); + Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt9); } // mar download with a valid SHA512 hash function run_test_pt9() { setResponseBody("SHA512", SHA512_HASH_SIMPLE_MAR); run_test_helper_pt1("mar download with a valid SHA512 hash", - AUS_Cr.NS_OK, run_test_pt10); + Cr.NS_OK, run_test_pt10); } // mar download with an invalid SHA512 hash function run_test_pt10() { setResponseBody("SHA512", SHA512_HASH_SIMPLE_MAR + "0"); run_test_helper_pt1("mar download with an invalid SHA512 hash", - AUS_Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt11); + Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt11); } // mar download with the mar not found function run_test_pt11() { - var patches = getRemotePatchString(null, gURLData + "missing.mar"); - var updates = getRemoteUpdateString(patches); + let patches = getRemotePatchString(null, gURLData + "missing.mar"); + let updates = getRemoteUpdateString(patches); gResponseBody = getRemoteUpdatesXMLString(updates); run_test_helper_pt1("mar download with the mar not found", - AUS_Cr.NS_ERROR_UNEXPECTED, run_test_pt12); + Cr.NS_ERROR_UNEXPECTED, run_test_pt12); } // mar download with a valid MD5 hash but invalid file size @@ -202,9 +204,9 @@ function run_test_pt12() { // NS_ERROR_CONTENT_CORRUPTED. // Bug 828858 was filed to follow up on this issue. run_test_helper_bug828858_pt1("mar download with a valid MD5 hash but invalid file size", - AUS_Cr.NS_ERROR_UNEXPECTED, finish_test); + Cr.NS_ERROR_UNEXPECTED, finish_test); } else { run_test_helper_pt1("mar download with a valid MD5 hash but invalid file size", - AUS_Cr.NS_ERROR_UNEXPECTED, finish_test); + Cr.NS_ERROR_UNEXPECTED, finish_test); } } diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js index 17d44686e5..e6eee6e4c3 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js @@ -13,7 +13,7 @@ function run_test() { Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false); - let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), "Fake Window Watcher", "@mozilla.org/embedcomp/window-watcher;1", @@ -34,18 +34,18 @@ function run_test() { let update = gUpdateManager.activeUpdate; update.errorCode = WRITE_ERROR; - let prompter = AUS_Cc["@mozilla.org/updates/update-prompt;1"]. - createInstance(AUS_Ci.nsIUpdatePrompt); + let prompter = Cc["@mozilla.org/updates/update-prompt;1"]. + createInstance(Ci.nsIUpdatePrompt); prompter.showUpdateError(update); } function end_test() { - let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), WindowWatcherFactory); } -var WindowWatcher = { +const WindowWatcher = { getNewPrompter: function(aParent) { do_check_eq(aParent, null); return { @@ -62,19 +62,14 @@ var WindowWatcher = { }; }, - QueryInterface: function(iid) { - if (iid.equals(AUS_Ci.nsIWindowWatcher) || - iid.equals(AUS_Ci.nsISupports)) - return this; + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]) +}; - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - } -} - -var WindowWatcherFactory = { - createInstance: function createInstance(outer, iid) { - if (outer != null) - throw AUS_Cr.NS_ERROR_NO_AGGREGATION; - return WindowWatcher.QueryInterface(iid); +const WindowWatcherFactory = { + createInstance: function createInstance(aOuter, aIID) { + if (aOuter != null) { + throw Cr.NS_ERROR_NO_AGGREGATION; + } + return WindowWatcher.QueryInterface(aIID); } }; diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js index 0c7c3ed723..bd54273725 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js @@ -10,21 +10,6 @@ let gDirService; let gDirProvider; let gOldProviders; -function FakeDirProvider() {} -FakeDirProvider.prototype = { - classID: Components.ID("{f30b43a7-2bfa-4e5f-8c4f-abc7dd4ac486}"), - QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIDirectoryServiceProvider]), - - getFile: function(prop, persistent) { - if (prop == KEY_UPDATE_ARCHIVE_DIR) { - if (gActiveUpdate) { - gActiveUpdate.errorCode = AUS_Cr.NS_ERROR_FILE_TOO_BIG; - } - } - return null; - } -}; - function run_test() { setupTestCommon(); @@ -37,19 +22,19 @@ function run_test() { gDirProvider = new FakeDirProvider(); - let cm = AUS_Cc["@mozilla.org/categorymanager;1"].getService(AUS_Ci.nsICategoryManager); + let cm = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager); gOldProviders = []; let enumerator = cm.enumerateCategory("xpcom-directory-providers"); while (enumerator.hasMoreElements()) { - let entry = enumerator.getNext().QueryInterface(AUS_Ci.nsISupportsCString).data; + let entry = enumerator.getNext().QueryInterface(Ci.nsISupportsCString).data; let contractID = cm.getCategoryEntry("xpcom-directory-providers", entry); - gOldProviders.push(AUS_Cc[contractID].createInstance(AUS_Ci.nsIDirectoryServiceProvider)); + gOldProviders.push(Cc[contractID].createInstance(Ci.nsIDirectoryServiceProvider)); } - gDirService = AUS_Cc["@mozilla.org/file/directory_service;1"] - .getService(AUS_Ci.nsIProperties); + gDirService = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties); - gOldProviders.forEach(function (p) { + gOldProviders.forEach(function(p) { gDirService.unregisterProvider(p); }); gDirService.registerProvider(gDirProvider); @@ -62,13 +47,13 @@ function xhr_pt1() { gXHR.status = 200; gXHR.responseText = gResponseBody; try { - var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"]. - createInstance(AUS_Ci.nsIDOMParser); + let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml"); } catch (e) { gXHR.responseXML = null; } - var e = { target: gXHR }; + let e = { target: gXHR }; gXHR.onload(e); } @@ -92,17 +77,31 @@ function check_test_pt1() { let state = gAUS.downloadUpdate(gActiveUpdate, true); do_check_eq(state, "null"); - do_check_eq(gActiveUpdate.errorCode >>> 0 , AUS_Cr.NS_ERROR_FILE_TOO_BIG); + do_check_eq(gActiveUpdate.errorCode >>> 0 , Cr.NS_ERROR_FILE_TOO_BIG); doTestFinish(); } function end_test() { gDirService.unregisterProvider(gDirProvider); - gOldProviders.forEach(function (p) { + gOldProviders.forEach(function(p) { gDirService.registerProvider(p); }); gActiveUpdate = null; gDirService = null; gDirProvider = null; } + +function FakeDirProvider() {} +FakeDirProvider.prototype = { + getFile: function(prop, persistent) { + if (prop == KEY_UPDATE_ARCHIVE_DIR) { + if (gActiveUpdate) { + gActiveUpdate.errorCode = Cr.NS_ERROR_FILE_TOO_BIG; + } + } + return null; + }, + classID: Components.ID("{f30b43a7-2bfa-4e5f-8c4f-abc7dd4ac486}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]) +}; diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedByOfflineRetry.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedByOfflineRetry.js index 87aa62fe78..7375f2c684 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedByOfflineRetry.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedByOfflineRetry.js @@ -31,12 +31,12 @@ function run_test_pt1() { } function xhr_pt1() { - gXHR.status = AUS_Cr.NS_ERROR_OFFLINE; + gXHR.status = Cr.NS_ERROR_OFFLINE; gXHR.onerror({ target: gXHR }); } function check_test_pt1(request, update) { - do_check_eq(gStatusCode, AUS_Cr.NS_ERROR_OFFLINE); + do_check_eq(gStatusCode, Cr.NS_ERROR_OFFLINE); do_check_eq(update.errorCode, NETWORK_ERROR_OFFLINE); // Forward the error to AUS, which should register the online observer @@ -47,22 +47,22 @@ function check_test_pt1(request, update) { Services.obs.notifyObservers(gAUS, "network:offline-status-changed", "online"); } -var updatePrompt = { +const updatePrompt = { showUpdateAvailable: function(update) { check_test_pt2(update); } }; function xhr_pt2() { - var patches = getLocalPatchString(); - var updates = getLocalUpdateString(patches); - var responseBody = getLocalUpdatesXMLString(updates); + let patches = getLocalPatchString(); + let updates = getLocalUpdateString(patches); + let responseBody = getLocalUpdatesXMLString(updates); gXHR.status = 200; gXHR.responseText = responseBody; try { - var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"]. - createInstance(AUS_Ci.nsIDOMParser); + let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); gXHR.responseXML = parser.parseFromString(responseBody, "application/xml"); } catch (e) { } diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js index 982ae0a0dc..8570cd3e14 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js @@ -46,12 +46,12 @@ function callHandleEvent() { gXHR.status = 400; gXHR.responseText = gResponseBody; try { - var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"]. - createInstance(AUS_Ci.nsIDOMParser); + let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml"); } catch (e) { } - var e = { target: gXHR }; + let e = { target: gXHR }; gXHR.onload(e); } @@ -71,10 +71,11 @@ function run_test_helper_pt1(aMsg, aExpectedStatusResult, aNextRunFunc) { function check_test_helper_pt1_1() { do_check_eq(gUpdateCount, 1); gCheckFunc = check_test_helper_pt1_2; - var bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); - var state = gAUS.downloadUpdate(bestUpdate, false); - if (state == STATE_NONE || state == STATE_FAILED) + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); + let state = gAUS.downloadUpdate(bestUpdate, false); + if (state == STATE_NONE || state == STATE_FAILED) { do_throw("nsIApplicationUpdateService:downloadUpdate returned " + state); + } gAUS.addDownloadListener(downloadListener); } @@ -85,38 +86,38 @@ function check_test_helper_pt1_2() { } function setResponseBody(aHashFunction, aHashValue, aSize) { - var patches = getRemotePatchString(null, null, + let patches = getRemotePatchString(null, null, aHashFunction, aHashValue, aSize); - var updates = getRemoteUpdateString(patches); + let updates = getRemoteUpdateString(patches); gResponseBody = getRemoteUpdatesXMLString(updates); } -var newFactory = { +const newFactory = { createInstance: function(aOuter, aIID) { - if (aOuter) - throw Components.results.NS_ERROR_NO_AGGREGATION; + if (aOuter) { + throw Cr.NS_ERROR_NO_AGGREGATION; + } return new IncrementalDownload().QueryInterface(aIID); }, lockFactory: function(aLock) { - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + throw Cr.NS_ERROR_NOT_IMPLEMENTED; }, - QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIFactory]) + QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]) }; function initMockIncrementalDownload() { - var registrar = AUS_Cm.QueryInterface(AUS_Ci.nsIComponentRegistrar); + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); gIncrementalDownloadClassID = registrar.contractIDToCID(INC_CONTRACT_ID); - gIncOldFactory = AUS_Cm.getClassObject(AUS_Cc[INC_CONTRACT_ID], - AUS_Ci.nsIFactory); + gIncOldFactory = Cm.getClassObject(Cc[INC_CONTRACT_ID], Ci.nsIFactory); registrar.unregisterFactory(gIncrementalDownloadClassID, gIncOldFactory); - var components = [IncrementalDownload]; + let components = [IncrementalDownload]; registrar.registerFactory(gIncrementalDownloadClassID, "", INC_CONTRACT_ID, newFactory); } function cleanupMockIncrementalDownload() { if (gIncOldFactory) { - var registrar = AUS_Cm.QueryInterface(AUS_Ci.nsIComponentRegistrar); + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); registrar.unregisterFactory(gIncrementalDownloadClassID, newFactory); registrar.registerFactory(gIncrementalDownloadClassID, "", INC_CONTRACT_ID, gIncOldFactory); @@ -135,8 +136,6 @@ function IncrementalDownload() { } IncrementalDownload.prototype = { - QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIIncrementalDownload]), - /* nsIIncrementalDownload */ init: function(uri, file, chunkSize, intervalInSeconds) { this._destination = file; @@ -145,45 +144,45 @@ IncrementalDownload.prototype = { }, start: function(observer, ctxt) { - var tm = Components.classes["@mozilla.org/thread-manager;1"]. - getService(AUS_Ci.nsIThreadManager); + let tm = Cc["@mozilla.org/thread-manager;1"]. + getService(Ci.nsIThreadManager); // Do the actual operation async to give a chance for observers // to add themselves. tm.mainThread.dispatch(function() { - this._observer = observer.QueryInterface(AUS_Ci.nsIRequestObserver); + this._observer = observer.QueryInterface(Ci.nsIRequestObserver); this._ctxt = ctxt; this._observer.onStartRequest(this, this._ctxt); let mar = getTestDirFile(FILE_SIMPLE_MAR); mar.copyTo(this._destination.parent, this._destination.leafName); - var status = AUS_Cr.NS_OK + let status = Cr.NS_OK switch (gIncrementalDownloadErrorType++) { case 0: - status = AUS_Cr.NS_ERROR_NET_RESET; - break; + status = Cr.NS_ERROR_NET_RESET; + break; case 1: - status = AUS_Cr.NS_ERROR_CONNECTION_REFUSED; - break; + status = Cr.NS_ERROR_CONNECTION_REFUSED; + break; case 2: - status = AUS_Cr.NS_ERROR_NET_RESET; - break; + status = Cr.NS_ERROR_NET_RESET; + break; case 3: - status = AUS_Cr.NS_OK; + status = Cr.NS_OK; break; case 4: - status = AUS_Cr.NS_ERROR_OFFLINE; + status = Cr.NS_ERROR_OFFLINE; // After we report offline, we want to eventually show offline // status being changed to online. - var tm = Components.classes["@mozilla.org/thread-manager;1"]. - getService(AUS_Ci.nsIThreadManager); + let tm = Cc["@mozilla.org/thread-manager;1"]. + getService(Ci.nsIThreadManager); tm.mainThread.dispatch(function() { Services.obs.notifyObservers(gAUS, "network:offline-status-changed", "online"); - }, AUS_Ci.nsIThread.DISPATCH_NORMAL); - break; + }, Ci.nsIThread.DISPATCH_NORMAL); + break; } this._observer.onStopRequest(this, this._ctxt, status); - }.bind(this), AUS_Ci.nsIThread.DISPATCH_NORMAL); + }.bind(this), Ci.nsIThread.DISPATCH_NORMAL); }, get URI() { @@ -191,7 +190,7 @@ IncrementalDownload.prototype = { }, get currentSize() { - throw AUS_Cr.NS_ERROR_NOT_IMPLEMENTED; + throw Cr.NS_ERROR_NOT_IMPLEMENTED; }, get destination() { @@ -203,18 +202,18 @@ IncrementalDownload.prototype = { }, get totalSize() { - throw AUS_Cr.NS_ERROR_NOT_IMPLEMENTED; + throw Cr.NS_ERROR_NOT_IMPLEMENTED; }, /* nsIRequest */ cancel: function(aStatus) { - throw AUS_Cr.NS_ERROR_NOT_IMPLEMENTED; + throw Cr.NS_ERROR_NOT_IMPLEMENTED; }, suspend: function() { - throw AUS_Cr.NS_ERROR_NOT_IMPLEMENTED; + throw Cr.NS_ERROR_NOT_IMPLEMENTED; }, isPending: function() { - throw AUS_Cr.NS_ERROR_NOT_IMPLEMENTED; + throw Cr.NS_ERROR_NOT_IMPLEMENTED; }, _loadFlags: 0, get loadFlags() { @@ -240,15 +239,16 @@ IncrementalDownload.prototype = { _status: 0, get status() { return this._status; - } -} + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIIncrementalDownload]) +}; // Test disconnecting during an update function run_test_pt1() { initMockIncrementalDownload(); setResponseBody("MD5", MD5_HASH_SIMPLE_MAR); run_test_helper_pt1("mar download with connection interruption", - AUS_Cr.NS_OK, run_test_pt2); + Cr.NS_OK, run_test_pt2); } // Test disconnecting during an update @@ -258,15 +258,15 @@ function run_test_pt2() { Services.prefs.setIntPref(PREF_APP_UPDATE_RETRY_TIMEOUT, 0); setResponseBody("MD5", MD5_HASH_SIMPLE_MAR); - var expectedResult; + let expectedResult; if (IS_TOOLKIT_GONK) { // Gonk treats interrupted downloads differently. For gonk, if the state // is pending, this means that the download has completed and only the // staging needs to occur. So gonk will skip the download portion which // results in an NS_OK return. - expectedResult = AUS_Cr.NS_OK; + expectedResult = Cr.NS_OK; } else { - expectedResult = AUS_Cr.NS_ERROR_NET_RESET; + expectedResult = Cr.NS_ERROR_NET_RESET; } run_test_helper_pt1("mar download with connection interruption without recovery", expectedResult, run_test_pt3); @@ -277,5 +277,5 @@ function run_test_pt3() { gIncrementalDownloadErrorType = 4; setResponseBody("MD5", MD5_HASH_SIMPLE_MAR); run_test_helper_pt1("mar download with offline mode", - AUS_Cr.NS_OK, finish_test); + Cr.NS_OK, finish_test); } diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js index 240a46c242..b65404efda 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js @@ -9,11 +9,9 @@ function run_test() { logTestInfo("testing resuming an update download in progress for the same " + "version of the application on startup (Bug 485624)"); - var patches, updates; - - patches = getLocalPatchString(null, null, null, null, null, null, - STATE_DOWNLOADING); - updates = getLocalUpdateString(patches, null, null, "1.0", "1.0"); + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches, null, null, "1.0", "1.0"); writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); writeStatusFile(STATE_DOWNLOADING); @@ -38,5 +36,5 @@ function run_test() { writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); reloadUpdateManagerData(); - do_timeout(TEST_CHECK_TIMEOUT, doTestFinish); + do_execute_soon(doTestFinish); } diff --git a/toolkit/mozapps/update/tests/unit_aus_update/head_update.js b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js index 20666ab700..2db27288e6 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/head_update.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js @@ -1,3747 +1,5 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -'use strict'; - -const INSTALL_LOCALE = "@AB_CD@"; -const MOZ_APP_NAME = "@MOZ_APP_NAME@"; -const BIN_SUFFIX = "@BIN_SUFFIX@"; - -// MOZ_APP_VENDOR is optional. -#ifdef MOZ_APP_VENDOR -const MOZ_APP_VENDOR = "@MOZ_APP_VENDOR@"; -#else -const MOZ_APP_VENDOR = ""; -#endif - -// MOZ_APP_BASENAME is not optional for tests. -const MOZ_APP_BASENAME = "@MOZ_APP_BASENAME@"; -const APP_BIN_SUFFIX = "@BIN_SUFFIX@"; - -const APP_INFO_NAME = "XPCShell"; -const APP_INFO_VENDOR = "Mozilla"; - -#ifdef XP_WIN -const IS_WIN = true; -#else -const IS_WIN = false; -#endif - -#ifdef XP_MACOSX -const IS_MACOSX = true; -#ifdef MOZ_SHARK -const IS_SHARK = true; -#else -const IS_SHARK = false; -#endif -#else -const IS_MACOSX = false; -#endif - -#ifdef XP_UNIX -const IS_UNIX = true; -#else -const IS_UNIX = false; -#endif - -#ifdef ANDROID -const IS_ANDROID = true; -#else -const IS_ANDROID = false; -#endif - -#ifdef MOZ_WIDGET_GONK -const IS_TOOLKIT_GONK = true; -#else -const IS_TOOLKIT_GONK = false; -#endif - -#ifdef XP_MACOSX -const DIR_MACOS = "Contents/MacOS/"; -const DIR_RESOURCES = "Contents/Resources/"; -const FILE_COMPLETE_MAR = "complete_mac.mar"; -const FILE_PARTIAL_MAR = "partial_mac.mar"; -const LOG_COMPLETE_SUCCESS = "complete_log_success_mac"; -const LOG_PARTIAL_SUCCESS = "partial_log_success_mac"; -const LOG_PARTIAL_FAILURE = "partial_log_failure_mac"; -const FILE_COMPLETE_PRECOMPLETE = "complete_precomplete_mac"; -const FILE_PARTIAL_PRECOMPLETE = "partial_precomplete_mac"; -const FILE_COMPLETE_REMOVEDFILES = "complete_removed-files_mac"; -const FILE_PARTIAL_REMOVEDFILES = "partial_removed-files_mac"; -#else -const DIR_MACOS = ""; -const DIR_RESOURCES = ""; -const FILE_COMPLETE_MAR = "complete.mar"; -const FILE_PARTIAL_MAR = "partial.mar"; -const LOG_COMPLETE_SUCCESS = "complete_log_success"; -const LOG_PARTIAL_SUCCESS = "partial_log_success"; -const LOG_PARTIAL_FAILURE = "partial_log_failure"; -const FILE_COMPLETE_PRECOMPLETE = "complete_precomplete"; -const FILE_PARTIAL_PRECOMPLETE = "partial_precomplete"; -const FILE_COMPLETE_REMOVEDFILES = "complete_removed-files"; -const FILE_PARTIAL_REMOVEDFILES = "partial_removed-files"; -#endif - -const USE_EXECV = IS_UNIX && !IS_MACOSX; - -#ifdef MOZ_VERIFY_MAR_SIGNATURE -const IS_MAR_CHECKS_ENABLED = true; -#else -const IS_MAR_CHECKS_ENABLED = false; -#endif - -const URL_HOST = "http://localhost"; - -const FILE_APP_BIN = MOZ_APP_NAME + APP_BIN_SUFFIX; -const FILE_COMPLETE_EXE = "complete.exe"; -const FILE_HELPER_BIN = "TestAUSHelper" + BIN_SUFFIX; -const FILE_MAINTENANCE_SERVICE_BIN = "maintenanceservice.exe"; -const FILE_MAINTENANCE_SERVICE_INSTALLER_BIN = "maintenanceservice_installer.exe"; -const FILE_OLD_VERSION_MAR = "old_version.mar"; -const FILE_PARTIAL_EXE = "partial.exe"; -const FILE_UPDATER_BIN = "updater" + BIN_SUFFIX; -const FILE_WRONG_CHANNEL_MAR = "wrong_product_channel.mar"; - -const LOG_SWITCH_SUCCESS = "rename_file: proceeding to rename the directory\n" + - "rename_file: proceeding to rename the directory\n" + - "Now, remove the tmpDir\n" + - "succeeded\n" + - "calling QuitProgressUI"; - -const ERR_RENAME_FILE = "rename_file: failed to rename file"; -const ERR_UNABLE_OPEN_DEST = "unable to open destination file"; -const ERR_BACKUP_DISCARD = "backup_discard: unable to remove"; - -const LOG_SVC_SUCCESSFUL_LAUNCH = "Process was started... waiting on result."; - -// All we care about is that the last modified time has changed so that Mac OS -// X Launch Services invalidates its cache so the test allows up to one minute -// difference in the last modified time. -const MAC_MAX_TIME_DIFFERENCE = 60000; - -// Time to wait for the test helper process before continuing the test -const TEST_HELPER_TIMEOUT = 100; - -// Time to wait for a check in the test before continuing the test -const TEST_CHECK_TIMEOUT = 100; - -// How many of TEST_CHECK_TIMEOUT to wait before we abort the test. -const MAX_TIMEOUT_RUNS = 2000; - -// Time in seconds the helper application should sleep.the helper's input and output files -const HELPER_SLEEP_TIMEOUT = 180; - -// Maximum number of milliseconds the process that is launched can run before -// the test will try to kill it. -const APP_TIMER_TIMEOUT = 120000; - -#ifdef XP_WIN -const PIPE_TO_NULL = ">nul"; -#else -const PIPE_TO_NULL = "> /dev/null 2>&1"; -#endif - -const LOG_FUNCTION = do_print; - -// This default value will be overridden when using the http server. -var gURLData = URL_HOST + "/"; - -var gTestID; - -var gTestserver; - -var gRegisteredServiceCleanup; - -var gXHR; -var gXHRCallback; - -var gUpdatePrompt; -var gUpdatePromptCallback; - -var gCheckFunc; -var gResponseBody; -var gResponseStatusCode = 200; -var gRequestURL; -var gUpdateCount; -var gUpdates; -var gStatusCode; -var gStatusText; -var gStatusResult; - -var gProcess; -var gAppTimer; -var gHandle; - -var gGREDirOrig; -var gGREBinDirOrig; -var gAppDirOrig; - -var gServiceLaunchedCallbackLog = null; -var gServiceLaunchedCallbackArgs = null; - -// Variables are used instead of contants so tests can override these values if -// necessary. -var gCallbackBinFile = "callback_app" + BIN_SUFFIX; -var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"]; -var gPostUpdateBinFile = "postup_app" + BIN_SUFFIX; -var gStageUpdate = false; -var gSwitchApp = false; -var gDisableReplaceFallback = false; -var gUseTestAppDir = true; - -var gTimeoutRuns = 0; - -// Environment related globals -var gShouldResetEnv = undefined; -var gAddedEnvXRENoWindowsCrashDialog = false; -var gEnvXPCOMDebugBreak; -var gEnvXPCOMMemLeakLog; -var gEnvDyldLibraryPath; -var gEnvLdLibraryPath; - -// Set to true to log additional information for debugging. To log additional -// information for an individual test set DEBUG_AUS_TEST to true in the test's -// run_test function. -var DEBUG_AUS_TEST = true; -// Never set DEBUG_TEST_LOG to true except when running tests locally or on the -// try server since this will force a test that failed a parallel run to fail -// when the same test runs non-parallel so the log from parallel test run can -// be displayed in the log. -var DEBUG_TEST_LOG = false; -// Set to false to keep the log file from the failed parallel test run. -var gDeleteLogFile = true; -var gRealDump; -var gTestLogText = ""; -var gPassed; - -#include ../shared.js - -var gTestFiles = []; -var gTestDirs = []; - -// Common files for both successful and failed updates. -var gTestFilesCommon = [ -{ - description : "Should never change", - fileName : FILE_UPDATE_SETTINGS_INI, - relPathDir : DIR_RESOURCES, - originalContents : UPDATE_SETTINGS_CONTENTS, - compareContents : UPDATE_SETTINGS_CONTENTS, - originalFile : null, - compareFile : null, - originalPerms : 0o767, - comparePerms : 0o767 -}, { - description : "Should never change", - fileName : "channel-prefs.js", - relPathDir : DIR_RESOURCES + "defaults/pref/", - originalContents : "ShouldNotBeReplaced\n", - compareContents : "ShouldNotBeReplaced\n", - originalFile : null, - compareFile : null, - originalPerms : 0o767, - comparePerms : 0o767 -}]; - -// Files for a complete successful update. This can be used for a complete -// failed update by calling setTestFilesAndDirsForFailure. -var gTestFilesCompleteSuccess = [ -{ - description : "Added by update.manifest (add)", - fileName : "precomplete", - relPathDir : DIR_RESOURCES, - originalContents : null, - compareContents : null, - originalFile : FILE_PARTIAL_PRECOMPLETE, - compareFile : FILE_COMPLETE_PRECOMPLETE, - originalPerms : 0o666, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "searchpluginstext0", - relPathDir : DIR_RESOURCES + "searchplugins/", - originalContents : "ToBeReplacedWithFromComplete\n", - compareContents : "FromComplete\n", - originalFile : null, - compareFile : null, - originalPerms : 0o775, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "searchpluginspng1.png", - relPathDir : DIR_RESOURCES + "searchplugins/", - originalContents : null, - compareContents : null, - originalFile : null, - compareFile : "complete.png", - originalPerms : null, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "searchpluginspng0.png", - relPathDir : DIR_RESOURCES + "searchplugins/", - originalContents : null, - compareContents : null, - originalFile : "partial.png", - compareFile : "complete.png", - originalPerms : 0o666, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "removed-files", - relPathDir : DIR_RESOURCES, - originalContents : null, - compareContents : null, - originalFile : FILE_PARTIAL_REMOVEDFILES, - compareFile : FILE_COMPLETE_REMOVEDFILES, - originalPerms : 0o666, - comparePerms : 0o644 -}, { - description : "Added by update.manifest if the parent directory " + - "exists (add-if)", - fileName : "extensions1text0", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents : null, - compareContents : "FromComplete\n", - originalFile : null, - compareFile : null, - originalPerms : null, - comparePerms : 0o644 -}, { - description : "Added by update.manifest if the parent directory " + - "exists (add-if)", - fileName : "extensions1png1.png", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents : null, - compareContents : null, - originalFile : "partial.png", - compareFile : "complete.png", - originalPerms : 0o666, - comparePerms : 0o644 -}, { - description : "Added by update.manifest if the parent directory " + - "exists (add-if)", - fileName : "extensions1png0.png", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents : null, - compareContents : null, - originalFile : null, - compareFile : "complete.png", - originalPerms : null, - comparePerms : 0o644 -}, { - description : "Added by update.manifest if the parent directory " + - "exists (add-if)", - fileName : "extensions0text0", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents : "ToBeReplacedWithFromComplete\n", - compareContents : "FromComplete\n", - originalFile : null, - compareFile : null, - originalPerms : null, - comparePerms : 0o644 -}, { - description : "Added by update.manifest if the parent directory " + - "exists (add-if)", - fileName : "extensions0png1.png", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents : null, - compareContents : null, - originalFile : null, - compareFile : "complete.png", - originalPerms : null, - comparePerms : 0o644 -}, { - description : "Added by update.manifest if the parent directory " + - "exists (add-if)", - fileName : "extensions0png0.png", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents : null, - compareContents : null, - originalFile : null, - compareFile : "complete.png", - originalPerms : null, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "exe0.exe", - relPathDir : DIR_MACOS, - originalContents : null, - compareContents : null, - originalFile : FILE_HELPER_BIN, - compareFile : FILE_COMPLETE_EXE, - originalPerms : 0o777, - comparePerms : 0o755 -}, { - description : "Added by update.manifest (add)", - fileName : "10text0", - relPathDir : DIR_RESOURCES + "1/10/", - originalContents : "ToBeReplacedWithFromComplete\n", - compareContents : "FromComplete\n", - originalFile : null, - compareFile : null, - originalPerms : 0o767, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "0exe0.exe", - relPathDir : DIR_RESOURCES + "0/", - originalContents : null, - compareContents : null, - originalFile : FILE_HELPER_BIN, - compareFile : FILE_COMPLETE_EXE, - originalPerms : 0o777, - comparePerms : 0o755 -}, { - description : "Added by update.manifest (add)", - fileName : "00text1", - relPathDir : DIR_RESOURCES + "0/00/", - originalContents : "ToBeReplacedWithFromComplete\n", - compareContents : "FromComplete\n", - originalFile : null, - compareFile : null, - originalPerms : 0o677, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "00text0", - relPathDir : DIR_RESOURCES + "0/00/", - originalContents : "ToBeReplacedWithFromComplete\n", - compareContents : "FromComplete\n", - originalFile : null, - compareFile : null, - originalPerms : 0o775, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "00png0.png", - relPathDir : DIR_RESOURCES + "0/00/", - originalContents : null, - compareContents : null, - originalFile : null, - compareFile : "complete.png", - originalPerms : 0o776, - comparePerms : 0o644 -}, { - description : "Removed by precomplete (remove)", - fileName : "20text0", - relPathDir : DIR_RESOURCES + "2/20/", - originalContents : "ToBeDeleted\n", - compareContents : null, - originalFile : null, - compareFile : null, - originalPerms : null, - comparePerms : null -}, { - description : "Removed by precomplete (remove)", - fileName : "20png0.png", - relPathDir : DIR_RESOURCES + "2/20/", - originalContents : "ToBeDeleted\n", - compareContents : null, - originalFile : null, - compareFile : null, - originalPerms : null, - comparePerms : null -}]; - -// Concatenate the common files to the end of the array. -gTestFilesCompleteSuccess = gTestFilesCompleteSuccess.concat(gTestFilesCommon); - -// Files for a partial successful update. This can be used for a partial failed -// update by calling setTestFilesAndDirsForFailure. -var gTestFilesPartialSuccess = [ -{ - description : "Added by update.manifest (add)", - fileName : "precomplete", - relPathDir : DIR_RESOURCES, - originalContents : null, - compareContents : null, - originalFile : FILE_COMPLETE_PRECOMPLETE, - compareFile : FILE_PARTIAL_PRECOMPLETE, - originalPerms : 0o666, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "searchpluginstext0", - relPathDir : DIR_RESOURCES + "searchplugins/", - originalContents : "ToBeReplacedWithFromPartial\n", - compareContents : "FromPartial\n", - originalFile : null, - compareFile : null, - originalPerms : 0o775, - comparePerms : 0o644 -}, { - description : "Patched by update.manifest if the file exists " + - "(patch-if)", - fileName : "searchpluginspng1.png", - relPathDir : DIR_RESOURCES + "searchplugins/", - originalContents : null, - compareContents : null, - originalFile : "complete.png", - compareFile : "partial.png", - originalPerms : 0o666, - comparePerms : 0o666 -}, { - description : "Patched by update.manifest if the file exists " + - "(patch-if)", - fileName : "searchpluginspng0.png", - relPathDir : DIR_RESOURCES + "searchplugins/", - originalContents : null, - compareContents : null, - originalFile : "complete.png", - compareFile : "partial.png", - originalPerms : 0o666, - comparePerms : 0o666 -}, { - description : "Added by update.manifest if the parent directory " + - "exists (add-if)", - fileName : "extensions1text0", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents : null, - compareContents : "FromPartial\n", - originalFile : null, - compareFile : null, - originalPerms : null, - comparePerms : 0o644 -}, { - description : "Patched by update.manifest if the parent directory " + - "exists (patch-if)", - fileName : "extensions1png1.png", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents : null, - compareContents : null, - originalFile : "complete.png", - compareFile : "partial.png", - originalPerms : 0o666, - comparePerms : 0o666 -}, { - description : "Patched by update.manifest if the parent directory " + - "exists (patch-if)", - fileName : "extensions1png0.png", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents : null, - compareContents : null, - originalFile : "complete.png", - compareFile : "partial.png", - originalPerms : 0o666, - comparePerms : 0o666 -}, { - description : "Added by update.manifest if the parent directory " + - "exists (add-if)", - fileName : "extensions0text0", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents : "ToBeReplacedWithFromPartial\n", - compareContents : "FromPartial\n", - originalFile : null, - compareFile : null, - originalPerms : 0o644, - comparePerms : 0o644 -}, { - description : "Patched by update.manifest if the parent directory " + - "exists (patch-if)", - fileName : "extensions0png1.png", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents : null, - compareContents : null, - originalFile : "complete.png", - compareFile : "partial.png", - originalPerms : 0o644, - comparePerms : 0o644 -}, { - description : "Patched by update.manifest if the parent directory " + - "exists (patch-if)", - fileName : "extensions0png0.png", - relPathDir : DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents : null, - compareContents : null, - originalFile : "complete.png", - compareFile : "partial.png", - originalPerms : 0o644, - comparePerms : 0o644 -}, { - description : "Patched by update.manifest (patch)", - fileName : "exe0.exe", - relPathDir : DIR_MACOS, - originalContents : null, - compareContents : null, - originalFile : FILE_COMPLETE_EXE, - compareFile : FILE_PARTIAL_EXE, - originalPerms : 0o755, - comparePerms : 0o755 -}, { - description : "Patched by update.manifest (patch)", - fileName : "0exe0.exe", - relPathDir : DIR_RESOURCES + "0/", - originalContents : null, - compareContents : null, - originalFile : FILE_COMPLETE_EXE, - compareFile : FILE_PARTIAL_EXE, - originalPerms : 0o755, - comparePerms : 0o755 -}, { - description : "Added by update.manifest (add)", - fileName : "00text0", - relPathDir : DIR_RESOURCES + "0/00/", - originalContents : "ToBeReplacedWithFromPartial\n", - compareContents : "FromPartial\n", - originalFile : null, - compareFile : null, - originalPerms : 0o644, - comparePerms : 0o644 -}, { - description : "Patched by update.manifest (patch)", - fileName : "00png0.png", - relPathDir : DIR_RESOURCES + "0/00/", - originalContents : null, - compareContents : null, - originalFile : "complete.png", - compareFile : "partial.png", - originalPerms : 0o666, - comparePerms : 0o666 -}, { - description : "Added by update.manifest (add)", - fileName : "20text0", - relPathDir : DIR_RESOURCES + "2/20/", - originalContents : null, - compareContents : "FromPartial\n", - originalFile : null, - compareFile : null, - originalPerms : null, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "20png0.png", - relPathDir : DIR_RESOURCES + "2/20/", - originalContents : null, - compareContents : null, - originalFile : null, - compareFile : "partial.png", - originalPerms : null, - comparePerms : 0o644 -}, { - description : "Added by update.manifest (add)", - fileName : "00text2", - relPathDir : DIR_RESOURCES + "0/00/", - originalContents : null, - compareContents : "FromPartial\n", - originalFile : null, - compareFile : null, - originalPerms : null, - comparePerms : 0o644 -}, { - description : "Removed by update.manifest (remove)", - fileName : "10text0", - relPathDir : DIR_RESOURCES + "1/10/", - originalContents : "ToBeDeleted\n", - compareContents : null, - originalFile : null, - compareFile : null, - originalPerms : null, - comparePerms : null -}, { - description : "Removed by update.manifest (remove)", - fileName : "00text1", - relPathDir : DIR_RESOURCES + "0/00/", - originalContents : "ToBeDeleted\n", - compareContents : null, - originalFile : null, - compareFile : null, - originalPerms : null, - comparePerms : null -}]; - -// Concatenate the common files to the end of the array. -gTestFilesPartialSuccess = gTestFilesPartialSuccess.concat(gTestFilesCommon); - -var gTestDirsCommon = [ -{ - relPathDir : DIR_RESOURCES + "3/", - dirRemoved : false, - files : ["3text0", "3text1"], - filesRemoved : true -}, { - relPathDir : DIR_RESOURCES + "4/", - dirRemoved : true, - files : ["4text0", "4text1"], - filesRemoved : true -}, { - relPathDir : DIR_RESOURCES + "5/", - dirRemoved : true, - files : ["5test.exe", "5text0", "5text1"], - filesRemoved : true -}, { - relPathDir : DIR_RESOURCES + "6/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "7/", - dirRemoved : true, - files : ["7text0", "7text1"], - subDirs : ["70/", "71/"], - subDirFiles : ["7xtest.exe", "7xtext0", "7xtext1"] -}, { - relPathDir : DIR_RESOURCES + "8/", - dirRemoved : false -}, { - relPathDir : DIR_RESOURCES + "8/80/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "8/81/", - dirRemoved : false, - files : ["81text0", "81text1"] -}, { - relPathDir : DIR_RESOURCES + "8/82/", - dirRemoved : false, - subDirs : ["820/", "821/"] -}, { - relPathDir : DIR_RESOURCES + "8/83/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "8/84/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "8/85/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "8/86/", - dirRemoved : true, - files : ["86text0", "86text1"] -}, { - relPathDir : DIR_RESOURCES + "8/87/", - dirRemoved : true, - subDirs : ["870/", "871/"], - subDirFiles : ["87xtext0", "87xtext1"] -}, { - relPathDir : DIR_RESOURCES + "8/88/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "8/89/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "9/90/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "9/91/", - dirRemoved : false, - files : ["91text0", "91text1"] -}, { - relPathDir : DIR_RESOURCES + "9/92/", - dirRemoved : false, - subDirs : ["920/", "921/"] -}, { - relPathDir : DIR_RESOURCES + "9/93/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "9/94/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "9/95/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "9/96/", - dirRemoved : true, - files : ["96text0", "96text1"] -}, { - relPathDir : DIR_RESOURCES + "9/97/", - dirRemoved : true, - subDirs : ["970/", "971/"], - subDirFiles : ["97xtext0", "97xtext1"] -}, { - relPathDir : DIR_RESOURCES + "9/98/", - dirRemoved : true -}, { - relPathDir : DIR_RESOURCES + "9/99/", - dirRemoved : true -}]; - -// Directories for a complete successful update. This array can be used for a -// complete failed update by calling setTestFilesAndDirsForFailure. -var gTestDirsCompleteSuccess = [ -{ - description : "Removed by precomplete (rmdir)", - relPathDir : DIR_RESOURCES + "2/20/", - dirRemoved : true -}, { - description : "Removed by precomplete (rmdir)", - relPathDir : DIR_RESOURCES + "2/", - dirRemoved : true -}]; - -// Concatenate the common files to the beginning of the array. -gTestDirsCompleteSuccess = gTestDirsCommon.concat(gTestDirsCompleteSuccess); - -// Directories for a partial successful update. This array can be used for a -// partial failed update by calling setTestFilesAndDirsForFailure. -var gTestDirsPartialSuccess = [ -{ - description : "Removed by update.manifest (rmdir)", - relPathDir : DIR_RESOURCES + "1/10/", - dirRemoved : true -}, { - description : "Removed by update.manifest (rmdir)", - relPathDir : DIR_RESOURCES + "1/", - dirRemoved : true -}]; - -// Concatenate the common files to the beginning of the array. -gTestDirsPartialSuccess = gTestDirsCommon.concat(gTestDirsPartialSuccess); - -// This makes it possible to run most tests on xulrunner where the update -// channel default preference is not set. -if (MOZ_APP_NAME == "xulrunner") { - try { - gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); - } catch (e) { - setUpdateChannel("test_channel"); - } -} - -/** - * Helper function for setting up the test environment. - */ -function setupTestCommon() { - logTestInfo("start - general test setup"); - - do_test_pending(); - - if (gTestID) { - do_throw("setupTestCommon should only be called once!"); - } - - let caller = Components.stack.caller; - gTestID = caller.filename.toString().split("/").pop().split(".")[0]; - - if (DEBUG_TEST_LOG) { - let logFile = do_get_file(gTestID + ".log", true); - if (logFile.exists()) { - gPassed = false; - logTestInfo("start - dumping previous test run log"); - logTestInfo("\n" + readFile(logFile) + "\n"); - logTestInfo("finish - dumping previous test run log"); - if (gDeleteLogFile) { - logFile.remove(false); - } - do_throw("The parallel run of this test failed. Failing non-parallel " + - "test so the log from the parallel run can be displayed in " + - "non-parallel log.") - } else { - gRealDump = dump; - dump = dumpOverride; - } - } - - // Don't attempt to show a prompt when an update finishes. - Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true); - - gGREDirOrig = getGREDir(); - gGREBinDirOrig = getGREBinDir(); - gAppDirOrig = getAppBaseDir(); - - let applyDir = getApplyDirFile(null, true).parent; - - // Try to remove the directory used to apply updates and the updates directory - // on platforms other than Windows. Since the test hasn't ran yet and the - // directory shouldn't exist finished this is non-fatal for the test. - if (applyDir.exists()) { - logTestInfo("attempting to remove directory. Path: " + applyDir.path); - try { - removeDirRecursive(applyDir); - } catch (e) { - logTestInfo("non-fatal error removing directory. Path: " + - applyDir.path + ", Exception: " + e); - } - } - - // adjustGeneralPaths registers a cleanup function that calls end_test when - // it is defined as a function. - adjustGeneralPaths(); - - // Remove the updates directory on Windows and Mac OS X which is located - // outside of the application directory after the call to adjustGeneralPaths - // has set it up. Since the test hasn't ran yet and the directory shouldn't - // exist this is non-fatal for the test. - if (IS_WIN || IS_MACOSX) { - let updatesDir = getMockUpdRootD(); - if (updatesDir.exists()) { - logTestInfo("attempting to remove directory. Path: " + updatesDir.path); - try { - removeDirRecursive(updatesDir); - } catch (e) { - logTestInfo("non-fatal error removing directory. Path: " + - updatesDir.path + ", Exception: " + e); - } - } - } - - logTestInfo("finish - general test setup"); -} - -/** - * Nulls out the most commonly used global vars used by tests to prevent leaks - * as needed and attempts to restore the system to its original state. - */ -function cleanupTestCommon() { - logTestInfo("start - general test cleanup"); - - // Force the update manager to reload the update data to prevent it from - // writing the old data to the files that have just been removed. - reloadUpdateManagerData(); - - if (gChannel) { - gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer); - } - - // Call app update's observe method passing xpcom-shutdown to test that the - // shutdown of app update runs without throwing or leaking. The observer - // method is used directly instead of calling notifyObservers so components - // outside of the scope of this test don't assert and thereby cause app update - // tests to fail. - gAUS.observe(null, "xpcom-shutdown", ""); - - if (gXHR) { - gXHRCallback = null; - - gXHR.responseXML = null; - // null out the event handlers to prevent a mFreeCount leak of 1 - gXHR.onerror = null; - gXHR.onload = null; - gXHR.onprogress = null; - - gXHR = null; - } - - gTestserver = null; - - if (IS_UNIX) { - // This will delete the launch script if it exists. - getLaunchScript(); - } - - if (IS_WIN && MOZ_APP_BASENAME) { - let appDir = getApplyDirFile(null, true); - let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla"; - const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME + - "\\TaskBarIDs"; - let key = AUS_Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(AUS_Ci.nsIWindowsRegKey); - try { - key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, - AUS_Ci.nsIWindowsRegKey.ACCESS_ALL); - if (key.hasValue(appDir.path)) { - key.removeValue(appDir.path); - } - } catch (e) { - } - try { - key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH, - AUS_Ci.nsIWindowsRegKey.ACCESS_ALL); - if (key.hasValue(appDir.path)) { - key.removeValue(appDir.path); - } - } catch (e) { - } - } - - // The updates directory is located outside of the application directory on - // Windows and Mac OS X so it also needs to be removed. - if (IS_WIN || IS_MACOSX) { - let updatesDir = getMockUpdRootD(); - // Try to remove the directory used to apply updates. Since the test has - // already finished this is non-fatal for the test. - if (updatesDir.exists()) { - logTestInfo("attempting to remove directory. Path: " + updatesDir.path); - try { - removeDirRecursive(updatesDir); - } catch (e) { - logTestInfo("non-fatal error removing directory. Path: " + - updatesDir.path + ", Exception: " + e); - } - if (IS_MACOSX) { - let updatesRootDir = gUpdatesRootDir.clone(); - while (updatesRootDir.path != updatesDir.path) { - if (updatesDir.exists()) { - logTestInfo("attempting to remove directory. Path: " + - updatesDir.path); - try { - // Try to remove the directory without the recursive flag set - // since the top level directory has already had its contents - // removed and the parent directory might still be used by a - // different test. - updatesDir.remove(false); - } catch (e) { - logTestInfo("non-fatal error removing directory. Path: " + - updatesDir.path + ", Exception: " + e); - } - } - updatesDir = updatesDir.parent; - } - } - } - } - - let applyDir = getApplyDirFile(null, true).parent; - - // Try to remove the directory used to apply updates. Since the test has - // already finished this is non-fatal for the test. - if (applyDir.exists()) { - logTestInfo("attempting to remove directory. Path: " + applyDir.path); - try { - removeDirRecursive(applyDir); - } catch (e) { - logTestInfo("non-fatal error removing directory. Path: " + - applyDir.path + ", Exception: " + e); - } - } - - resetEnvironment(); - - logTestInfo("finish - general test cleanup"); - - if (gRealDump) { - dump = gRealDump; - gRealDump = null; - } - - if (DEBUG_TEST_LOG && !gPassed) { - let fos = AUS_Cc["@mozilla.org/network/file-output-stream;1"]. - createInstance(AUS_Ci.nsIFileOutputStream); - let logFile = do_get_file(gTestID + ".log", true); - if (!logFile.exists()) { - logFile.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); - } - fos.init(logFile, MODE_WRONLY | MODE_CREATE | MODE_APPEND, PERMS_FILE, 0); - fos.write(gTestLogText, gTestLogText.length); - fos.close(); - } - - if (DEBUG_TEST_LOG) { - gTestLogText = null; - } else { - let logFile = do_get_file(gTestID + ".log", true); - if (logFile.exists()) { - logFile.remove(false); - } - } -} - -/** - * Helper function to store the log output of calls to dump in a variable so the - * values can be written to a file for a parallel run of a test and printed to - * the log file when the test runs synchronously. - */ -function dumpOverride(aText) { - gTestLogText += aText; - gRealDump(aText); -} - -/** - * Helper function that calls do_test_finished that tracks whether a parallel - * run of a test passed when it runs synchronously so the log output can be - * inspected. - */ -function doTestFinish() { - if (gPassed === undefined) { - gPassed = true; - } - do_test_finished(); -} - -/** - * Sets the most commonly used preferences used by tests - */ -function setDefaultPrefs() { - Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true); - // Don't display UI for a successful installation. Some apps may not set this - // pref to false like Firefox does. - Services.prefs.setBoolPref(PREF_APP_UPDATE_SHOW_INSTALLED_UI, false); - // Enable Update logging - Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true); -} - -/** - * Helper function for updater binary tests that sets the appropriate values - * to check for update failures. - */ -function setTestFilesAndDirsForFailure() { - gTestFiles.forEach(function STFADFF_Files(aTestFile) { - aTestFile.compareContents = aTestFile.originalContents; - aTestFile.compareFile = aTestFile.originalFile; - aTestFile.comparePerms = aTestFile.originalPerms; - }); - - gTestDirs.forEach(function STFADFF_Dirs(aTestDir) { - aTestDir.dirRemoved = false; - if (aTestDir.filesRemoved) { - aTestDir.filesRemoved = false; - } - }); -} - -/** - * Helper function for updater binary tests that prevents the distribution - * directory files from being created. - */ -function preventDistributionFiles() { - gTestFiles = gTestFiles.filter(function(aTestFile) { - return aTestFile.relPathDir.indexOf("distribution/") == -1; - }); - - gTestDirs = gTestDirs.filter(function(aTestDir) { - return aTestDir.relPathDir.indexOf("distribution/") == -1; - }); -} - - -/** - * Initializes the most commonly used settings and creates an instance of the - * update service stub. - */ -function standardInit() { - createAppInfo("xpcshell@tests.mozilla.org", APP_INFO_NAME, "1.0", "2.0"); - setDefaultPrefs(); - // Initialize the update service stub component - initUpdateServiceStub(); -} - -/** - * Custom path handler for the http server - * - * @param aMetadata - * The http metadata for the request. - * @param aResponse - * The http response for the request. - */ -function pathHandler(aMetadata, aResponse) { - aResponse.setHeader("Content-Type", "text/xml", false); - aResponse.setStatusLine(aMetadata.httpVersion, gResponseStatusCode, "OK"); - aResponse.bodyOutputStream.write(gResponseBody, gResponseBody.length); -} - -/** - * Helper function for getting the application version from the application.ini - * file. This will look in both the GRE and the application directories for the - * application.ini file. - * - * @return The version string from the application.ini file. - * @throws If the application.ini file is not found. - */ -function getAppVersion() { - // Read the application.ini and use its application version. - let iniFile = gGREDirOrig.clone(); - iniFile.append(FILE_APPLICATION_INI); - if (!iniFile.exists()) { - iniFile = gGREBinDirOrig.clone(); - iniFile.append(FILE_APPLICATION_INI); - if (!iniFile.exists()) { - do_throw("Unable to find application.ini!"); - } - } - let iniParser = AUS_Cc["@mozilla.org/xpcom/ini-parser-factory;1"]. - getService(AUS_Ci.nsIINIParserFactory). - createINIParser(iniFile); - return iniParser.getString("App", "Version"); -} - -/** - * Helper function for getting the relative path to the directory where the - * application binary is located (e.g. /dir.app/). - * - * Note: The dir.app subdirectory under is needed for - * platforms other than Mac OS X so the tests can run in parallel due to - * update staging creating a lock file named moz_update_in_progress.lock in - * the parent directory of the installation directory. - * - * @return The relative path to the directory where application binary is - * located. - */ -function getApplyDirPath() { - return gTestID + "/dir.app/"; -} - -/** - * Helper function for getting the nsIFile for a file in the directory where the - * update will be applied. - * - * The files for the update are located two directories below the apply to - * directory since Mac OS X sets the last modified time for the root directory - * to the current time and if the update changes any files in the root directory - * then it wouldn't be possible to test (bug 600098). - * - * @param aRelPath (optional) - * The relative path to the file or directory to get from the root of - * the test's directory. If not specified the test's directory will be - * returned. - * @param aAllowNonexistent (optional) - * Whether the file must exist. If false or not specified the file must - * exist or the function will throw. - * @return The nsIFile for the file in the directory where the update will be - * applied. - * @throws If aAllowNonexistent is not specified or is false and the file or - * directory does not exist. - */ -function getApplyDirFile(aRelPath, aAllowNonexistent) { - let relpath = getApplyDirPath() + (aRelPath ? aRelPath : ""); - return do_get_file(relpath, aAllowNonexistent); -} - -/** - * Helper function for getting the nsIFile for a file in the directory where the - * update will be staged. - * - * The files for the update are located two directories below the stage - * directory since Mac OS X sets the last modified time for the root directory - * to the current time and if the update changes any files in the root directory - * then it wouldn't be possible to test (bug 600098). - * - * @param aRelPath (optional) - * The relative path to the file or directory to get from the root of - * the stage directory. If not specified the stage directory will be - * returned. - * @param aAllowNonexistent (optional) - * Whether the file must exist. If false or not specified the file must - * exist or the function will throw. - * @return The nsIFile for the file in the directory where the update will be - * staged. - * @throws If aAllowNonexistent is not specified or is false and the file or - * directory does not exist. - */ -function getStageDirFile(aRelPath, aAllowNonexistent) { - if (IS_MACOSX) { - let file = getMockUpdRootD(); - file.append(DIR_UPDATES); - file.append(DIR_PATCH); - file.append(DIR_UPDATED); - if (aRelPath) { - let pathParts = aRelPath.split("/"); - for (let i = 0; i < pathParts.length; i++) { - if (pathParts[i]) { - file.append(pathParts[i]); - } - } - } - if (!aAllowNonexistent && !file.exists()) { - do_throw(file.path + " does not exist"); - } - return file; - } - - let relpath = getApplyDirPath() + DIR_UPDATED + "/" + (aRelPath ? aRelPath : ""); - return do_get_file(relpath, aAllowNonexistent); -} - -/** - * Helper function for getting the relative path to the directory where the - * test data files are located. - * - * @return The relative path to the directory where the test data files are - * located. - */ -function getTestDirPath() { - return "../data/"; -} - -/** - * Helper function for getting the nsIFile for a file in the test data - * directory. - * - * @param aRelPath (optional) - * The relative path to the file or directory to get from the root of - * the test's data directory. If not specified the test's data - * directory will be returned. - * @return The nsIFile for the file in the test data directory. - * @throws If the file or directory does not exist. - */ -function getTestDirFile(aRelPath) { - let relpath = getTestDirPath() + (aRelPath ? aRelPath : ""); - return do_get_file(relpath, false); -} - -/** - * Helper function for getting the nsIFile for the maintenance service - * directory on Windows. - * - * @return The nsIFile for the maintenance service directory. - */ -function getMaintSvcDir() { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - const CSIDL_PROGRAM_FILES = 0x26; - const CSIDL_PROGRAM_FILESX86 = 0x2A; - // This will return an empty string on our Win XP build systems. - let maintSvcDir = getSpecialFolderDir(CSIDL_PROGRAM_FILESX86); - if (maintSvcDir) { - maintSvcDir.append("Mozilla Maintenance Service"); - debugDump("using CSIDL_PROGRAM_FILESX86 - maintenance service install " + - "directory path: " + maintSvcDir.path); - } - if (!maintSvcDir || !maintSvcDir.exists()) { - maintSvcDir = getSpecialFolderDir(CSIDL_PROGRAM_FILES); - if (maintSvcDir) { - maintSvcDir.append("Mozilla Maintenance Service"); - debugDump("using CSIDL_PROGRAM_FILES - maintenance service install " + - "directory path: " + maintSvcDir.path); - } - } - if (!maintSvcDir) { - do_throw("Unable to find the maintenance service install directory"); - } - - return maintSvcDir; -} - -#ifdef XP_WIN -function getSpecialFolderDir(aCSIDL) { - AUS_Cu.import("resource://gre/modules/ctypes.jsm"); - let lib = ctypes.open("shell32"); - let SHGetSpecialFolderPath = lib.declare("SHGetSpecialFolderPathW", - ctypes.winapi_abi, - ctypes.bool, /* bool(return) */ - ctypes.int32_t, /* HWND hwndOwner */ - ctypes.char16_t.ptr, /* LPTSTR lpszPath */ - ctypes.int32_t, /* int csidl */ - ctypes.bool /* BOOL fCreate */); - - let aryPath = ctypes.char16_t.array()(260); - let rv = SHGetSpecialFolderPath(0, aryPath, aCSIDL, false); - lib.close(); - - let path = aryPath.readString(); // Convert the c-string to js-string - if (!path) { - return null; - } - logTestInfo("SHGetSpecialFolderPath returned path: " + path); - let dir = AUS_Cc["@mozilla.org/file/local;1"]. - createInstance(AUS_Ci.nsILocalFile); - dir.initWithPath(path); - return dir; -} - -XPCOMUtils.defineLazyGetter(this, "gInstallDirPathHash", - function test_gInstallDirPathHash() { - // Figure out where we should check for a cached hash value - if (!MOZ_APP_BASENAME) - return null; - - let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla"; - let appDir = getApplyDirFile(null, true); - - const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME + - "\\TaskBarIDs"; - let regKey = AUS_Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(AUS_Ci.nsIWindowsRegKey); - try { - regKey.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, - AUS_Ci.nsIWindowsRegKey.ACCESS_ALL); - regKey.writeStringValue(appDir.path, gTestID); - return gTestID; - } catch (e) { - } - - try { - regKey.create(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH, - AUS_Ci.nsIWindowsRegKey.ACCESS_ALL); - regKey.writeStringValue(appDir.path, gTestID); - return gTestID; - } catch (e) { - logTestInfo("failed to create registry key. Registry Path: " + REG_PATH + - ", Key Name: " + appDir.path + ", Key Value: " + gTestID + - ", Exception " + e); - } - return null; -}); - -XPCOMUtils.defineLazyGetter(this, "gLocalAppDataDir", - function test_gLocalAppDataDir() { - const CSIDL_LOCAL_APPDATA = 0x1c; - return getSpecialFolderDir(CSIDL_LOCAL_APPDATA); -}); - -XPCOMUtils.defineLazyGetter(this, "gProgFilesDir", - function test_gProgFilesDir() { - const CSIDL_PROGRAM_FILES = 0x26; - return getSpecialFolderDir(CSIDL_PROGRAM_FILES); -}); - -/** - * Helper function for getting the update root directory used by the tests. This - * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir - * in nsXREDirProvider.cpp so an application will be able to find the update - * when running a test that launches the application. - */ -function getMockUpdRootD() { - let localAppDataDir = gLocalAppDataDir.clone(); - let progFilesDir = gProgFilesDir.clone(); - let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsIFile).parent; - - let appDirPath = appDir.path; - let relPathUpdates = ""; - if (gInstallDirPathHash && (MOZ_APP_VENDOR || MOZ_APP_BASENAME)) { - relPathUpdates += (MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME) + - "\\" + DIR_UPDATES + "\\" + gInstallDirPathHash; - } - - if (!relPathUpdates && progFilesDir) { - if (appDirPath.length > progFilesDir.path.length) { - if (appDirPath.substr(0, progFilesDir.path.length) == progFilesDir.path) { - if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) { - relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME; - } else { - relPathUpdates += MOZ_APP_BASENAME; - } - relPathUpdates += appDirPath.substr(progFilesDir.path.length); - } - } - } - - if (!relPathUpdates) { - if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) { - relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME; - } else { - relPathUpdates += MOZ_APP_BASENAME; - } - relPathUpdates += "\\" + MOZ_APP_NAME; - } - - let updatesDir = AUS_Cc["@mozilla.org/file/local;1"]. - createInstance(AUS_Ci.nsILocalFile); - updatesDir.initWithPath(localAppDataDir.path + "\\" + relPathUpdates); - logTestInfo("returning UpdRootD Path: " + updatesDir.path); - return updatesDir; -} -#elif XP_MACOSX -XPCOMUtils.defineLazyGetter(this, "gUpdatesRootDir", - function test_gUpdatesRootDir() { - let dir = Services.dirsvc.get("ULibDir", AUS_Ci.nsILocalFile); - dir.append("Caches"); - if (MOZ_APP_VENDOR || MOZ_APP_BASENAME) { - dir.append(MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME); - } else { - dir.append("Mozilla"); - } - dir.append(DIR_UPDATES); - return dir; -}); - -/** - * Helper function for getting the update root directory used by the tests. This - * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir - * in nsXREDirProvider.cpp so an application will be able to find the update - * when running a test that launches the application. - */ -function getMockUpdRootD() { - let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsIFile). - parent.parent.parent; - let appDirPath = appDir.path; - appDirPath = appDirPath.substr(0, appDirPath.length - 4); - - let pathUpdates = gUpdatesRootDir.path + appDirPath; - let updatesDir = AUS_Cc["@mozilla.org/file/local;1"]. - createInstance(AUS_Ci.nsILocalFile); - updatesDir.initWithPath(pathUpdates); - logTestInfo("returning UpdRootD Path: " + updatesDir.path); - return updatesDir; -} -#else -/** - * Helper function for getting the update root directory used by the tests. This - * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir - * in nsXREDirProvider.cpp so an application will be able to find the update - * when running a test that launches the application. - */ -function getMockUpdRootD() { - return getApplyDirFile(DIR_MACOS, true); -} -#endif - -const kLockFileName = "updated.update_in_progress.lock"; -/** - * Helper function for locking a directory on Windows. - * - * @param aDir - * The nsIFile for the directory to lock. - */ -function lockDirectory(aDir) { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - let file = aDir.clone(); - file.append(kLockFileName); - file.create(file.NORMAL_FILE_TYPE, 0o444); - file.QueryInterface(AUS_Ci.nsILocalFileWin); - file.fileAttributesWin |= file.WFA_READONLY; - file.fileAttributesWin &= ~file.WFA_READWRITE; - logTestInfo("testing the successful creation of the lock file"); - do_check_true(file.exists()); - do_check_false(file.isWritable()); -} -/** - * Helper function for unlocking a directory on Windows. - * - * @param aDir - * The nsIFile for the directory to unlock. - */ -function unlockDirectory(aDir) { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - let file = aDir.clone(); - file.append(kLockFileName); - file.QueryInterface(AUS_Ci.nsILocalFileWin); - file.fileAttributesWin |= file.WFA_READWRITE; - file.fileAttributesWin &= ~file.WFA_READONLY; - logTestInfo("removing and testing the successful removal of the lock file"); - file.remove(false); - do_check_false(file.exists()); -} - -/** - * Helper function for updater tests for launching the updater binary to apply - * a mar file. - * - * @param aExpectedExitValue - * The expected exit value from the updater binary. - * @param aExpectedStatus - * The expected value of update.status when the test finishes. - * @param aCallback (optional) - * A callback function that will be called when this function finishes. - * If null no function will be called when this function finishes. - * If not specified the checkUpdateApplied function will be called when - * this function finishes. - */ -function runUpdate(aExpectedExitValue, aExpectedStatus, aCallback) { - // Copy the updater binary to the updates directory. - let binDir = gGREBinDirOrig.clone(); - let updater = binDir.clone(); - updater.append("updater.app"); - if (!updater.exists()) { - updater = binDir.clone(); - updater.append(FILE_UPDATER_BIN); - if (!updater.exists()) { - do_throw("Unable to find updater binary!"); - } - } - - let updatesDir = getUpdatesPatchDir(); - let updateBin; - if (IS_WIN) { - updateBin = updater.clone(); - } else { - updater.copyToFollowingLinks(updatesDir, updater.leafName); - updateBin = updatesDir.clone(); - updateBin.append(updater.leafName); - if (updateBin.leafName == "updater.app") { - updateBin.append("Contents"); - updateBin.append("MacOS"); - updateBin.append("updater"); - } - } - if (!updateBin.exists()) { - do_throw("Unable to find the updater executable!"); - } - - let applyToDir = getApplyDirFile(null, true); - let applyToDirPath = applyToDir.path; - - let stageDir = getStageDirFile(null, true); - let stageDirPath = stageDir.path; - - if (IS_WIN) { - // Convert to native path - applyToDirPath = applyToDirPath.replace(/\//g, "\\"); - stageDirPath = stageDirPath.replace(/\//g, "\\"); - } - - let callbackApp = getApplyDirFile(DIR_RESOURCES + gCallbackBinFile); - callbackApp.permissions = PERMS_DIRECTORY; - - let args = [updatesDir.path, applyToDirPath]; - if (gStageUpdate) { - args[2] = stageDirPath; - args[3] = -1; - } else { - if (gSwitchApp) { - args[2] = stageDirPath; - args[3] = "0/replace"; - } else { - args[2] = applyToDirPath; - args[3] = "0"; - } - args = args.concat([callbackApp.parent.path, callbackApp.path]); - args = args.concat(gCallbackArgs); - } - logTestInfo("running the updater: " + updateBin.path + " " + args.join(" ")); - - let env = AUS_Cc["@mozilla.org/process/environment;1"]. - getService(AUS_Ci.nsIEnvironment); - if (gDisableReplaceFallback) { - env.set("MOZ_NO_REPLACE_FALLBACK", "1"); - } - - let process = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); - process.init(updateBin); - process.run(true, args, args.length); - - if (gDisableReplaceFallback) { - env.set("MOZ_NO_REPLACE_FALLBACK", ""); - } - - let status = readStatusFile(); - if (process.exitValue != aExpectedExitValue || status != aExpectedStatus) { - if (process.exitValue != aExpectedExitValue) { - logTestInfo("updater exited with unexpected value! Got: " + - process.exitValue + ", Expected: " + aExpectedExitValue); - } - if (status != aExpectedStatus) { - logTestInfo("update status is not the expected status! Got: " + status + - ", Expected: " + aExpectedStatus); - } - let updateLog = getUpdatesPatchDir(); - updateLog.append(FILE_UPDATE_LOG); - logTestInfo("contents of " + updateLog.path + ":\n" + - readFileBytes(updateLog).replace(/\r\n/g, "\n")); - } - logTestInfo("testing updater binary process exitValue against expected " + - "exit value"); - do_check_eq(process.exitValue, aExpectedExitValue); - logTestInfo("testing update status against expected status"); - do_check_eq(status, aExpectedStatus); - - if (aCallback !== null) { - if (typeof(aCallback) == typeof(Function)) { - aCallback(); - } else { - checkUpdateApplied(); - } - } -} - -/** - * Helper function for updater tests to stage an update. - */ -function stageUpdate() { - logTestInfo("start - attempting to stage update"); - Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false); - - setEnvironment(); - // Stage the update. - AUS_Cc["@mozilla.org/updates/update-processor;1"]. - createInstance(AUS_Ci.nsIUpdateProcessor). - processUpdate(gUpdateManager.activeUpdate); - resetEnvironment(); - - logTestInfo("finish - attempting to stage update"); -} - -/** - * Helper function to check whether the maintenance service updater tests should - * run. See bug 711660 for more details. - * - * @param aFirstTest - * Whether this is the first test within the test. - * @param aSkipTest - * Whether to skip this test if the installed maintenance service - * isn't the same as the build's maintenance service. This is a - * temporary workaround until all build systems grant write access to - * the maintenance service install directory so the tests can copy the - * version of the maintenance service that should be tests. - * @return true if the test should run and false if it shouldn't. - */ -function shouldRunServiceTest(aFirstTest, aSkipTest) { - let binDir = getGREBinDir(); - let updaterBin = binDir.clone(); - updaterBin.append(FILE_UPDATER_BIN); - if (!updaterBin.exists()) { - do_throw("Unable to find updater binary!"); - } - - let updaterBinPath = updaterBin.path; - if (/ /.test(updaterBinPath)) { - updaterBinPath = '"' + updaterBinPath + '"'; - } - - const REG_PATH = "SOFTWARE\\Mozilla\\MaintenanceService\\" + - "3932ecacee736d366d6436db0f55bce4"; - - let key = AUS_Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(AUS_Ci.nsIWindowsRegKey); - try { - key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, - AUS_Ci.nsIWindowsRegKey.ACCESS_READ | key.WOW64_64); - } catch (e) { -#ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK - // The build system could sign the files and not have the test registry key - // in which case we should fail the test by throwing so it can be fixed. - if (isBinarySigned(updaterBinPath)) { - do_throw("binary is signed but the test registry key does not exists!"); - } -#endif - - logTestInfo("this test can only run on the buildbot build system at this " + - "time."); - return false; - } - - // Check to make sure the service is installed - let helperBin = getTestDirFile(FILE_HELPER_BIN); - let args = ["wait-for-service-stop", "MozillaMaintenance", "10"]; - let process = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); - process.init(helperBin); - logTestInfo("checking if the service exists on this machine."); - process.run(true, args, args.length); - if (process.exitValue == 0xEE) { - do_throw("test registry key exists but this test can only run on systems " + - "with the maintenance service installed."); - } else { - logTestInfo("service exists, return value: " + process.exitValue); - } - - // If this is the first test in the series, then there is no reason the - // service should be anything but stopped, so be strict here and throw - // an error. - if (aFirstTest && process.exitValue != 0) { - do_throw("First test, check for service stopped state returned error " + - process.exitValue); - } - -#ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK - if (!isBinarySigned(updaterBinPath)) { - logTestInfo("test registry key exists but this test can only run on " + - "builds with signed binaries when " + - "DISABLE_UPDATER_AUTHENTICODE_CHECK is not defined"); - do_throw("this test can only run on builds with signed binaries."); - } -#endif - - // In case the machine is running an old maintenance service or if it - // is not installed, and permissions exist to install it. Then install - // the newer bin that we have since all of the other checks passed. - return attemptServiceInstall(aSkipTest); -} - -/** - * Helper function to check whether the a binary is signed. - * - * @param aBinPath The path to the file to check if it is signed. - * @return true if the file is signed and false if it isn't. - */ -function isBinarySigned(aBinPath) { - let helperBin = getTestDirFile(FILE_HELPER_BIN); - let args = ["check-signature", aBinPath]; - let process = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); - process.init(helperBin); - process.run(true, args, args.length); - if (process.exitValue != 0) { - logTestInfo("binary is not signed. " + FILE_HELPER_BIN + " returned " + - process.exitValue + " for file " + aBinPath); - return false; - } - return true; -} - -/** - * Helper function for asynchronously setting up the application files required - * to launch the application for the updater tests by either copying or creating - * symlinks for the files. This is needed for Windows debug builds which can - * lock a file that is being copied so that the tests can run in parallel. After - * the files have been copied the setupAppFilesFinished function will be called. +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ -function setupAppFilesAsync() { - gTimeoutRuns++; - try { - setupAppFiles(); - } catch (e) { - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while trying to setup application " + - "files. Exception: " + e); - } - do_timeout(TEST_CHECK_TIMEOUT, setupAppFilesAsync); - return; - } - - setupAppFilesFinished(); -} - -/** - * Helper function for setting up the application files required to launch the - * application for the updater tests by either copying or creating symlinks to - * the files. - */ -function setupAppFiles() { - logTestInfo("start - copying or creating symlinks to application files " + - "for the test"); - - let destDir = getApplyDirFile(null, true); - if (!destDir.exists()) { - try { - destDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - } catch (e) { - logTestInfo("unable to create directory, Path: " + destDir.path + - ", Exception: " + e); - do_throw(e); - } - } - - // Required files for the application or the test that aren't listed in the - // dependentlibs.list file. - let appFiles = [ { relPath : FILE_APP_BIN, - inGreDir : false }, - { relPath : FILE_UPDATER_BIN, - inGreDir : false }, - { relPath : FILE_APPLICATION_INI, - inGreDir : true }, - { relPath : "dependentlibs.list", - inGreDir : true } ]; - - // On Linux the updater.png must also be copied - if (IS_UNIX && !IS_MACOSX) { - appFiles.push( { relPath : "icons/updater.png", - inGreDir : true } ); - } - - // Read the dependent libs file leafnames from the dependentlibs.list file - // into the array. - let deplibsFile = gGREDirOrig.clone(); - deplibsFile.append("dependentlibs.list"); - let istream = AUS_Cc["@mozilla.org/network/file-input-stream;1"]. - createInstance(AUS_Ci.nsIFileInputStream); - istream.init(deplibsFile, 0x01, 0o444, 0); - istream.QueryInterface(AUS_Ci.nsILineInputStream); - - let hasMore; - let line = {}; - do { - hasMore = istream.readLine(line); - appFiles.push( { relPath : line.value, - inGreDir : false } ); - } while(hasMore); - - istream.close(); - - appFiles.forEach(function CMAF_FLN_FE(aAppFile) { - copyFileToTestAppDir(aAppFile.relPath, aAppFile.inGreDir); - }); - - logTestInfo("finish - copying or creating symlinks to application files " + - "for the test"); -} - -/** - * Copies the specified files from the dist/bin directory into the test's - * application directory. - * - * @param aFileRelPath - * The relative path to the source and the destination of the file to - * copy. - * @param aInGreDir - * Whether the file is located in the GRE directory which is - * /Contents/Resources on Mac OS X and is the installation - * directory on all other platforms. If false the file must be in the - * GRE Binary directory which is /Contents/MacOS on Mac OS X and - * is the installation directory on on all other platforms. - */ -function copyFileToTestAppDir(aFileRelPath, aInGreDir) { - // gGREDirOrig and gGREBinDirOrig must always be cloned when changing its - // properties - let srcFile = aInGreDir ? gGREDirOrig.clone() : gGREBinDirOrig.clone(); - let destFile = aInGreDir ? getGREDir() : getGREBinDir(); - let fileRelPath = aFileRelPath; - let pathParts = fileRelPath.split("/"); - for (let i = 0; i < pathParts.length; i++) { - if (pathParts[i]) { - srcFile.append(pathParts[i]); - destFile.append(pathParts[i]); - } - } - - if (IS_MACOSX && !srcFile.exists()) { - logTestInfo("unable to copy file since it doesn't exist! Checking if " + - fileRelPath + ".app exists. Path: " + - srcFile.path); - // gGREDirOrig and gGREBinDirOrig must always be cloned when changing its - // properties - srcFile = aInGreDir ? gGREDirOrig.clone() : gGREBinDirOrig.clone(); - destFile = aInGreDir ? getGREDir() : getGREBinDir(); - for (let i = 0; i < pathParts.length; i++) { - if (pathParts[i]) { - srcFile.append(pathParts[i] + (pathParts.length - 1 == i ? ".app" : "")); - destFile.append(pathParts[i] + (pathParts.length - 1 == i ? ".app" : "")); - } - } - fileRelPath = fileRelPath + ".app"; - } - - if (!srcFile.exists()) { - do_throw("Unable to copy file since it doesn't exist! Path: " + - srcFile.path); - } - - // Symlink libraries. Note that the XUL library on Mac OS X doesn't have a - // file extension and shouldSymlink will always be false on Windows. - let shouldSymlink = (pathParts[pathParts.length - 1] == "XUL" || - fileRelPath.substr(fileRelPath.length - 3) == ".so" || - fileRelPath.substr(fileRelPath.length - 6) == ".dylib"); - if (!shouldSymlink) { - if (!destFile.exists()) { - try { - srcFile.copyToFollowingLinks(destFile.parent, destFile.leafName); - } catch (e) { - // Just in case it is partially copied - if (destFile.exists()) { - try { - destFile.remove(true); - } catch (e) { - logTestInfo("unable to remove file that failed to copy! Path: " + - destFile.path); - } - } - do_throw("Unable to copy file! Path: " + srcFile.path + - ", Exception: " + e); - } - } - } else { - try { - if (destFile.exists()) { - destFile.remove(false); - } - let ln = AUS_Cc["@mozilla.org/file/local;1"].createInstance(AUS_Ci.nsILocalFile); - ln.initWithPath("/bin/ln"); - let process = AUS_Cc["@mozilla.org/process/util;1"].createInstance(AUS_Ci.nsIProcess); - process.init(ln); - let args = ["-s", srcFile.path, destFile.path]; - process.run(true, args, args.length); - logTestInfo("verifying symlink. Path: " + destFile.path); - do_check_true(destFile.isSymlink()); - } catch (e) { - do_throw("Unable to create symlink for file! Path: " + srcFile.path + - ", Exception: " + e); - } - } -} - -/** - * Attempts to upgrade the maintenance service if permissions are allowed. - * This is useful for XP where we have permission to upgrade in case an - * older service installer exists. Also if the user manually installed into - * a unprivileged location. - * - * @param aSkipTest - * Whether to skip this test if the installed maintenance service - * isn't the same as the build's maintenance service. This is a - * temporary workaround until all build systems grant write access to - * the maintenance service install directory so the tests can copy the - * version of the maintenance service that should be tests. - */ -function attemptServiceInstall(aSkipTest) { - let maintSvcDir = getMaintSvcDir(); - if (!maintSvcDir || !maintSvcDir.exists()) { - do_throw("maintenance service install directory doesn't exist!"); - } - let oldMaintSvcBin = maintSvcDir.clone(); - oldMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); - if (!oldMaintSvcBin.exists()) { - do_throw("maintenance service install directory binary doesn't exist! " + - "Path: " + oldMaintSvcBin.path); - } - let buildMaintSvcBin = getGREBinDir(); - buildMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); - if (readFileBytes(oldMaintSvcBin) == readFileBytes(buildMaintSvcBin)) { - logTestInfo("installed maintenance service binary is the same as the " + - "build's maintenance service binary"); - return true; - } - let backupMaintSvcBin = maintSvcDir.clone(); - backupMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN + ".backup"); - try { - if (backupMaintSvcBin.exists()) { - backupMaintSvcBin.remove(false); - } - oldMaintSvcBin.moveTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN + ".backup"); - buildMaintSvcBin.copyTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN); - backupMaintSvcBin.remove(false); - return true; - } catch (e) { - // Restore the original file in case the moveTo was successful. - if (backupMaintSvcBin.exists()) { - oldMaintSvcBin = maintSvcDir.clone(); - oldMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); - if (!oldMaintSvcBin.exists()) { - backupMaintSvcBin.moveTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN); - } - } - logTestInfo("unable to copy new maintenance service into the " + - "maintenance service directory: " + maintSvcDir.path + ", " + - "Exception: " + e); - } - - let version = AUS_Cc["@mozilla.org/system-info;1"]. - getService(AUS_Ci.nsIPropertyBag2). - getProperty("version"); - var isWin7OrBelow = (parseFloat(version) <= 6.1); - // The account running the tests on Win XP and Win 7 build systems have write - // access to the maintenance service directory so throw if copying the - // maintenance service binary fails. This should always throw after write - // access is provided on all Windows build slaves in bug 1067756. - if (isWin7OrBelow) { - do_throw("The account running the tests on Win 7 and below build systems " + - "should have write access to the maintenance service directory!"); - } - - return aSkipTest ? false : true; -} - -/** - * Helper function for updater tests for launching the updater using the - * maintenance service to apply a mar file. - * - * @param aInitialStatus - * The initial value of update.status. - * @param aExpectedStatus - * The expected value of update.status when the test finishes. - * @param aCheckSvcLog (optional) - * Whether the service log should be checked. - */ -function runUpdateUsingService(aInitialStatus, aExpectedStatus, aCheckSvcLog) { - // Check the service logs for a successful update - function checkServiceLogs(aOriginalContents) { - let contents = readServiceLogFile(); - logTestInfo("the contents of maintenanceservice.log:\n" + contents + "\n"); - do_check_neq(contents, aOriginalContents); - do_check_neq(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1); - } - function readServiceLogFile() { - let file = getMaintSvcDir(); - file.append("logs"); - file.append("maintenanceservice.log"); - return readFile(file); - } - function waitServiceApps() { - // maintenanceservice_installer.exe is started async during updates. - waitForApplicationStop("maintenanceservice_installer.exe"); - // maintenanceservice_tmp.exe is started async from the service installer. - waitForApplicationStop("maintenanceservice_tmp.exe"); - // In case the SCM thinks the service is stopped, but process still exists. - waitForApplicationStop("maintenanceservice.exe"); - } - function waitForServiceStop(aFailTest) { - waitServiceApps(); - logTestInfo("waiting for service to stop if necessary..."); - // Use the helper bin to ensure the service is stopped. If not - // stopped then wait for the service to be stopped (at most 120 seconds) - let helperBin = getTestDirFile(FILE_HELPER_BIN); - let helperBinArgs = ["wait-for-service-stop", - "MozillaMaintenance", - "120"]; - let helperBinProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); - helperBinProcess.init(helperBin); - logTestInfo("stopping service..."); - helperBinProcess.run(true, helperBinArgs, helperBinArgs.length); - if (helperBinProcess.exitValue == 0xEE) { - do_throw("The service does not exist on this machine. Return value: " + - helperBinProcess.exitValue); - } else if (helperBinProcess.exitValue != 0) { - if (aFailTest) { - do_throw("maintenance service did not stop, last state: " + - helperBinProcess.exitValue + ". Forcing test failure."); - } else { - logTestInfo("maintenance service did not stop, last state: " + - helperBinProcess.exitValue + ". May cause failures."); - } - } else { - logTestInfo("service stopped."); - } - waitServiceApps(); - } - function waitForApplicationStop(aApplication) { - logTestInfo("waiting for " + aApplication + " to stop if " + - "necessary..."); - // Use the helper bin to ensure the application is stopped. - // If not, then wait for it to be stopped (at most 120 seconds) - let helperBin = getTestDirFile(FILE_HELPER_BIN); - let helperBinArgs = ["wait-for-application-exit", - aApplication, - "120"]; - let helperBinProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); - helperBinProcess.init(helperBin); - helperBinProcess.run(true, helperBinArgs, helperBinArgs.length); - if (helperBinProcess.exitValue != 0) { - do_throw(aApplication + " did not stop, last state: " + - helperBinProcess.exitValue + ". Forcing test failure."); - } - } - - // Make sure the service from the previous test is already stopped. - waitForServiceStop(true); - - // Prevent the cleanup function from begin run more than once - if (gRegisteredServiceCleanup === undefined) { - gRegisteredServiceCleanup = true; - - do_register_cleanup(function RUUS_cleanup() { - resetEnvironment(); - - // This will delete the app arguments log file if it exists. - try { - getAppArgsLogPath(); - } catch (e) { - logTestInfo("unable to remove file during cleanup. Exception: " + e); - } - }); - } - - let svcOriginalLog; - // Default to checking the service log if the parameter is not specified. - if (aCheckSvcLog === undefined || aCheckSvcLog) { - svcOriginalLog = readServiceLogFile(); - } - - let appArgsLogPath = getAppArgsLogPath(); - gServiceLaunchedCallbackLog = appArgsLogPath.replace(/^"|"$/g, ""); - - let updatesDir = getUpdatesPatchDir(); - writeStatusFile(aInitialStatus); - - // sanity check - do_check_eq(readStatusState(), aInitialStatus); - - writeVersionFile(DEFAULT_UPDATE_VERSION); - - gServiceLaunchedCallbackArgs = [ - "-no-remote", - "-process-updates", - "-dump-args", - appArgsLogPath - ]; - - if (gSwitchApp) { - // We want to set the env vars again - gShouldResetEnv = undefined; - } - - setEnvironment(); - - // There is a security check done by the service to make sure the updater - // we are executing is the same as the one in the apply-to dir. - // To make sure they match from tests we copy updater.exe to the apply-to dir. - copyFileToTestAppDir(FILE_UPDATER_BIN, false); - - // The service will execute maintenanceservice_installer.exe and - // will copy maintenanceservice.exe out of the same directory from - // the installation directory. So we need to make sure both of those - // bins always exist in the installation directory. - copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN, false); - copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, false); - - let launchBin = getLaunchBin(); - let args = getProcessArgs(["-dump-args", appArgsLogPath]); - - let process = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); - process.init(launchBin); - logTestInfo("launching " + launchBin.path + " " + args.join(" ")); - // Firefox does not wait for the service command to finish, but - // we still launch the process sync to avoid intermittent failures with - // the log file not being written out yet. - // We will rely on watching the update.status file and waiting for the service - // to stop to know the service command is done. - process.run(true, args, args.length); - - resetEnvironment(); - - function timerCallback(aTimer) { - // Wait for the expected status - let status = readStatusState(); - // status will probably always be equal to STATE_APPLYING but there is a - // race condition where it would be possible on slower machines where status - // could be equal to STATE_PENDING_SVC. - if (status == STATE_APPLYING || - status == STATE_PENDING_SVC) { - logTestInfo("still waiting to see the " + aExpectedStatus + - " status, got " + status + " for now..."); - return; - } - - // Make sure all of the logs are written out. - waitForServiceStop(false); - - aTimer.cancel(); - aTimer = null; - - if (status != aExpectedStatus) { - logTestInfo("update status is not the expected status! Got: " + status + - ", Expected: " + aExpectedStatus); - logTestInfo("update.status contents: " + readStatusFile()); - let updateLog = getUpdatesPatchDir(); - updateLog.append(FILE_UPDATE_LOG); - logTestInfo("contents of " + updateLog.path + ":\n" + - readFileBytes(updateLog).replace(/\r\n/g, "\n")); - } - logTestInfo("testing update status against expected status"); - do_check_eq(status, aExpectedStatus); - - if (aCheckSvcLog) { - checkServiceLogs(svcOriginalLog); - } - - checkUpdateFinished(); - } - - let timer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer); - timer.initWithCallback(timerCallback, 1000, timer.TYPE_REPEATING_SLACK); -} - -/** - * Gets the platform specific shell binary that is launched using nsIProcess and - * in turn launches a binary used for the test (e.g. application, updater, - * etc.). A shell is used so debug console output can be redirected to a file so - * it doesn't end up in the test log. - * - * @return nsIFile for the shell binary to launch using nsIProcess. - * @throws if the shell binary doesn't exist. - */ -function getLaunchBin() { - let launchBin; - if (IS_WIN) { - launchBin = Services.dirsvc.get("WinD", AUS_Ci.nsIFile); - launchBin.append("System32"); - launchBin.append("cmd.exe"); - } else { - launchBin = AUS_Cc["@mozilla.org/file/local;1"]. - createInstance(AUS_Ci.nsILocalFile); - launchBin.initWithPath("/bin/sh"); - } - - if (!launchBin.exists()) - do_throw(launchBin.path + " must exist to run this test!"); - - return launchBin; -} - -/** - * Helper function that waits until the helper has completed its operations and - * is in a sleep state before performing an update by calling doUpdate. - */ -function waitForHelperSleep() { - gTimeoutRuns++; - // Give the lock file process time to lock the file before updating otherwise - // this test can fail intermittently on Windows debug builds. - let output = getApplyDirFile(DIR_RESOURCES + "output", true); - if (readFile(output) != "sleeping\n") { - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper to " + - "finish its operation. Path: " + output.path); - } - do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); - return; - } - try { - output.remove(false); - } - catch (e) { - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper " + - "message file to no longer be in use. Path: " + output.path); - } - logTestInfo("failed to remove file. Path: " + output.path); - do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); - return; - } - doUpdate(); -} - -/** - * Helper function that waits until the helper has finished its operations - * before calling waitForHelperFinishFileUnlock to verify that the helper's - * input and output directories are no longer in use. - */ -function waitForHelperFinished() { - // Give the lock file process time to lock the file before updating otherwise - // this test can fail intermittently on Windows debug builds. - let output = getApplyDirFile(DIR_RESOURCES + "output", true); - if (readFile(output) != "finished\n") { - do_timeout(TEST_HELPER_TIMEOUT, waitForHelperFinished); - return; - } - // Give the lock file process time to unlock the file before deleting the - // input and output files. - waitForHelperFinishFileUnlock(); -} - -/** - * Helper function that waits until the helper's input and output files are no - * longer in use before calling checkUpdate. - */ -function waitForHelperFinishFileUnlock() { - try { - let output = getApplyDirFile(DIR_RESOURCES + "output", true); - if (output.exists()) { - output.remove(false); - } - let input = getApplyDirFile(DIR_RESOURCES + "input", true); - if (input.exists()) { - input.remove(false); - } - } catch (e) { - // Give the lock file process time to unlock the file before deleting the - // input and output files. - do_timeout(TEST_HELPER_TIMEOUT, waitForHelperFinishFileUnlock); - return; - } - checkUpdate(); -} - -/** - * Helper function to tell the helper to finish and exit its sleep state. - */ -function setupHelperFinish() { - let input = getApplyDirFile(DIR_RESOURCES + "input", true); - writeFile(input, "finish\n"); - waitForHelperFinished(); -} - -/** - * Helper function for updater binary tests that creates the files and - * directories used by the test. - * - * @param aMarFile - * The mar file for the update test. - */ -function setupUpdaterTest(aMarFile) { - let updatesPatchDir = getUpdatesPatchDir(); - if (!updatesPatchDir.exists()) { - updatesPatchDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - } - // Copy the mar that will be applied - let mar = getTestDirFile(aMarFile); - mar.copyToFollowingLinks(updatesPatchDir, FILE_UPDATE_ARCHIVE); - - let helperBin = getTestDirFile(FILE_HELPER_BIN); - let afterApplyBinDir = getApplyDirFile(DIR_RESOURCES, true); - helperBin.copyToFollowingLinks(afterApplyBinDir, gCallbackBinFile); - helperBin.copyToFollowingLinks(afterApplyBinDir, gPostUpdateBinFile); - - let applyToDir = getApplyDirFile(null, true); - gTestFiles.forEach(function SUT_TF_FE(aTestFile) { - if (aTestFile.originalFile || aTestFile.originalContents) { - let testDir = getApplyDirFile(aTestFile.relPathDir, true); - if (!testDir.exists()) - testDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - - let testFile; - if (aTestFile.originalFile) { - testFile = getTestDirFile(aTestFile.originalFile); - testFile.copyToFollowingLinks(testDir, aTestFile.fileName); - testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName); - } else { - testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName, - true); - writeFile(testFile, aTestFile.originalContents); - } - - // Skip these tests on Windows and OS/2 since their - // implementaions of chmod doesn't really set permissions. - if (!IS_WIN && aTestFile.originalPerms) { - testFile.permissions = aTestFile.originalPerms; - // Store the actual permissions on the file for reference later after - // setting the permissions. - if (!aTestFile.comparePerms) { - aTestFile.comparePerms = testFile.permissions; - } - } - } - }); - - // Add the test directory that will be updated for a successful update or left - // in the initial state for a failed update. - gTestDirs.forEach(function SUT_TD_FE(aTestDir) { - let testDir = getApplyDirFile(aTestDir.relPathDir, true); - if (!testDir.exists()) { - testDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - } - - if (aTestDir.files) { - aTestDir.files.forEach(function SUT_TD_F_FE(aTestFile) { - let testFile = getApplyDirFile(aTestDir.relPathDir + aTestFile, true); - if (!testFile.exists()) { - testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); - } - }); - } - - if (aTestDir.subDirs) { - aTestDir.subDirs.forEach(function SUT_TD_SD_FE(aSubDir) { - let testSubDir = getApplyDirFile(aTestDir.relPathDir + aSubDir, true); - if (!testSubDir.exists()) { - testSubDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - } - - if (aTestDir.subDirFiles) { - aTestDir.subDirFiles.forEach(function SUT_TD_SDF_FE(aTestFile) { - let testFile = getApplyDirFile(aTestDir.relPathDir + aSubDir + aTestFile, true); - if (!testFile.exists()) { - testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); - } - }); - } - }); - } - }); -} - -/** - * Helper function for updater binary tests that creates the update-settings.ini - * file. - */ -function createUpdateSettingsINI() { - let updateSettingsIni = getApplyDirFile(null, true); - if (IS_MACOSX) { - updateSettingsIni.append("Contents"); - updateSettingsIni.append("Resources"); - } - updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); - writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS); -} - -/** - * Helper function for updater binary tests that creates the updater.ini - * file. - * - * @param aIsExeAsync - * True or undefined if the post update process should be async. If - * undefined ExeAsync will not be added to the updater.ini file in - * order to test the default launch behavior which is async. - */ -function createUpdaterINI(aIsExeAsync) { - let exeArg = "ExeArg=post-update-async\n"; - let exeAsync = ""; - if (aIsExeAsync !== undefined) - { - if (aIsExeAsync) { - exeAsync = "ExeAsync=true\n"; - } else { - exeArg = "ExeArg=post-update-sync\n"; - exeAsync = "ExeAsync=false\n"; - } - } - - let updaterIniContents = "[Strings]\n" + - "Title=Update Test\n" + - "Info=Running update test " + gTestID + "\n\n" + - "[PostUpdateMac]\n" + - "ExeRelPath=" + DIR_RESOURCES + gPostUpdateBinFile + "\n" + - exeArg + - exeAsync + - "\n" + - "[PostUpdateWin]\n" + - "ExeRelPath=" + gPostUpdateBinFile + "\n" + - exeArg + - exeAsync; - let updaterIni = getApplyDirFile(DIR_RESOURCES + FILE_UPDATER_INI, true); - writeFile(updaterIni, updaterIniContents); -} - -/** - * Helper function for updater binary tests for verifying the contents of the - * update log after a successful update. - * - * @param aCompareLogFile - * The log file to compare the update log with. - * @param aExcludeDistributionDir - * Removes lines containing the distribution directory from the log - * file to compare the update log with. - */ -function checkUpdateLogContents(aCompareLogFile, aExcludeDistributionDir) { - if (IS_UNIX && !IS_MACOSX) { - // Sorting on Linux is different so skip checking the logs for now. - return; - } - let updateLog = getUpdatesPatchDir(); - updateLog.append(FILE_UPDATE_LOG); - let updateLogContents = readFileBytes(updateLog); - - // The channel-prefs.js is defined in gTestFilesCommon which will always be - // located to the end of gTestFiles. - if (gTestFiles.length > 1 && - gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" && - !gTestFiles[gTestFiles.length - 1].originalContents) { - updateLogContents = updateLogContents.replace(/.*defaults\/.*/g, ""); - } - if (gTestFiles.length > 2 && - gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI && - !gTestFiles[gTestFiles.length - 2].originalContents) { - updateLogContents = updateLogContents.replace(/.*update-settings.ini.*/g, ""); - } - if (gStageUpdate) { - // Skip the staged update messages - updateLogContents = updateLogContents.replace(/Performing a staged update/, ""); - } else if (gSwitchApp) { - // Skip the switch app request messages - updateLogContents = updateLogContents.replace(/Performing a staged update/, ""); - updateLogContents = updateLogContents.replace(/Performing a replace request/, ""); - } - // Skip the source/destination lines since they contain absolute paths. - updateLogContents = updateLogContents.replace(/PATCH DIRECTORY.*/g, ""); - updateLogContents = updateLogContents.replace(/INSTALLATION DIRECTORY.*/g, ""); - updateLogContents = updateLogContents.replace(/WORKING DIRECTORY.*/g, ""); - // Skip lines that log failed attempts to open the callback executable. - updateLogContents = updateLogContents.replace(/NS_main: callback app file .*/g, ""); - if (IS_MACOSX) { - // Skip lines that log moving the distribution directory for Mac v2 signing. - updateLogContents = updateLogContents.replace(/Moving old [^\n]*\nrename_file: .*/g, ""); - updateLogContents = updateLogContents.replace(/New distribution directory .*/g, ""); - } - if (gSwitchApp) { - // Remove the lines which contain absolute paths - updateLogContents = updateLogContents.replace(/^Begin moving.*$/mg, ""); - updateLogContents = updateLogContents.replace(/^ensure_remove: failed to remove file: .*$/mg, ""); - updateLogContents = updateLogContents.replace(/^ensure_remove_recursive: unable to remove directory: .*$/mg, ""); - updateLogContents = updateLogContents.replace(/^Removing tmpDir failed, err: -1$/mg, ""); - updateLogContents = updateLogContents.replace(/^remove_recursive_on_reboot: .*$/mg, ""); - } - updateLogContents = updateLogContents.replace(/\r/g, ""); - // Replace error codes since they are different on each platform. - updateLogContents = updateLogContents.replace(/, err:.*\n/g, "\n"); - // Replace to make the log parsing happy. - updateLogContents = updateLogContents.replace(/non-fatal error /g, ""); - // The FindFile results when enumerating the filesystem on Windows is not - // determistic so the results matching the following need to be ignored. - updateLogContents = updateLogContents.replace(/.*7\/7text.*\n/g, ""); - // Remove consecutive newlines - updateLogContents = updateLogContents.replace(/\n+/g, "\n"); - // Remove leading and trailing newlines - updateLogContents = updateLogContents.replace(/^\n|\n$/g, ""); - // The update log when running the service tests sometimes starts with data - // from the previous launch of the updater. - updateLogContents = updateLogContents.replace(/^calling QuitProgressUI\n[^\n]*\nUPDATE TYPE/g, "UPDATE TYPE"); - - let compareLogContents = ""; - if (aCompareLogFile) { - compareLogContents = readFileBytes(getTestDirFile(aCompareLogFile)); - } - if (gSwitchApp) { - compareLogContents += LOG_SWITCH_SUCCESS; - } - // The channel-prefs.js is defined in gTestFilesCommon which will always be - // located to the end of gTestFiles. - if (gTestFiles.length > 1 && - gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" && - !gTestFiles[gTestFiles.length - 1].originalContents) { - compareLogContents = compareLogContents.replace(/.*defaults\/.*/g, ""); - } - if (gTestFiles.length > 2 && - gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI && - !gTestFiles[gTestFiles.length - 2].originalContents) { - compareLogContents = compareLogContents.replace(/.*update-settings.ini.*/g, ""); - } - if (aExcludeDistributionDir) { - compareLogContents = compareLogContents.replace(/.*distribution\/.*/g, ""); - } - // Remove leading and trailing newlines - compareLogContents = compareLogContents.replace(/\n+/g, "\n"); - // Remove leading and trailing newlines - compareLogContents = compareLogContents.replace(/^\n|\n$/g, ""); - - // Don't write the contents of the file to the log to reduce log spam - // unless there is a failure. - if (compareLogContents == updateLogContents) { - logTestInfo("log contents are correct"); - do_check_true(true); - } else { - logTestInfo("log contents are not correct"); - do_check_eq(compareLogContents, updateLogContents); - } -} - -/** - * Helper function to check if the update log contains a string. - * - * @param aCheckString - * The string to check if the update log contains. - */ -function checkUpdateLogContains(aCheckString) { - let updateLog = getUpdatesPatchDir(); - updateLog.append(FILE_UPDATE_LOG); - let updateLogContents = readFileBytes(updateLog); - if (updateLogContents.indexOf(aCheckString) != -1) { - logTestInfo("log file does contain: " + aCheckString); - do_check_true(true); - } else { - logTestInfo("log file does not contain: " + aCheckString); - logTestInfo("log file contents:\n" + updateLogContents); - do_check_true(false); - } -} - -/** - * Helper function for updater binary tests for verifying the state of files and - * directories after a successful update. - * - * @param aGetFileFunc - * The function used to get the files in the directory to be checked. - * @param aStageDirExists - * If true the staging directory will be tested for existence and if - * false the staging directory will be tested for non-existence. - * @param aToBeDeletedDirExists - * On Windows, if true the tobedeleted directory will be tested for - * existence and if false the tobedeleted directory will be tested for - * non-existence. On all othere platforms it will be tested for - * non-existence. - */ -function checkFilesAfterUpdateSuccess(aGetFileFunc, aStageDirExists, - aToBeDeletedDirExists) { - logTestInfo("testing contents of files after a successful update"); - gTestFiles.forEach(function CFAUS_TF_FE(aTestFile) { - let testFile = aGetFileFunc(aTestFile.relPathDir + aTestFile.fileName, true); - logTestInfo("testing file: " + testFile.path); - if (aTestFile.compareFile || aTestFile.compareContents) { - do_check_true(testFile.exists()); - - // Skip these tests on Windows and OS/2 since their - // implementaions of chmod doesn't really set permissions. - if (!IS_WIN && aTestFile.comparePerms) { - // Check if the permssions as set in the complete mar file are correct. - let logPerms = "testing file permissions - "; - if (aTestFile.originalPerms) { - logPerms += "original permissions: " + - aTestFile.originalPerms.toString(8) + ", "; - } - logPerms += "compare permissions : " + - aTestFile.comparePerms.toString(8) + ", "; - logPerms += "updated permissions : " + testFile.permissions.toString(8); - logTestInfo(logPerms); - do_check_eq(testFile.permissions & 0xfff, aTestFile.comparePerms & 0xfff); - } - - let fileContents1 = readFileBytes(testFile); - let fileContents2 = aTestFile.compareFile ? - readFileBytes(getTestDirFile(aTestFile.compareFile)) : - aTestFile.compareContents; - // Don't write the contents of the file to the log to reduce log spam - // unless there is a failure. - if (fileContents1 == fileContents2) { - logTestInfo("file contents are correct"); - do_check_true(true); - } else { - logTestInfo("file contents are not correct"); - do_check_eq(fileContents1, fileContents2); - } - } else { - do_check_false(testFile.exists()); - } - }); - - logTestInfo("testing operations specified in removed-files were performed " + - "after a successful update"); - gTestDirs.forEach(function CFAUS_TD_FE(aTestDir) { - let testDir = aGetFileFunc(aTestDir.relPathDir, true); - logTestInfo("testing directory: " + testDir.path); - if (aTestDir.dirRemoved) { - do_check_false(testDir.exists()); - } else { - do_check_true(testDir.exists()); - - if (aTestDir.files) { - aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) { - let testFile = aGetFileFunc(aTestDir.relPathDir + aTestFile, true); - logTestInfo("testing directory file: " + testFile.path); - if (aTestDir.filesRemoved) { - do_check_false(testFile.exists()); - } else { - do_check_true(testFile.exists()); - } - }); - } - - if (aTestDir.subDirs) { - aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) { - let testSubDir = aGetFileFunc(aTestDir.relPathDir + aSubDir, true); - logTestInfo("testing sub-directory: " + testSubDir.path); - do_check_true(testSubDir.exists()); - if (aTestDir.subDirFiles) { - aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) { - let testFile = aGetFileFunc(aTestDir.relPathDir + - aSubDir + aTestFile, true); - logTestInfo("testing sub-directory file: " + testFile.path); - do_check_true(testFile.exists()); - }); - } - }); - } - } - }); - - checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, - aToBeDeletedDirExists); -} - -/** - * Helper function for updater binary tests for verifying the state of files and - * directories after a failed update. - * - * @param aGetFileFunc - * the function used to get the files in the directory to be checked. - * @param aStageDirExists - * If true the staging directory will be tested for existence and if - * false the staging directory will be tested for non-existence. - * @param aToBeDeletedDirExists - * On Windows, if true the tobedeleted directory will be tested for - * existence and if false the tobedeleted directory will be tested for - * non-existence. On all othere platforms it will be tested for - * non-existence. - */ -function checkFilesAfterUpdateFailure(aGetFileFunc, aStageDirExists, - aToBeDeletedDirExists) { - logTestInfo("testing contents of files after a failed update"); - gTestFiles.forEach(function CFAUF_TF_FE(aTestFile) { - let testFile = aGetFileFunc(aTestFile.relPathDir + aTestFile.fileName, true); - logTestInfo("testing file: " + testFile.path); - if (aTestFile.compareFile || aTestFile.compareContents) { - do_check_true(testFile.exists()); - - // Skip these tests on Windows and OS/2 since their - // implementaions of chmod doesn't really set permissions. - if (!IS_WIN && aTestFile.comparePerms) { - // Check the original permssions are retained on the file. - let logPerms = "testing file permissions - "; - if (aTestFile.originalPerms) { - logPerms += "original permissions: " + - aTestFile.originalPerms.toString(8) + ", "; - } - logPerms += "compare permissions : " + - aTestFile.comparePerms.toString(8) + ", "; - logPerms += "updated permissions : " + testFile.permissions.toString(8); - logTestInfo(logPerms); - do_check_eq(testFile.permissions & 0xfff, aTestFile.comparePerms & 0xfff); - } - - let fileContents1 = readFileBytes(testFile); - let fileContents2 = aTestFile.compareFile ? - readFileBytes(getTestDirFile(aTestFile.compareFile)) : - aTestFile.compareContents; - // Don't write the contents of the file to the log to reduce log spam - // unless there is a failure. - if (fileContents1 == fileContents2) { - logTestInfo("file contents are correct"); - do_check_true(true); - } else { - logTestInfo("file contents are not correct"); - do_check_eq(fileContents1, fileContents2); - } - } else { - do_check_false(testFile.exists()); - } - }); - - logTestInfo("testing operations specified in removed-files were not " + - "performed after a failed update"); - gTestDirs.forEach(function CFAUF_TD_FE(aTestDir) { - let testDir = aGetFileFunc(aTestDir.relPathDir, true); - logTestInfo("testing directory: " + testDir.path); - do_check_true(testDir.exists()); - - if (aTestDir.files) { - aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) { - let testFile = aGetFileFunc(aTestDir.relPathDir + aTestFile, true); - logTestInfo("testing directory file: " + testFile.path); - do_check_true(testFile.exists()); - }); - } - - if (aTestDir.subDirs) { - aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) { - let testSubDir = aGetFileFunc(aTestDir.relPathDir + aSubDir, true); - logTestInfo("testing sub-directory: " + testSubDir.path); - do_check_true(testSubDir.exists()); - if (aTestDir.subDirFiles) { - aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) { - let testFile = aGetFileFunc(aTestDir.relPathDir + - aSubDir + aTestFile, true); - logTestInfo("testing sub-directory file: " + testFile.path); - do_check_true(testFile.exists()); - }); - } - }); - } - }); - - checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, - aToBeDeletedDirExists); -} - -/** - * Helper function for updater binary tests for verifying the state of common - * files and directories after a successful or failed update. - * - * @param aGetFileFunc - * the function used to get the files in the directory to be checked. - * @param aStageDirExists - * If true the staging directory will be tested for existence and if - * false the staging directory will be tested for non-existence. - * @param aToBeDeletedDirExists - * On Windows, if true the tobedeleted directory will be tested for - * existence and if false the tobedeleted directory will be tested for - * non-existence. On all othere platforms it will be tested for - * non-existence. - */ -function checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, - aToBeDeletedDirExists) { - logTestInfo("testing extra directories"); - - let stageDir = getStageDirFile(null, true); - logTestInfo("testing directory should " + - (aStageDirExists ? "" : "not ") + - "exist: " + stageDir.path); - do_check_eq(stageDir.exists(), aStageDirExists); - - let toBeDeletedDirExists = IS_WIN ? aToBeDeletedDirExists : false; - let toBeDeletedDir = getApplyDirFile(DIR_TOBEDELETED, true); - logTestInfo("testing directory should " + - (toBeDeletedDirExists ? "" : "not ") + - "exist: " + toBeDeletedDir.path); - do_check_eq(toBeDeletedDir.exists(), toBeDeletedDirExists); - - logTestInfo("testing updating directory doesn't exist in the application " + - "directory"); - let updatingDir = getApplyDirFile("updating", true); - do_check_false(updatingDir.exists()); - - if (stageDir.exists()) { - logTestInfo("testing updating directory doesn't exist in the staging " + - "directory"); - updatingDir = stageDir.clone(); - updatingDir.append("updating"); - do_check_false(updatingDir.exists()); - } - - logTestInfo("testing backup files should not be left behind in the " + - "application directory"); - let applyToDir = getApplyDirFile(null, true); - checkFilesInDirRecursive(applyToDir, checkForBackupFiles); - - if (stageDir.exists()) { - logTestInfo("testing backup files should not be left behind in the " + - "staging directory"); - let applyToDir = getApplyDirFile(null, true); - checkFilesInDirRecursive(stageDir, checkForBackupFiles); - } - - logTestInfo("testing patch files should not be left behind"); - let updatesDir = getUpdatesPatchDir(); - let entries = updatesDir.QueryInterface(AUS_Ci.nsIFile).directoryEntries; - while (entries.hasMoreElements()) { - let entry = entries.getNext().QueryInterface(AUS_Ci.nsIFile); - do_check_neq(getFileExtension(entry), "patch"); - } -} - -/** - * Helper function for updater binary tests for verifying the contents of the - * updater callback application log which should contain the arguments passed to - * the callback application. - */ -function checkCallbackAppLog() { - let appLaunchLog = getApplyDirFile(DIR_RESOURCES + gCallbackArgs[1], true); - if (!appLaunchLog.exists()) { - do_timeout(TEST_HELPER_TIMEOUT, checkCallbackAppLog); - return; - } - - let expectedLogContents = gCallbackArgs.join("\n") + "\n"; - let logContents = readFile(appLaunchLog); - // It is possible for the log file contents check to occur before the log file - // contents are completely written so wait until the contents are the expected - // value. If the contents are never the expected value then the test will - // fail by timing out. - if (logContents != expectedLogContents) { - do_timeout(TEST_HELPER_TIMEOUT, checkCallbackAppLog); - return; - } - - if (logContents == expectedLogContents) { - logTestInfo("callback log file contents are correct"); - do_check_true(true); - } else { - logTestInfo("callback log file contents are not correct"); - do_check_eq(logContents, expectedLogContents); - } - - waitForFilesInUse(); -} - -/** - * Helper function for updater binary tests for getting the log and running - * files created by the test helper binary file when called with the post-update - * command line argument. - * - * @param aSuffix - * The string to append to the post update test helper binary path. - */ -function getPostUpdateFile(aSuffix) { - return getApplyDirFile(DIR_RESOURCES + gPostUpdateBinFile + aSuffix, true); -} - -/** - * Helper function for updater binary tests for verifying the contents of the - * updater post update binary log. - */ -function checkPostUpdateAppLog() { - gTimeoutRuns++; - let postUpdateLog = getPostUpdateFile(".log"); - if (!postUpdateLog.exists()) { - logTestInfo("postUpdateLog does not exist. Path: " + postUpdateLog.path); - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the post update " + - "process to create the post update log. Path: " + - postUpdateLog.path); - } - do_timeout(TEST_HELPER_TIMEOUT, checkPostUpdateAppLog); - return; - } - - let logContents = readFile(postUpdateLog); - // It is possible for the log file contents check to occur before the log file - // contents are completely written so wait until the contents are the expected - // value. If the contents are never the expected value then the test will - // fail by timing out. - if (logContents != "post-update\n") { - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the post update " + - "process to create the expected contents in the post update log. Path: " + - postUpdateLog.path); - } - do_timeout(TEST_HELPER_TIMEOUT, checkPostUpdateAppLog); - return; - } - - logTestInfo("post update app log file contents are correct"); - do_check_true(true); - - gCheckFunc(); -} - -/** - * Helper function for updater service tests for verifying the contents of the - * updater callback application log which should contain the arguments passed to - * the callback application. - */ -function checkCallbackServiceLog() { - do_check_neq(gServiceLaunchedCallbackLog, null); - - let expectedLogContents = gServiceLaunchedCallbackArgs.join("\n") + "\n"; - let logFile = AUS_Cc["@mozilla.org/file/local;1"].createInstance(AUS_Ci.nsILocalFile); - logFile.initWithPath(gServiceLaunchedCallbackLog); - let logContents = readFile(logFile); - // It is possible for the log file contents check to occur before the log file - // contents are completely written so wait until the contents are the expected - // value. If the contents are never the expected value then the test will - // fail by timing out. - if (logContents != expectedLogContents) { - logTestInfo("callback service log not expected value, waiting longer"); - do_timeout(TEST_HELPER_TIMEOUT, checkCallbackServiceLog); - return; - } - - logTestInfo("testing that the callback application successfully launched " + - "and the expected command line arguments were passed to it"); - do_check_eq(logContents, expectedLogContents); - - waitForFilesInUse(); -} - -// Waits until files that are in use that break tests are no longer in use and -// then calls do_test_finished. -function waitForFilesInUse() { - if (IS_WIN) { - let appBin = getApplyDirFile(FILE_APP_BIN, true); - let maintSvcInstaller = getApplyDirFile(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, true); - let helper = getApplyDirFile("uninstall/helper.exe", true); - let updater = getUpdatesPatchDir(); - updater.append(FILE_UPDATER_BIN); - - let files = [appBin, updater, maintSvcInstaller, helper]; - - for (var i = 0; i < files.length; ++i) { - let file = files[i]; - let fileBak = file.parent.clone(); - if (file.exists()) { - fileBak.append(file.leafName + ".bak"); - try { - if (fileBak.exists()) { - fileBak.remove(false); - } - file.copyTo(fileBak.parent, fileBak.leafName); - file.remove(false); - fileBak.moveTo(file.parent, file.leafName); - logTestInfo("file is not in use. Path: " + file.path); - } catch (e) { - logTestInfo("file in use, will try again after " + TEST_CHECK_TIMEOUT + - " ms, Path: " + file.path + ", Exception: " + e); - try { - if (fileBak.exists()) { - fileBak.remove(false); - } - } catch (e) { - logTestInfo("unable to remove file, this should never happen! " + - "Path: " + fileBak.path + ", Exception: " + e); - } - do_timeout(TEST_CHECK_TIMEOUT, waitForFilesInUse); - return; - } - } - } - } - - logTestInfo("calling doTestFinish"); - doTestFinish(); -} - -/** - * Helper function for updater binary tests for verifying there are no update - * backup files left behind after an update. - * - * @param aFile - * An nsIFile to check if it has moz-backup for its extension. - */ -function checkForBackupFiles(aFile) { - do_check_neq(getFileExtension(aFile), "moz-backup"); -} - -/** - * Helper function for updater binary tests for recursively enumerating a - * directory and calling a callback function with the file as a parameter for - * each file found. - * - * @param aDir - * A nsIFile for the directory to be deleted - * @param aCallback - * A callback function that will be called with the file as a - * parameter for each file found. - */ -function checkFilesInDirRecursive(aDir, aCallback) { - if (!aDir.exists()) - do_throw("Directory must exist!"); - - let dirEntries = aDir.directoryEntries; - while (dirEntries.hasMoreElements()) { - let entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile); - - if (entry.isDirectory()) { - checkFilesInDirRecursive(entry, aCallback); - } else { - aCallback(entry); - } - } -} - -/** - * Sets up the bare bones XMLHttpRequest implementation below. - * - * @param aCallback - * The callback function that will call the nsIDomEventListener's - * handleEvent method. - * - * Example of the callback function - * - * function callHandleEvent() { - * gXHR.status = gExpectedStatus; - * var e = { target: gXHR }; - * gXHR.onload.handleEvent(e); - * } - */ -function overrideXHR(aCallback) { - gXHRCallback = aCallback; - gXHR = new xhr(); - var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); - registrar.registerFactory(gXHR.classID, gXHR.classDescription, - gXHR.contractID, gXHR); -} - - -/** - * Bare bones XMLHttpRequest implementation for testing onprogress, onerror, - * and onload nsIDomEventListener handleEvent. - */ -function makeHandler(aVal) { - if (typeof aVal == "function") - return { handleEvent: aVal }; - return aVal; -} -function xhr() { -} -xhr.prototype = { - overrideMimeType: function(aMimetype) { }, - setRequestHeader: function(aHeader, aValue) { }, - status: null, - channel: { set notificationCallbacks(aVal) { } }, - _url: null, - _method: null, - open: function(aMethod, aUrl) { - gXHR.channel.originalURI = Services.io.newURI(aUrl, null, null); - gXHR._method = aMethod; gXHR._url = aUrl; - }, - responseXML: null, - responseText: null, - send: function(aBody) { - do_execute_soon(gXHRCallback); // Use a timeout so the XHR completes - }, - _onprogress: null, - set onprogress(aValue) { gXHR._onprogress = makeHandler(aValue); }, - get onprogress() { return gXHR._onprogress; }, - _onerror: null, - set onerror(aValue) { gXHR._onerror = makeHandler(aValue); }, - get onerror() { return gXHR._onerror; }, - _onload: null, - set onload(aValue) { gXHR._onload = makeHandler(aValue); }, - get onload() { return gXHR._onload; }, - addEventListener: function(aEvent, aValue, aCapturing) { - eval("gXHR._on" + aEvent + " = aValue"); - }, - flags: AUS_Ci.nsIClassInfo.SINGLETON, - implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT, - getHelperForLanguage: function(aLanguage) null, - getInterfaces: function(aCount) { - var interfaces = [AUS_Ci.nsISupports]; - aCount.value = interfaces.length; - return interfaces; - }, - classDescription: "XMLHttpRequest", - contractID: "@mozilla.org/xmlextras/xmlhttprequest;1", - classID: Components.ID("{c9b37f43-4278-4304-a5e0-600991ab08cb}"), - createInstance: function(aOuter, aIID) { - if (aOuter == null) - return gXHR.QueryInterface(aIID); - throw AUS_Cr.NS_ERROR_NO_AGGREGATION; - }, - QueryInterface: function(aIID) { - if (aIID.equals(AUS_Ci.nsIClassInfo) || - aIID.equals(AUS_Ci.nsISupports)) - return gXHR; - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - }, - get wrappedJSObject() { return this; } -}; - -/** - * Helper function to override the update prompt component to verify whether it - * is called or not. - * - * @param aCallback - * The callback to call if the update prompt component is called. - */ -function overrideUpdatePrompt(aCallback) { - var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); - gUpdatePrompt = new UpdatePrompt(); - gUpdatePromptCallback = aCallback; - registrar.registerFactory(gUpdatePrompt.classID, gUpdatePrompt.classDescription, - gUpdatePrompt.contractID, gUpdatePrompt); -} - -function UpdatePrompt() { - var fns = ["checkForUpdates", "showUpdateAvailable", "showUpdateDownloaded", - "showUpdateError", "showUpdateHistory", "showUpdateInstalled"]; - - fns.forEach(function(aPromptFn) { - UpdatePrompt.prototype[aPromptFn] = function() { - if (!gUpdatePromptCallback) { - return; - } - - var callback = gUpdatePromptCallback[aPromptFn]; - if (!callback) { - return; - } - - callback.apply(gUpdatePromptCallback, - Array.prototype.slice.call(arguments)); - } - }); -} - -UpdatePrompt.prototype = { - flags: AUS_Ci.nsIClassInfo.SINGLETON, - implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT, - getHelperForLanguage: function(aLanguage) null, - getInterfaces: function(aCount) { - var interfaces = [AUS_Ci.nsISupports, AUS_Ci.nsIUpdatePrompt]; - aCount.value = interfaces.length; - return interfaces; - }, - classDescription: "UpdatePrompt", - contractID: "@mozilla.org/updates/update-prompt;1", - classID: Components.ID("{8c350a15-9b90-4622-93a1-4d320308664b}"), - createInstance: function(aOuter, aIID) { - if (aOuter == null) - return gUpdatePrompt.QueryInterface(aIID); - throw AUS_Cr.NS_ERROR_NO_AGGREGATION; - }, - QueryInterface: function(aIID) { - if (aIID.equals(AUS_Ci.nsIClassInfo) || - aIID.equals(AUS_Ci.nsISupports) || - aIID.equals(AUS_Ci.nsIUpdatePrompt)) - return gUpdatePrompt; - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - }, -}; - -/* Update check listener */ -const updateCheckListener = { - onProgress: function UCL_onProgress(aRequest, aPosition, aTotalSize) { - }, - - onCheckComplete: function UCL_onCheckComplete(aRequest, aUpdates, aUpdateCount) { - gRequestURL = aRequest.channel.originalURI.spec; - gUpdateCount = aUpdateCount; - gUpdates = aUpdates; - logTestInfo("url = " + gRequestURL + ", " + - "request.status = " + aRequest.status + ", " + - "update.statusText = " + aRequest.statusText + ", " + - "updateCount = " + aUpdateCount); - // Use a timeout to allow the XHR to complete - do_execute_soon(gCheckFunc); - }, - - onError: function UCL_onError(aRequest, aUpdate) { - gRequestURL = aRequest.channel.originalURI.spec; - gStatusCode = aRequest.status; - - gStatusText = aUpdate.statusText; - logTestInfo("url = " + gRequestURL + ", " + - "request.status = " + gStatusCode + ", " + - "update.statusText = " + gStatusText); - // Use a timeout to allow the XHR to complete - do_execute_soon(gCheckFunc.bind(null, aRequest, aUpdate)); - }, - - QueryInterface: function(aIID) { - if (!aIID.equals(AUS_Ci.nsIUpdateCheckListener) && - !aIID.equals(AUS_Ci.nsISupports)) - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - return this; - } -}; - -/* Update download listener - nsIRequestObserver */ -const downloadListener = { - onStartRequest: function DL_onStartRequest(aRequest, aContext) { - }, - - onProgress: function DL_onProgress(aRequest, aContext, aProgress, aMaxProgress) { - }, - - onStatus: function DL_onStatus(aRequest, aContext, aStatus, aStatusText) { - }, - - onStopRequest: function DL_onStopRequest(aRequest, aContext, aStatus) { - gStatusResult = aStatus; - // Use a timeout to allow the request to complete - do_execute_soon(gCheckFunc); - }, - - QueryInterface: function DL_QueryInterface(aIID) { - if (!aIID.equals(AUS_Ci.nsIRequestObserver) && - !aIID.equals(AUS_Ci.nsIProgressEventSink) && - !aIID.equals(AUS_Ci.nsISupports)) - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - return this; - } -}; - -/** - * Helper for starting the http server used by the tests - */ -function start_httpserver() { - let dir = getTestDirFile(); - logTestInfo("http server directory path: " + dir.path); - - if (!dir.isDirectory()) { - do_throw("A file instead of a directory was specified for HttpServer " + - "registerDirectory! Path: " + dir.path); - } - - AUS_Cu.import("resource://testing-common/httpd.js"); - gTestserver = new HttpServer(); - gTestserver.registerDirectory("/", dir); - gTestserver.start(-1); - let testserverPort = gTestserver.identity.primaryPort; - gURLData = URL_HOST + ":" + testserverPort + "/"; - logTestInfo("http server port = " + testserverPort); -} - -/** - * Helper for stopping the http server used by the tests - * - * @param aCallback - * The callback to call after stopping the http server. - */ -function stop_httpserver(aCallback) { - do_check_true(!!aCallback); - gTestserver.stop(aCallback); -} - -/** - * Creates an nsIXULAppInfo - * - * @param aID - * The ID of the test application - * @param aName - * A name for the test application - * @param aVersion - * The version of the application - * @param aPlatformVersion - * The goanna version of the application - */ -function createAppInfo(aID, aName, aVersion, aPlatformVersion) { - const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1"; - const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}"); - var XULAppInfo = { - vendor: APP_INFO_VENDOR, - name: aName, - ID: aID, - version: aVersion, - appBuildID: "2007010101", - platformVersion: aPlatformVersion, - platformBuildID: "2007010101", - inSafeMode: false, - logConsoleErrors: true, - OS: "XPCShell", - XPCOMABI: "noarch-spidermonkey", - - QueryInterface: function QueryInterface(aIID) { - if (aIID.equals(AUS_Ci.nsIXULAppInfo) || - aIID.equals(AUS_Ci.nsIXULRuntime) || -#ifdef XP_WIN - aIID.equals(AUS_Ci.nsIWinAppHelper) || -#endif - aIID.equals(AUS_Ci.nsISupports)) - return this; - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - } - }; - - var XULAppInfoFactory = { - createInstance: function (aOuter, aIID) { - if (aOuter == null) - return XULAppInfo.QueryInterface(aIID); - throw AUS_Cr.NS_ERROR_NO_AGGREGATION; - } - }; - - var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); - registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo", - XULAPPINFO_CONTRACTID, XULAppInfoFactory); -} - -/** - * Returns the platform specific arguments used by nsIProcess when launching - * the application. - * - * @param aExtraArgs (optional) - * An array of extra arguments to append to the default arguments. - * @return an array of arguments to be passed to nsIProcess. - * - * Note: a shell is necessary to pipe the application's console output which - * would otherwise pollute the xpcshell log. - * - * Command line arguments used when launching the application: - * -no-remote prevents shell integration from being affected by an existing - * application process. - * -process-updates makes the application exits after being relaunched by the - * updater. - * the platform specific string defined by PIPE_TO_NULL to output both stdout - * and stderr to null. This is needed to prevent output from the application - * from ending up in the xpchsell log. - */ -function getProcessArgs(aExtraArgs) { - if (!aExtraArgs) { - aExtraArgs = []; - } - - let appBinPath = getApplyDirFile(DIR_MACOS + FILE_APP_BIN, false).path; - if (/ /.test(appBinPath)) { - appBinPath = '"' + appBinPath + '"'; - } - - let args; - if (IS_UNIX) { - let launchScript = getLaunchScript(); - // Precreate the script with executable permissions - launchScript.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY); - - let scriptContents = "#! /bin/sh\n"; - scriptContents += appBinPath + " -no-remote -process-updates " + - aExtraArgs.join(" ") + " " + PIPE_TO_NULL; - writeFile(launchScript, scriptContents); - logTestInfo("created " + launchScript.path + " containing:\n" + - scriptContents); - args = [launchScript.path]; - } else { - args = ["/D", "/Q", "/C", appBinPath, "-no-remote", "-process-updates"]. - concat(aExtraArgs).concat([PIPE_TO_NULL]); - } - return args; -} - -/** - * Gets a file path for the application to dump its arguments into. This is used - * to verify that a callback application is launched. - * - * @return the file for the application to dump its arguments into. - */ -function getAppArgsLogPath() { - let appArgsLog = do_get_file("/", true); - appArgsLog.append(gTestID + "_app_args_log"); - if (appArgsLog.exists()) { - appArgsLog.remove(false); - } - let appArgsLogPath = appArgsLog.path; - if (/ /.test(appArgsLogPath)) { - appArgsLogPath = '"' + appArgsLogPath + '"'; - } - return appArgsLogPath; -} - -/** - * Gets the nsIFile reference for the shell script to launch the application. If - * the file exists it will be removed by this function. - * - * @return the nsIFile for the shell script to launch the application. - */ -function getLaunchScript() { - let launchScript = do_get_file("/", true); - launchScript.append(gTestID + "_launch.sh"); - if (launchScript.exists()) { - launchScript.remove(false); - } - return launchScript; -} - -/** - * Makes GreD, XREExeF, and UpdRootD point to unique file system locations so - * xpcshell tests can run in parallel and to keep the environment clean. - */ -function adjustGeneralPaths() { - let dirProvider = { - getFile: function AGP_DP_getFile(aProp, aPersistent) { - aPersistent.value = true; - switch (aProp) { - case NS_GRE_DIR: - if (gUseTestAppDir) { - return getApplyDirFile(DIR_RESOURCES, true); - } - break; - case NS_GRE_BIN_DIR: - if (gUseTestAppDir) { - return getApplyDirFile(DIR_MACOS, true); - } - break; - case XRE_EXECUTABLE_FILE: - if (gUseTestAppDir) { - return getApplyDirFile(DIR_MACOS + FILE_APP_BIN, true); - } - break; - case XRE_UPDATE_ROOT_DIR: - return getMockUpdRootD(); - } - return null; - }, - QueryInterface: function(aIID) { - if (aIID.equals(AUS_Ci.nsIDirectoryServiceProvider) || - aIID.equals(AUS_Ci.nsISupports)) - return this; - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - } - }; - let ds = Services.dirsvc.QueryInterface(AUS_Ci.nsIDirectoryService); - ds.QueryInterface(AUS_Ci.nsIProperties).undefine(NS_GRE_DIR); - ds.QueryInterface(AUS_Ci.nsIProperties).undefine(NS_GRE_BIN_DIR); - ds.QueryInterface(AUS_Ci.nsIProperties).undefine(XRE_EXECUTABLE_FILE); - ds.registerProvider(dirProvider); - do_register_cleanup(function AGP_cleanup() { - logTestInfo("start - unregistering directory provider"); - - if (gAppTimer) { - logTestInfo("start - cancel app timer"); - gAppTimer.cancel(); - gAppTimer = null; - logTestInfo("finish - cancel app timer"); - } - - if (gProcess && gProcess.isRunning) { - logTestInfo("start - kill process"); - try { - gProcess.kill(); - } catch (e) { - logTestInfo("kill process failed. Exception: " + e); - } - gProcess = null; - logTestInfo("finish - kill process"); - } - - if (gHandle) { - try { - logTestInfo("start - closing handle"); - let kernel32 = ctypes.open("kernel32"); - let CloseHandle = kernel32.declare("CloseHandle", ctypes.default_abi, - ctypes.bool, /*return*/ - ctypes.voidptr_t /*handle*/); - if (!CloseHandle(gHandle)) { - logTestInfo("call to CloseHandle failed"); - } - kernel32.close(); - gHandle = null; - logTestInfo("finish - closing handle"); - } catch (e) { - logTestInfo("call to CloseHandle failed. Exception: " + e); - } - } - - // Call end_test first before the directory provider is unregistered - if (typeof(end_test) == typeof(Function)) { - logTestInfo("calling end_test"); - end_test(); - } - - ds.unregisterProvider(dirProvider); - cleanupTestCommon(); - - logTestInfo("finish - unregistering directory provider"); - }); -} - - -/** - * Helper function for launching the application to apply an update. - */ -function launchAppToApplyUpdate() { - logTestInfo("start - launching application to apply update"); - - let appBin = getApplyDirFile(DIR_MACOS + FILE_APP_BIN, false); - - if (typeof(customLaunchAppToApplyUpdate) == typeof(Function)) { - customLaunchAppToApplyUpdate(); - } - - let launchBin = getLaunchBin(); - let args = getProcessArgs(); - logTestInfo("launching " + launchBin.path + " " + args.join(" ")); - - gProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); - gProcess.init(launchBin); - - gAppTimer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer); - gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT, - AUS_Ci.nsITimer.TYPE_ONE_SHOT); - - setEnvironment(); - logTestInfo("launching application"); - gProcess.runAsync(args, args.length, gProcessObserver); - resetEnvironment(); - - logTestInfo("finish - launching application to apply update"); -} - -/** - * The observer for the call to nsIProcess:runAsync. - */ -let gProcessObserver = { - observe: function PO_observe(aSubject, aTopic, aData) { - logTestInfo("topic: " + aTopic + ", process exitValue: " + - gProcess.exitValue); - if (gAppTimer) { - gAppTimer.cancel(); - gAppTimer = null; - } - if (aTopic != "process-finished" || gProcess.exitValue != 0) { - do_throw("Failed to launch application"); - } - do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished); - }, - QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver]) -}; - -/** - * The timer callback to kill the process if it takes too long. - */ -let gTimerCallback = { - notify: function TC_notify(aTimer) { - gAppTimer = null; - if (gProcess.isRunning) { - logTestInfo("attempt to kill process"); - gProcess.kill(); - } - do_throw("launch application timer expired"); - }, - QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsITimerCallback]) -}; - -/** - * The update-staged observer for the call to nsIUpdateProcessor:processUpdate. - */ -let gUpdateStagedObserver = { - observe: function(aSubject, aTopic, aData) { - if (aTopic == "update-staged") { - Services.obs.removeObserver(gUpdateStagedObserver, "update-staged"); - checkUpdateApplied(); - } - }, - QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver]) -}; - -/** - * Sets the environment that will be used by the application process when it is - * launched. - */ -function setEnvironment() { - // Prevent setting the environment more than once. - if (gShouldResetEnv !== undefined) - return; - - gShouldResetEnv = true; - - let env = AUS_Cc["@mozilla.org/process/environment;1"]. - getService(AUS_Ci.nsIEnvironment); - if (IS_WIN && !env.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) { - gAddedEnvXRENoWindowsCrashDialog = true; - logTestInfo("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " + - "variable to 1... previously it didn't exist"); - env.set("XRE_NO_WINDOWS_CRASH_DIALOG", "1"); - } - - if (IS_UNIX) { - let appGreBinDir = gGREBinDirOrig.clone(); - let envGreBinDir = AUS_Cc["@mozilla.org/file/local;1"]. - createInstance(AUS_Ci.nsILocalFile); - let shouldSetEnv = true; - if (IS_MACOSX) { - if (env.exists("DYLD_LIBRARY_PATH")) { - gEnvDyldLibraryPath = env.get("DYLD_LIBRARY_PATH"); - envGreBinDir.initWithPath(gEnvDyldLibraryPath); - if (envGreBinDir.path == appGreBinDir.path) { - gEnvDyldLibraryPath = null; - shouldSetEnv = false; - } - } - - if (shouldSetEnv) { - logTestInfo("setting DYLD_LIBRARY_PATH environment variable value to " + - appGreBinDir.path); - env.set("DYLD_LIBRARY_PATH", appGreBinDir.path); - } - } else { - if (env.exists("LD_LIBRARY_PATH")) { - gEnvLdLibraryPath = env.get("LD_LIBRARY_PATH"); - envGreBinDir.initWithPath(gEnvLdLibraryPath); - if (envGreBinDir.path == appGreBinDir.path) { - gEnvLdLibraryPath = null; - shouldSetEnv = false; - } - } - - if (shouldSetEnv) { - logTestInfo("setting LD_LIBRARY_PATH environment variable value to " + - appGreBinDir.path); - env.set("LD_LIBRARY_PATH", appGreBinDir.path); - } - } - } - - if (env.exists("XPCOM_MEM_LEAK_LOG")) { - gEnvXPCOMMemLeakLog = env.get("XPCOM_MEM_LEAK_LOG"); - logTestInfo("removing the XPCOM_MEM_LEAK_LOG environment variable... " + - "previous value " + gEnvXPCOMMemLeakLog); - env.set("XPCOM_MEM_LEAK_LOG", ""); - } - - if (env.exists("XPCOM_DEBUG_BREAK")) { - gEnvXPCOMDebugBreak = env.get("XPCOM_DEBUG_BREAK"); - logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " + - "warn... previous value " + gEnvXPCOMDebugBreak); - } else { - logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " + - "warn... previously it didn't exist"); - } - - env.set("XPCOM_DEBUG_BREAK", "warn"); - - if (gStageUpdate) { - logTestInfo("setting the MOZ_UPDATE_STAGING environment variable to 1"); - env.set("MOZ_UPDATE_STAGING", "1"); - } - - logTestInfo("setting MOZ_NO_SERVICE_FALLBACK environment variable to 1"); - env.set("MOZ_NO_SERVICE_FALLBACK", "1"); -} - -/** - * Sets the environment back to the original values after launching the - * application. - */ -function resetEnvironment() { - // Prevent resetting the environment more than once. - if (gShouldResetEnv !== true) - return; - - gShouldResetEnv = false; - - let env = AUS_Cc["@mozilla.org/process/environment;1"]. - getService(AUS_Ci.nsIEnvironment); - - if (gEnvXPCOMMemLeakLog) { - logTestInfo("setting the XPCOM_MEM_LEAK_LOG environment variable back to " + - gEnvXPCOMMemLeakLog); - env.set("XPCOM_MEM_LEAK_LOG", gEnvXPCOMMemLeakLog); - } - - if (gEnvXPCOMDebugBreak) { - logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable back to " + - gEnvXPCOMDebugBreak); - env.set("XPCOM_DEBUG_BREAK", gEnvXPCOMDebugBreak); - } else { - logTestInfo("clearing the XPCOM_DEBUG_BREAK environment variable"); - env.set("XPCOM_DEBUG_BREAK", ""); - } - - if (IS_UNIX) { - if (IS_MACOSX) { - if (gEnvDyldLibraryPath) { - logTestInfo("setting DYLD_LIBRARY_PATH environment variable value " + - "back to " + gEnvDyldLibraryPath); - env.set("DYLD_LIBRARY_PATH", gEnvDyldLibraryPath); - } else { - logTestInfo("removing DYLD_LIBRARY_PATH environment variable"); - env.set("DYLD_LIBRARY_PATH", ""); - } - } else { - if (gEnvLdLibraryPath) { - logTestInfo("setting LD_LIBRARY_PATH environment variable value back " + - "to " + gEnvLdLibraryPath); - env.set("LD_LIBRARY_PATH", gEnvLdLibraryPath); - } else { - logTestInfo("removing LD_LIBRARY_PATH environment variable"); - env.set("LD_LIBRARY_PATH", ""); - } - } - } - - if (IS_WIN && gAddedEnvXRENoWindowsCrashDialog) { - logTestInfo("removing the XRE_NO_WINDOWS_CRASH_DIALOG environment " + - "variable"); - env.set("XRE_NO_WINDOWS_CRASH_DIALOG", ""); - } - - if (gStageUpdate) { - logTestInfo("removing the MOZ_UPDATE_STAGING environment variable"); - env.set("MOZ_UPDATE_STAGING", ""); - } - logTestInfo("removing MOZ_NO_SERVICE_FALLBACK environment variable"); - env.set("MOZ_NO_SERVICE_FALLBACK", ""); -} +load("../data/xpcshellUtilsAUS.js"); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js b/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js index 86eb09af48..703f61f3ec 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js @@ -41,13 +41,13 @@ function callHandleEvent() { gXHR.status = 400; gXHR.responseText = gResponseBody; try { - var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"]. - createInstance(AUS_Ci.nsIDOMParser); + let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml"); } catch (e) { gXHR.responseXML = null; } - var e = { target: gXHR }; + let e = { target: gXHR }; gXHR.onload(e); } @@ -63,13 +63,13 @@ function run_test_pt02() { gUpdates = null; gUpdateCount = null; gCheckFunc = check_test_pt02; - var patches = getRemotePatchString("complete", "http://complete/", "SHA1", + let patches = getRemotePatchString("complete", "http://complete/", "SHA1", "98db9dad8e1d80eda7e1170d0187d6f53e477059", "9856459"); patches += getRemotePatchString("partial", "http://partial/", "SHA1", "e6678ca40ae7582316acdeddf3c133c9c8577de4", "1316138"); - var updates = getRemoteUpdateString(patches, "minor", "Minor Test", + let updates = getRemoteUpdateString(patches, "minor", "Minor Test", "version 2.1a1pre", "2.1a1pre", "3.1a1pre", "20080811053724", "http://details/", @@ -87,19 +87,19 @@ function check_test_pt02() { // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244 // and until this is fixed this will not test the value for detailsURL when it // isn't specified in the update xml. -// var defaultDetailsURL; +// let defaultDetailsURL; // try { // Try using a default details URL supplied by the distribution // if the update XML does not supply one. -// var formatter = AUS_Cc["@mozilla.org/toolkit/URLFormatterService;1"]. -// getService(AUS_Ci.nsIURLFormatter); +// let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]. +// getService(Ci.nsIURLFormatter); // defaultDetailsURL = formatter.formatURLPref(PREF_APP_UPDATE_URL_DETAILS); // } catch (e) { // defaultDetailsURL = ""; // } do_check_eq(gUpdateCount, 1); - var bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount).QueryInterface(AUS_Ci.nsIPropertyBag); + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount).QueryInterface(Ci.nsIPropertyBag); do_check_eq(bestUpdate.type, "minor"); do_check_eq(bestUpdate.name, "Minor Test"); do_check_eq(bestUpdate.displayVersion, "version 2.1a1pre"); @@ -129,7 +129,7 @@ function check_test_pt02() { do_check_eq(bestUpdate.getProperty("custom1_attr"), "custom1 value"); do_check_eq(bestUpdate.getProperty("custom2_attr"), "custom2 value"); - var patch = bestUpdate.getPatchAt(0); + let patch = bestUpdate.getPatchAt(0); do_check_eq(patch.type, "complete"); do_check_eq(patch.URL, "http://complete/"); do_check_eq(patch.hashFunction, "SHA1"); @@ -164,10 +164,10 @@ function run_test_pt03() { gUpdates = null; gUpdateCount = null; gCheckFunc = check_test_pt03; - var patches = getRemotePatchString("complete", "http://complete/", "SHA1", + let patches = getRemotePatchString("complete", "http://complete/", "SHA1", "98db9dad8e1d80eda7e1170d0187d6f53e477059", "9856459"); - var updates = getRemoteUpdateString(patches, "major", "Major Test", + let updates = getRemoteUpdateString(patches, "major", "Major Test", null, null, "5.1a1pre", "20080811053724", "http://details/", @@ -179,7 +179,7 @@ function run_test_pt03() { function check_test_pt03() { do_check_eq(gUpdateCount, 1); - var bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); do_check_eq(bestUpdate.type, "major"); do_check_eq(bestUpdate.name, "Major Test"); do_check_eq(bestUpdate.displayVersion, "version 4.1a1pre"); @@ -206,7 +206,7 @@ function check_test_pt03() { do_check_eq(bestUpdate.patchCount, 1); //XXX TODO - test nsIUpdate:serialize - var patch = bestUpdate.getPatchAt(0); + let patch = bestUpdate.getPatchAt(0); do_check_eq(patch.type, "complete"); do_check_eq(patch.URL, "http://complete/"); do_check_eq(patch.hashFunction, "SHA1"); @@ -240,9 +240,9 @@ function run_test_pt05() { // one update available with two patches function run_test_pt06() { - var patches = getRemotePatchString("complete"); + let patches = getRemotePatchString("complete"); patches += getRemotePatchString("partial"); - var updates = getRemoteUpdateString(patches); + let updates = getRemoteUpdateString(patches); gResponseBody = getRemoteUpdatesXMLString(updates); run_test_helper_pt1("testing one update available", 1, run_test_pt07); @@ -250,9 +250,9 @@ function run_test_pt06() { // three updates available each with two patches function run_test_pt07() { - var patches = getRemotePatchString("complete"); + let patches = getRemotePatchString("complete"); patches += getRemotePatchString("partial"); - var updates = getRemoteUpdateString(patches); + let updates = getRemoteUpdateString(patches); updates += getRemoteUpdateString(patches); updates += getRemoteUpdateString(patches); gResponseBody = getRemoteUpdatesXMLString(updates); @@ -263,9 +263,9 @@ function run_test_pt07() { // one update with complete and partial patches with size 0 specified in the // update xml function run_test_pt08() { - var patches = getRemotePatchString("complete", null, null, null, "0"); + let patches = getRemotePatchString("complete", null, null, null, "0"); patches += getRemotePatchString("partial", null, null, null, "0"); - var updates = getRemoteUpdateString(patches); + let updates = getRemoteUpdateString(patches); gResponseBody = getRemoteUpdatesXMLString(updates); run_test_helper_pt1("testing one update with complete and partial " + "patches with size 0", 0, run_test_pt09); @@ -273,8 +273,8 @@ function run_test_pt08() { // one update with complete patch with size 0 specified in the update xml function run_test_pt09() { - var patches = getRemotePatchString("complete", null, null, null, "0"); - var updates = getRemoteUpdateString(patches); + let patches = getRemotePatchString("complete", null, null, null, "0"); + let updates = getRemoteUpdateString(patches); gResponseBody = getRemoteUpdatesXMLString(updates); run_test_helper_pt1("testing one update with complete patch with size 0", 0, run_test_pt10); @@ -282,8 +282,8 @@ function run_test_pt09() { // one update with partial patch with size 0 specified in the update xml function run_test_pt10() { - var patches = getRemotePatchString("partial", null, null, null, "0"); - var updates = getRemoteUpdateString(patches); + let patches = getRemotePatchString("partial", null, null, null, "0"); + let updates = getRemoteUpdateString(patches); gResponseBody = getRemoteUpdatesXMLString(updates); run_test_helper_pt1("testing one update with partial patch with size 0", 0, run_test_pt11); @@ -291,9 +291,9 @@ function run_test_pt10() { // check that updates for older versions of the application aren't selected function run_test_pt11() { - var patches = getRemotePatchString("complete"); + let patches = getRemotePatchString("complete"); patches += getRemotePatchString("partial"); - var updates = getRemoteUpdateString(patches, "minor", null, null, "1.0pre"); + let updates = getRemoteUpdateString(patches, "minor", null, null, "1.0pre"); updates += getRemoteUpdateString(patches, "minor", null, null, "1.0a"); gResponseBody = getRemoteUpdatesXMLString(updates); run_test_helper_pt1("testing two updates older than the current version", @@ -301,23 +301,23 @@ function run_test_pt11() { } function check_test_pt11() { - var bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); do_check_eq(bestUpdate, null); run_test_pt12(); } // check that updates for the current version of the application are selected function run_test_pt12() { - var patches = getRemotePatchString("complete"); + let patches = getRemotePatchString("complete"); patches += getRemotePatchString("partial"); - var updates = getRemoteUpdateString(patches, "minor", null, "version 1.0"); + let updates = getRemoteUpdateString(patches, "minor", null, "version 1.0"); gResponseBody = getRemoteUpdatesXMLString(updates); run_test_helper_pt1("testing one update equal to the current version", 1, check_test_pt12); } function check_test_pt12() { - var bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); do_check_neq(bestUpdate, null); do_check_eq(bestUpdate.displayVersion, "version 1.0"); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js b/toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js index 46a47c160e..6a01875f2b 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js @@ -15,7 +15,7 @@ function run_test() { Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false); - let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), "Fake Window Watcher", "@mozilla.org/embedcomp/window-watcher;1", @@ -52,7 +52,7 @@ function run_test() { // didn't throw and otherwise it would report no tests run. do_check_true(true); - registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); + registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), WindowWatcherFactory); registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af56}"), @@ -69,46 +69,36 @@ function check_showUpdateAvailable() { do_throw("showUpdateAvailable should not have called openWindow!"); } -var WindowWatcher = { +const WindowWatcher = { openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) { gCheckFunc(); }, - QueryInterface: function(aIID) { - if (aIID.equals(AUS_Ci.nsIWindowWatcher) || - aIID.equals(AUS_Ci.nsISupports)) - return this; + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]) +}; - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - } -} - -var WindowWatcherFactory = { +const WindowWatcherFactory = { createInstance: function createInstance(aOuter, aIID) { - if (aOuter != null) - throw AUS_Cr.NS_ERROR_NO_AGGREGATION; + if (aOuter != null) { + throw Cr.NS_ERROR_NO_AGGREGATION; + } return WindowWatcher.QueryInterface(aIID); } }; -var WindowMediator = { +const WindowMediator = { getMostRecentWindow: function(aWindowType) { - return { getInterface: XPCOMUtils.generateQI([AUS_Ci.nsIDOMWindow]) }; + return { getInterface: XPCOMUtils.generateQI([Ci.nsIDOMWindow]) }; }, - QueryInterface: function(aIID) { - if (aIID.equals(AUS_Ci.nsIWindowMediator) || - aIID.equals(AUS_Ci.nsISupports)) - return this; - - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - } + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediator]) } -var WindowMediatorFactory = { +const WindowMediatorFactory = { createInstance: function createInstance(aOuter, aIID) { - if (aOuter != null) - throw AUS_Cr.NS_ERROR_NO_AGGREGATION; + if (aOuter != null) { + throw Cr.NS_ERROR_NO_AGGREGATION; + } return WindowMediator.QueryInterface(aIID); } }; diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js index 174740dffa..eb55cf6e1f 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js @@ -16,7 +16,7 @@ function run_test() { Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true); - let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), "Fake Window Watcher", "@mozilla.org/embedcomp/window-watcher;1", @@ -57,7 +57,7 @@ function run_test() { // didn't throw and otherwise it would report no tests run. do_check_true(true); - registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); + registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), WindowWatcherFactory); @@ -76,7 +76,7 @@ function check_showUpdateError() { do_throw("showUpdateError should not have seen getNewPrompter!"); } -var WindowWatcher = { +const WindowWatcher = { openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) { gCheckFunc(); }, @@ -85,19 +85,14 @@ var WindowWatcher = { gCheckFunc(); }, - QueryInterface: function(aIID) { - if (aIID.equals(AUS_Ci.nsIWindowWatcher) || - aIID.equals(AUS_Ci.nsISupports)) - return this; + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]) +}; - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - } -} - -var WindowWatcherFactory = { +const WindowWatcherFactory = { createInstance: function createInstance(aOuter, aIID) { - if (aOuter != null) - throw AUS_Cr.NS_ERROR_NO_AGGREGATION; + if (aOuter != null) { + throw Cr.NS_ERROR_NO_AGGREGATION; + } return WindowWatcher.QueryInterface(aIID); } }; diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js b/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js index 0b3979ab88..e29c6a3f4b 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js @@ -15,7 +15,7 @@ function run_test() { overrideXHR(callHandleEvent); standardInit(); - let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), "Fake Window Watcher", "@mozilla.org/embedcomp/window-watcher;1", @@ -51,7 +51,7 @@ function check_test() { } function end_test() { - let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), WindowWatcherFactory); registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af56}"), @@ -64,12 +64,12 @@ function callHandleEvent() { gXHR.status = 400; gXHR.responseText = gResponseBody; try { - var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"]. - createInstance(AUS_Ci.nsIDOMParser); + let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml"); } catch (e) { } - var e = { target: gXHR }; + let e = { target: gXHR }; gXHR.onload(e); } @@ -77,46 +77,36 @@ function check_showUpdateAvailable() { do_throw("showUpdateAvailable should not have called openWindow!"); } -var WindowWatcher = { +const WindowWatcher = { openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) { check_showUpdateAvailable(); }, - QueryInterface: function(aIID) { - if (aIID.equals(AUS_Ci.nsIWindowWatcher) || - aIID.equals(AUS_Ci.nsISupports)) - return this; + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]) +}; - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - } -} - -var WindowWatcherFactory = { +const WindowWatcherFactory = { createInstance: function createInstance(aOuter, aIID) { - if (aOuter != null) - throw AUS_Cr.NS_ERROR_NO_AGGREGATION; + if (aOuter != null) { + throw Cr.NS_ERROR_NO_AGGREGATION; + } return WindowWatcher.QueryInterface(aIID); } }; -var WindowMediator = { +const WindowMediator = { getMostRecentWindow: function(aWindowType) { return null; }, - QueryInterface: function(aIID) { - if (aIID.equals(AUS_Ci.nsIWindowMediator) || - aIID.equals(AUS_Ci.nsISupports)) - return this; + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediator]) +}; - throw AUS_Cr.NS_ERROR_NO_INTERFACE; - } -} - -var WindowMediatorFactory = { +const WindowMediatorFactory = { createInstance: function createInstance(aOuter, aIID) { - if (aOuter != null) - throw AUS_Cr.NS_ERROR_NO_AGGREGATION; + if (aOuter != null) { + throw Cr.NS_ERROR_NO_AGGREGATION; + } return WindowMediator.QueryInterface(aIID); } }; diff --git a/toolkit/mozapps/update/tests/unit_aus_update/updateCheckOnLoadOnErrorStatusText.js b/toolkit/mozapps/update/tests/unit_aus_update/updateCheckOnLoadOnErrorStatusText.js index 563f3fd2a3..982cefee68 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/updateCheckOnLoadOnErrorStatusText.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/updateCheckOnLoadOnErrorStatusText.js @@ -29,7 +29,7 @@ function run_test() { // call the nsIDOMEventListener's handleEvent method for onload. function callHandleEvent() { gXHR.status = gExpectedStatusCode; - var e = { target: gXHR }; + let e = { target: gXHR }; gXHR.onload(e); } @@ -46,7 +46,7 @@ function run_test_helper(aNextRunFunc, aExpectedStatusCode, aMsg) { function check_test_helper() { do_check_eq(gStatusCode, gExpectedStatusCode); - var expectedStatusText = getStatusText(gExpectedStatusCode); + let expectedStatusText = getStatusText(gExpectedStatusCode); do_check_eq(gStatusText, expectedStatusText); gNextRunFunc(); } @@ -67,7 +67,7 @@ function run_test_pt1() { function check_test_pt1() { do_check_eq(gStatusCode, gExpectedStatusCode); - var expectedStatusText = getStatusText(404); + let expectedStatusText = getStatusText(404); do_check_eq(gStatusText, expectedStatusText); run_test_pt2(); } @@ -98,55 +98,55 @@ function run_test_pt5() { // failed (unknown reason) - NS_BINDING_FAILED (2152398849) function run_test_pt6() { - run_test_helper(run_test_pt7, AUS_Cr.NS_BINDING_FAILED, + run_test_helper(run_test_pt7, Cr.NS_BINDING_FAILED, "testing failed (unknown reason)"); } // connection timed out - NS_ERROR_NET_TIMEOUT (2152398862) function run_test_pt7() { - run_test_helper(run_test_pt8, AUS_Cr.NS_ERROR_NET_TIMEOUT, + run_test_helper(run_test_pt8, Cr.NS_ERROR_NET_TIMEOUT, "testing connection timed out"); } // network offline - NS_ERROR_OFFLINE (2152398864) function run_test_pt8() { - run_test_helper(run_test_pt9, AUS_Cr.NS_ERROR_OFFLINE, + run_test_helper(run_test_pt9, Cr.NS_ERROR_OFFLINE, "testing network offline"); } // port not allowed - NS_ERROR_PORT_ACCESS_NOT_ALLOWED (2152398867) function run_test_pt9() { - run_test_helper(run_test_pt10, AUS_Cr.NS_ERROR_PORT_ACCESS_NOT_ALLOWED, + run_test_helper(run_test_pt10, Cr.NS_ERROR_PORT_ACCESS_NOT_ALLOWED, "testing port not allowed"); } // no data was received - NS_ERROR_NET_RESET (2152398868) function run_test_pt10() { - run_test_helper(run_test_pt11, AUS_Cr.NS_ERROR_NET_RESET, + run_test_helper(run_test_pt11, Cr.NS_ERROR_NET_RESET, "testing no data was received"); } // update server not found - NS_ERROR_UNKNOWN_HOST (2152398878) function run_test_pt11() { - run_test_helper(run_test_pt12, AUS_Cr.NS_ERROR_UNKNOWN_HOST, + run_test_helper(run_test_pt12, Cr.NS_ERROR_UNKNOWN_HOST, "testing update server not found"); } // proxy server not found - NS_ERROR_UNKNOWN_PROXY_HOST (2152398890) function run_test_pt12() { - run_test_helper(run_test_pt13, AUS_Cr.NS_ERROR_UNKNOWN_PROXY_HOST, + run_test_helper(run_test_pt13, Cr.NS_ERROR_UNKNOWN_PROXY_HOST, "testing proxy server not found"); } // data transfer interrupted - NS_ERROR_NET_INTERRUPT (2152398919) function run_test_pt13() { - run_test_helper(run_test_pt14, AUS_Cr.NS_ERROR_NET_INTERRUPT, + run_test_helper(run_test_pt14, Cr.NS_ERROR_NET_INTERRUPT, "testing data transfer interrupted"); } // proxy server connection refused - NS_ERROR_PROXY_CONNECTION_REFUSED (2152398920) function run_test_pt14() { - run_test_helper(run_test_pt15, AUS_Cr.NS_ERROR_PROXY_CONNECTION_REFUSED, + run_test_helper(run_test_pt15, Cr.NS_ERROR_PROXY_CONNECTION_REFUSED, "testing proxy server connection refused"); } @@ -158,12 +158,12 @@ function run_test_pt15() { // network is offline - NS_ERROR_DOCUMENT_NOT_CACHED (2152398918) function run_test_pt16() { - run_test_helper(run_test_pt17, AUS_Cr.NS_ERROR_DOCUMENT_NOT_CACHED, + run_test_helper(run_test_pt17, Cr.NS_ERROR_DOCUMENT_NOT_CACHED, "testing network is offline"); } // connection refused - NS_ERROR_CONNECTION_REFUSED (2152398861) function run_test_pt17() { - run_test_helper(doTestFinish, AUS_Cr.NS_ERROR_CONNECTION_REFUSED, + run_test_helper(doTestFinish, Cr.NS_ERROR_CONNECTION_REFUSED, "testing connection refused"); } diff --git a/toolkit/mozapps/update/tests/unit_aus_update/updateHealthReport.js b/toolkit/mozapps/update/tests/unit_aus_update/updateHealthReport.js index b1fd4ce5ac..8d0b8573f8 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/updateHealthReport.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/updateHealthReport.js @@ -3,9 +3,6 @@ "use strict"; -const {utils: Cu, classes: Cc, interfaces: Ci} = Components; - - Cu.import("resource://gre/modules/Metrics.jsm"); Cu.import("resource://gre/modules/UpdaterHealthProvider.jsm"); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js index e2b91c60f0..83c984a2bc 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js @@ -12,21 +12,21 @@ function run_test() { setUpdateChannel("test_channel"); - var patch, patches, update, updates; // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244 // and until bug 470244 is fixed this will not test the value for detailsURL // when it isn't specified in the update xml. - patches = getLocalPatchString("partial", "http://partial/", "SHA256", "cd43", - "86", "true", STATE_PENDING); - updates = getLocalUpdateString(patches, "major", "New", "version 4", "4.0", - "4.0", "20070811053724", "http://details1/", - "http://billboard1/", "http://license1/", - "http://service1/", "1238441300314", - "test status text", "false", "test_channel", - "true", "true", "true", "345600", "true", - "test version", "3.0", "3.0", - "custom1_attr=\"custom1 value\"", - "custom2_attr=\"custom2 value\""); + let patches = getLocalPatchString("partial", "http://partial/", "SHA256", + "cd43", "86", "true", STATE_PENDING); + let updates = getLocalUpdateString(patches, "major", "New", "version 4", + "4.0", "4.0", "20070811053724", + "http://details1/", "http://billboard1/", + "http://license1/", "http://service1/", + "1238441300314", "test status text", + "false", "test_channel", "true", "true", + "true", "345600", "true", "test version", + "3.0", "3.0", + "custom1_attr=\"custom1 value\"", + "custom2_attr=\"custom2 value\""); writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); writeStatusFile(STATE_SUCCEEDED); @@ -48,7 +48,7 @@ function run_test() { do_check_eq(gUpdateManager.activeUpdate, null); do_check_eq(gUpdateManager.updateCount, 2); - update = gUpdateManager.getUpdateAt(0).QueryInterface(AUS_Ci.nsIPropertyBag); + let update = gUpdateManager.getUpdateAt(0).QueryInterface(Ci.nsIPropertyBag); do_check_eq(update.state, STATE_SUCCEEDED); do_check_eq(update.type, "major"); do_check_eq(update.name, "New"); @@ -73,7 +73,7 @@ function run_test() { do_check_eq(update.getProperty("custom1_attr"), "custom1 value"); do_check_eq(update.getProperty("custom2_attr"), "custom2 value"); - patch = update.selectedPatch; + let patch = update.selectedPatch; do_check_eq(patch.type, "partial"); do_check_eq(patch.URL, "http://partial/"); do_check_eq(patch.hashFunction, "SHA256"); @@ -82,7 +82,7 @@ function run_test() { do_check_true(patch.selected); do_check_eq(patch.state, STATE_SUCCEEDED); - update = gUpdateManager.getUpdateAt(1).QueryInterface(AUS_Ci.nsIPropertyBag); + update = gUpdateManager.getUpdateAt(1).QueryInterface(Ci.nsIPropertyBag); do_check_eq(update.state, STATE_FAILED); do_check_eq(update.name, "Existing"); do_check_eq(update.type, "major"); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/updateRootDirMigration_win.js b/toolkit/mozapps/update/tests/unit_aus_update/updateRootDirMigration_win.js index 9fcf6e52a5..74080aa95e 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/updateRootDirMigration_win.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/updateRootDirMigration_win.js @@ -6,12 +6,12 @@ const PREF_APP_UPDATE_MIGRATE_APP_DIR = "app.update.migrated.updateDir"; function clearTaskbarIDHash(exePath, appInfoName) { - let registry = AUS_Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(AUS_Ci.nsIWindowsRegKey); + let registry = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); try { - registry.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + registry.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, "Software\\Mozilla\\" + appInfoName + "\\TaskBarIDs", - AUS_Ci.nsIWindowsRegKey.ACCESS_ALL); + Ci.nsIWindowsRegKey.ACCESS_ALL); registry.removeValue(exePath); } catch (e) { } @@ -21,12 +21,12 @@ function clearTaskbarIDHash(exePath, appInfoName) { } function setTaskbarIDHash(exePath, hash, appInfoName) { - let registry = AUS_Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(AUS_Ci.nsIWindowsRegKey); + let registry = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); try { - registry.create(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + registry.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, "Software\\Mozilla\\" + appInfoName + "\\TaskBarIDs", - AUS_Ci.nsIWindowsRegKey.ACCESS_WRITE); + Ci.nsIWindowsRegKey.ACCESS_WRITE); registry.writeStringValue(exePath, hash); } catch (e) { } @@ -36,7 +36,7 @@ function setTaskbarIDHash(exePath, hash, appInfoName) { }; function getMigrated() { - var migrated = 0; + let migrated = 0; try { migrated = Services.prefs.getBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR); } catch (e) { @@ -51,14 +51,14 @@ function run_test() { standardInit(); - var appinfo = AUS_Cc["@mozilla.org/xre/app-info;1"]. - getService(AUS_Ci.nsIXULAppInfo). - QueryInterface(AUS_Ci.nsIXULRuntime); + let appinfo = Cc["@mozilla.org/xre/app-info;1"]. + getService(Ci.nsIXULAppInfo). + QueryInterface(Ci.nsIXULRuntime); // Obtain the old update root leaf - var updateLeafName; - var exeFile = FileUtils.getFile(XRE_EXECUTABLE_FILE, []); - var programFiles = FileUtils.getFile("ProgF", []); + let updateLeafName; + let exeFile = FileUtils.getFile(XRE_EXECUTABLE_FILE, []); + let programFiles = FileUtils.getFile("ProgF", []); if (exeFile.path.substring(0, programFiles.path.length).toLowerCase() == programFiles.path.toLowerCase()) { updateLeafName = exeFile.parent.leafName; @@ -67,7 +67,7 @@ function run_test() { } // Obtain the old update root - var oldUpdateRoot; + let oldUpdateRoot; if (appinfo.vendor) { oldUpdateRoot = FileUtils.getDir("LocalAppData", [appinfo.vendor, appinfo.name, @@ -77,7 +77,7 @@ function run_test() { updateLeafName], false); } // Obtain the new update root - var newUpdateRoot = FileUtils.getDir("UpdRootD", [], false); + let newUpdateRoot = FileUtils.getDir("UpdRootD", [], false); /////////////////////////////////////////////////////////// // Setting a taskbar ID without the old update dir existing should set the @@ -112,14 +112,14 @@ function run_test() { Services.prefs.setBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR, false); setTaskbarIDHash(exeFile.parent.path, "AAAAAAAA", appinfo.name); - var oldUpdateDirs = oldUpdateRoot.clone(); + let oldUpdateDirs = oldUpdateRoot.clone(); oldUpdateDirs.append("updates"); oldUpdateDirs.append("0"); - oldUpdateDirs.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + oldUpdateDirs.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); // Get an array of all of the files we want to migrate. // We do this to create them in the old update directory. - var filesToMigrate = [FILE_UPDATES_DB, FILE_UPDATE_ACTIVE, + let filesToMigrate = [FILE_UPDATES_DB, FILE_UPDATE_ACTIVE, ["updates", FILE_LAST_LOG], ["updates", FILE_BACKUP_LOG], ["updates", "0", FILE_UPDATE_STATUS]]; // Move each of those files to the new directory @@ -132,7 +132,7 @@ function run_test() { } else { oldFile.append(relPath); } - oldFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); + oldFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); }); // Do the migration initUpdateServiceStub(); @@ -163,9 +163,9 @@ function run_test() { } function end_test() { - var appinfo = AUS_Cc["@mozilla.org/xre/app-info;1"]. - getService(AUS_Ci.nsIXULAppInfo). - QueryInterface(AUS_Ci.nsIXULRuntime); - var exeFile = FileUtils.getFile(XRE_EXECUTABLE_FILE, []); + let appinfo = Cc["@mozilla.org/xre/app-info;1"]. + getService(Ci.nsIXULAppInfo). + QueryInterface(Ci.nsIXULRuntime); + let exeFile = FileUtils.getFile(XRE_EXECUTABLE_FILE, []); clearTaskbarIDHash(exeFile.parent.path, appinfo.name); } diff --git a/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js b/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js index 10e475613d..8e85ba56e0 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js @@ -5,7 +5,7 @@ /* General URL Construction Tests */ -Components.utils.import("resource://gre/modules/ctypes.jsm") +Cu.import("resource://gre/modules/ctypes.jsm") const URL_PREFIX = URL_HOST + "/"; @@ -20,16 +20,16 @@ function run_test() { // The mock XMLHttpRequest is MUCH faster overrideXHR(callHandleEvent); standardInit(); - gAppInfo = AUS_Cc["@mozilla.org/xre/app-info;1"]. - getService(AUS_Ci.nsIXULAppInfo). - QueryInterface(AUS_Ci.nsIXULRuntime); + gAppInfo = Cc["@mozilla.org/xre/app-info;1"]. + getService(Ci.nsIXULAppInfo). + QueryInterface(Ci.nsIXULRuntime); do_execute_soon(run_test_pt1); } // Callback function used by the custom XMLHttpRequest implementation to // call the nsIDOMEventListener's handleEvent method for onload. function callHandleEvent() { - var e = { target: gXHR }; + let e = { target: gXHR }; gXHR.onload(e); } @@ -41,7 +41,7 @@ function getResult(url) { // url constructed with %PRODUCT% function run_test_pt1() { gCheckFunc = check_test_pt1; - var url = URL_PREFIX + "%PRODUCT%/"; + let url = URL_PREFIX + "%PRODUCT%/"; logTestInfo("testing url constructed with %PRODUCT% - " + url); setUpdateURLOverride(url); gUpdateChecker.checkForUpdates(updateCheckListener, true); @@ -55,7 +55,7 @@ function check_test_pt1() { // url constructed with %VERSION% function run_test_pt2() { gCheckFunc = check_test_pt2; - var url = URL_PREFIX + "%VERSION%/"; + let url = URL_PREFIX + "%VERSION%/"; logTestInfo("testing url constructed with %VERSION% - " + url); setUpdateURLOverride(url); gUpdateChecker.checkForUpdates(updateCheckListener, true); @@ -69,7 +69,7 @@ function check_test_pt2() { // url constructed with %BUILD_ID% function run_test_pt3() { gCheckFunc = check_test_pt3; - var url = URL_PREFIX + "%BUILD_ID%/"; + let url = URL_PREFIX + "%BUILD_ID%/"; logTestInfo("testing url constructed with %BUILD_ID% - " + url); setUpdateURLOverride(url); gUpdateChecker.checkForUpdates(updateCheckListener, true); @@ -84,14 +84,14 @@ function check_test_pt3() { // XXX TODO - it might be nice if we tested the actual ABI function run_test_pt4() { gCheckFunc = check_test_pt4; - var url = URL_PREFIX + "%BUILD_TARGET%/"; + let url = URL_PREFIX + "%BUILD_TARGET%/"; logTestInfo("testing url constructed with %BUILD_TARGET% - " + url); setUpdateURLOverride(url); gUpdateChecker.checkForUpdates(updateCheckListener, true); } function check_test_pt4() { - var abi; + let abi; try { abi = gAppInfo.XPCOMABI; } catch (e) { @@ -102,16 +102,12 @@ function check_test_pt4() { // Mac universal build should report a different ABI than either macppc // or mactel. This is necessary since nsUpdateService.js will set the ABI to // Universal-gcc3 for Mac universal builds. - var macutils = AUS_Cc["@mozilla.org/xpcom/mac-utils;1"]. - getService(AUS_Ci.nsIMacUtils); + let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"]. + getService(Ci.nsIMacUtils); - if (macutils.isUniversalBinary) + if (macutils.isUniversalBinary) { abi += "-u-" + macutils.architecturesInBinary; - if (IS_SHARK) { - // Disambiguate optimised and shark nightlies - abi += "-shark" } - } do_check_eq(getResult(gRequestURL), gAppInfo.OS + "_" + abi); @@ -122,7 +118,7 @@ function check_test_pt4() { // Bug 488936 added the update.locale file that stores the update locale function run_test_pt5() { gCheckFunc = check_test_pt5; - var url = URL_PREFIX + "%LOCALE%/"; + let url = URL_PREFIX + "%LOCALE%/"; logTestInfo("testing url constructed with %LOCALE% - " + url); setUpdateURLOverride(url); try { @@ -142,7 +138,7 @@ function check_test_pt5() { // url constructed with %CHANNEL% function run_test_pt6() { gCheckFunc = check_test_pt6; - var url = URL_PREFIX + "%CHANNEL%/"; + let url = URL_PREFIX + "%CHANNEL%/"; logTestInfo("testing url constructed with %CHANNEL% - " + url); setUpdateURLOverride(url); setUpdateChannel("test_channel"); @@ -157,7 +153,7 @@ function check_test_pt6() { // url constructed with %CHANNEL% with distribution partners function run_test_pt7() { gCheckFunc = check_test_pt7; - var url = URL_PREFIX + "%CHANNEL%/"; + let url = URL_PREFIX + "%CHANNEL%/"; logTestInfo("testing url constructed with %CHANNEL% - " + url); setUpdateURLOverride(url); gDefaultPrefBranch.setCharPref(PREF_APP_PARTNER_BRANCH + "test_partner1", "test_partner1"); @@ -173,7 +169,7 @@ function check_test_pt7() { // url constructed with %PLATFORM_VERSION% function run_test_pt8() { gCheckFunc = check_test_pt8; - var url = URL_PREFIX + "%PLATFORM_VERSION%/"; + let url = URL_PREFIX + "%PLATFORM_VERSION%/"; logTestInfo("testing url constructed with %PLATFORM_VERSION% - " + url); setUpdateURLOverride(url); gUpdateChecker.checkForUpdates(updateCheckListener, true); @@ -187,7 +183,7 @@ function check_test_pt8() { // url constructed with %OS_VERSION% function run_test_pt9() { gCheckFunc = check_test_pt9; - var url = URL_PREFIX + "%OS_VERSION%/"; + let url = URL_PREFIX + "%OS_VERSION%/"; logTestInfo("testing url constructed with %OS_VERSION% - " + url); setUpdateURLOverride(url); gUpdateChecker.checkForUpdates(updateCheckListener, true); @@ -231,7 +227,7 @@ function getServicePack() { let winVer = OSVERSIONINFOEXW(); winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size; - if(0 === GetVersionEx(winVer.address())) { + if (0 === GetVersionEx(winVer.address())) { // Using "throw" instead of "do_throw" (see NOTE above) throw("Failure in GetVersionEx (returned 0)"); } @@ -295,12 +291,11 @@ function getProcArchitecture() { } function check_test_pt9() { - var osVersion; - var sysInfo = AUS_Cc["@mozilla.org/system-info;1"]. - getService(AUS_Ci.nsIPropertyBag2); + let osVersion; + let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2); osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version"); - if(IS_WIN) { + if (IS_WIN) { try { let servicePack = getServicePack(); osVersion += "." + servicePack; @@ -308,7 +303,7 @@ function check_test_pt9() { do_throw("Failure obtaining service pack: " + e); } - if("5.0" === sysInfo.getProperty("version")) { // Win2K + if ("5.0" === sysInfo.getProperty("version")) { // Win2K osVersion += " (unknown)"; } else { try { @@ -336,7 +331,7 @@ function check_test_pt9() { // url constructed with %DISTRIBUTION% function run_test_pt10() { gCheckFunc = check_test_pt10; - var url = URL_PREFIX + "%DISTRIBUTION%/"; + let url = URL_PREFIX + "%DISTRIBUTION%/"; logTestInfo("testing url constructed with %DISTRIBUTION% - " + url); setUpdateURLOverride(url); gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_ID, "test_distro"); @@ -351,7 +346,7 @@ function check_test_pt10() { // url constructed with %DISTRIBUTION_VERSION% function run_test_pt11() { gCheckFunc = check_test_pt11; - var url = URL_PREFIX + "%DISTRIBUTION_VERSION%/"; + let url = URL_PREFIX + "%DISTRIBUTION_VERSION%/"; logTestInfo("testing url constructed with %DISTRIBUTION_VERSION% - " + url); setUpdateURLOverride(url); gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_VERSION, "test_distro_version"); @@ -366,7 +361,7 @@ function check_test_pt11() { // url with force param that doesn't already have a param - bug 454357 function run_test_pt12() { gCheckFunc = check_test_pt12; - var url = URL_PREFIX; + let url = URL_PREFIX; logTestInfo("testing url with force param that doesn't already have a " + "param - " + url); setUpdateURLOverride(url); @@ -381,7 +376,7 @@ function check_test_pt12() { // url with force param that already has a param - bug 454357 function run_test_pt13() { gCheckFunc = check_test_pt13; - var url = URL_PREFIX + "?extra=param"; + let url = URL_PREFIX + "?extra=param"; logTestInfo("testing url with force param that already has a param - " + url); logTestInfo("testing url constructed that has a parameter - " + url); setUpdateURLOverride(url); @@ -396,7 +391,7 @@ function check_test_pt13() { function run_test_pt14() { Services.prefs.setCharPref("app.update.custom", "custom"); gCheckFunc = check_test_pt14; - var url = URL_PREFIX + "?custom=%CUSTOM%"; + let url = URL_PREFIX + "?custom=%CUSTOM%"; logTestInfo("testing url constructed with %CUSTOM% - " + url); setUpdateURLOverride(url); gUpdateChecker.checkForUpdates(updateCheckListener, true); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini index 2a344a9868..1ad7dc582c 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini +++ b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini @@ -6,7 +6,6 @@ head = head_update.js tail = skip-if = toolkit == 'android' -generated-files = head_update.js [canCheckForAndCanApplyUpdates.js] [urlConstruction.js] @@ -38,7 +37,3 @@ reason = custom nsIUpdatePrompt [uiUnsupportedAlreadyNotified.js] skip-if = toolkit == 'gonk' reason = custom nsIUpdatePrompt -[updateRootDirMigration_win.js] -skip-if = os != 'win' -[updateHealthReport.js] -skip-if = ! healthreport diff --git a/toolkit/mozapps/update/tests/unit_base_updater/head_update.js b/toolkit/mozapps/update/tests/unit_base_updater/head_update.js new file mode 100644 index 0000000000..2db27288e6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/head_update.js @@ -0,0 +1,5 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +load("../data/xpcshellUtilsAUS.js"); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyDirLockedStageFailure_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyDirLockedStageFailure_win.js index e85933b153..3bc892f6c4 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyDirLockedStageFailure_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyDirLockedStageFailure_win.js @@ -89,5 +89,6 @@ function finishTest() { do_check_eq(readStatusState(), STATE_PENDING); checkFilesAfterUpdateFailure(getApplyDirFile, false, false); unlockDirectory(getAppBaseDir()); + standardInit(); waitForFilesInUse(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js index f7a127fe7e..61bdccd1c4 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js @@ -7,7 +7,7 @@ * apply it. */ -Components.utils.import("resource://gre/modules/ctypes.jsm"); +Cu.import("resource://gre/modules/ctypes.jsm"); function run_test() { if (MOZ_APP_NAME == "xulrunner") { diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseFallbackStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseFallbackStageFailureComplete_win.js index 40d6da251f..6bd118481f 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseFallbackStageFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseFallbackStageFailureComplete_win.js @@ -16,8 +16,8 @@ function run_test() { let callbackApp = getApplyDirFile(DIR_RESOURCES + gCallbackBinFile); let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let callbackAppProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let callbackAppProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); callbackAppProcess.init(callbackApp); callbackAppProcess.run(false, args, args.length); @@ -40,5 +40,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, false, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js index 7c4657e25d..3b1ed83e24 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js @@ -16,8 +16,8 @@ function run_test() { let callbackApp = getApplyDirFile(DIR_RESOURCES + gCallbackBinFile); let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let callbackAppProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let callbackAppProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); callbackAppProcess.init(callbackApp); callbackAppProcess.run(false, args, args.length); @@ -41,5 +41,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, true, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js index 4d20792cfb..4a63fa9c90 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js @@ -49,8 +49,8 @@ function run_test() { callbackApp.permissions = PERMS_DIRECTORY; let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let callbackAppProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let callbackAppProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); callbackAppProcess.init(callbackApp); callbackAppProcess.run(false, args, args.length); @@ -113,13 +113,14 @@ function checkUpdate() { checkSymlink(); } checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + standardInit(); checkCallbackAppLog(); } function runHelperProcess(args) { let helperBin = getTestDirFile(FILE_HELPER_BIN); - let process = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let process = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); process.init(helperBin); logTestInfo("Running " + helperBin.path + " " + args.join(" ")); process.run(true, args, args.length); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js index 450720dfa2..92613d48b6 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js @@ -15,8 +15,8 @@ function run_test() { callbackApp.permissions = PERMS_DIRECTORY; let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let callbackAppProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let callbackAppProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); callbackAppProcess.init(callbackApp); callbackAppProcess.run(false, args, args.length); @@ -53,5 +53,6 @@ function checkUpdate() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js index dd19b8d3ce..8bfa06d85b 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js @@ -23,5 +23,6 @@ function run_test() { function checkUpdateApplied() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js index 7d483381fd..e8cc9bca8d 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js @@ -23,5 +23,6 @@ function run_test() { function checkUpdateApplied() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js index d147dd9cef..a0ecb23550 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js @@ -17,5 +17,6 @@ function run_test() { function checkUpdateApplied() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js index f1f153c562..a80d1aeb4d 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js @@ -17,5 +17,6 @@ function run_test() { function checkUpdateApplied() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js index 98cb9c96b7..b24485e70b 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js @@ -26,7 +26,7 @@ function run_test() { } // Note that on platforms where we use execv, we cannot trust the return code. - runUpdate((USE_EXECV ? 0 : 1), STATE_FAILED_UNEXPECTED_FILE_OPERATION_ERROR); + runUpdate((USE_EXECV ? 0 : 1), STATE_FAILED_LOADSOURCE_ERROR_WRONG_SIZE); } /** @@ -50,5 +50,6 @@ function checkUpdateApplied() { checkFilesAfterUpdateFailure(getApplyDirFile, false, false); checkUpdateLogContents(LOG_PARTIAL_FAILURE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailureComplete_win.js index af360e2ae0..ce98564706 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailureComplete_win.js @@ -17,8 +17,8 @@ function run_test() { gTestFiles[13].fileName); let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -41,5 +41,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, false, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailurePartial_win.js index f847be9539..9d0b7b7087 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailurePartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailurePartial_win.js @@ -17,8 +17,8 @@ function run_test() { gTestFiles[11].fileName); let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -41,5 +41,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, false, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js index 7b417147f5..17fb0c7a02 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js @@ -17,8 +17,8 @@ function run_test() { gTestFiles[13].fileName); let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -42,5 +42,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, true, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js index 448caf5a35..8df2f1ea86 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js @@ -17,8 +17,8 @@ function run_test() { gTestFiles[11].fileName); let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -42,5 +42,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, true, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js index 83ca06c52e..61e85cacff 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js @@ -15,8 +15,8 @@ function run_test() { gTestFiles[13].fileName); let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js index 41c856f09a..3db36ab081 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js @@ -15,8 +15,8 @@ function run_test() { gTestFiles[11].fileName); let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -34,5 +34,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); checkUpdateLogContains(ERR_BACKUP_DISCARD); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js index a785f60b0c..58f04ea359 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js @@ -25,8 +25,8 @@ function run_test() { lockFileRelPath = lockFileRelPath.join("/") + "/" + gTestFiles[3].fileName; let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT, lockFileRelPath]; - let lockFileProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let lockFileProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); lockFileProcess.init(helperBin); lockFileProcess.run(false, args, args.length); @@ -44,5 +44,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, false, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js index 6318f4e902..92b2503663 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js @@ -25,8 +25,8 @@ function run_test() { lockFileRelPath = lockFileRelPath.join("/") + "/" + gTestFiles[2].fileName; let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT, lockFileRelPath]; - let lockFileProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let lockFileProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); lockFileProcess.init(helperBin); lockFileProcess.run(false, args, args.length); @@ -44,5 +44,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, false, false); checkUpdateLogContains(ERR_UNABLE_OPEN_DEST); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailureComplete_win.js index 28e0ebff53..0e90452912 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailureComplete_win.js @@ -26,8 +26,8 @@ function run_test() { lockFileRelPath = lockFileRelPath.join("/") + "/" + gTestFiles[3].fileName; let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT, lockFileRelPath]; - let lockFileProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let lockFileProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); lockFileProcess.init(helperBin); lockFileProcess.run(false, args, args.length); @@ -35,7 +35,7 @@ function run_test() { } function doUpdate() { - runUpdate(1, STATE_FAILED_WRITE_ERROR, null); + runUpdate(1, STATE_FAILED_WRITE_ERROR_FILE_COPY, null); // Switch the application to the staged application that was updated. gStageUpdate = false; @@ -50,5 +50,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, false, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailurePartial_win.js index 6a73a435ec..8f1c1bbd5a 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailurePartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailurePartial_win.js @@ -26,8 +26,8 @@ function run_test() { lockFileRelPath = lockFileRelPath.join("/") + "/" + gTestFiles[2].fileName; let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT, lockFileRelPath]; - let lockFileProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let lockFileProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); lockFileProcess.init(helperBin); lockFileProcess.run(false, args, args.length); @@ -35,7 +35,7 @@ function run_test() { } function doUpdate() { - runUpdate(1, STATE_FAILED_WRITE_ERROR, null); + runUpdate(1, STATE_FAILED_WRITE_ERROR_FILE_COPY, null); // Switch the application to the staged application that was updated. gStageUpdate = false; @@ -50,5 +50,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, false, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js index 4e3ea512a4..e65451663d 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js @@ -26,8 +26,8 @@ function run_test() { lockFileRelPath = lockFileRelPath.join("/") + "/" + gTestFiles[3].fileName; let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT, lockFileRelPath]; - let lockFileProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let lockFileProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); lockFileProcess.init(helperBin); lockFileProcess.run(false, args, args.length); @@ -35,7 +35,7 @@ function run_test() { } function doUpdate() { - runUpdate(1, STATE_FAILED_WRITE_ERROR, null); + runUpdate(1, STATE_FAILED_WRITE_ERROR_FILE_COPY, null); // Switch the application to the staged application that was updated. gStageUpdate = false; @@ -51,5 +51,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, true, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js index b2b9a4c932..916830f902 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js @@ -26,8 +26,8 @@ function run_test() { lockFileRelPath = lockFileRelPath.join("/") + "/" + gTestFiles[2].fileName; let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT, lockFileRelPath]; - let lockFileProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let lockFileProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); lockFileProcess.init(helperBin); lockFileProcess.run(false, args, args.length); @@ -35,7 +35,7 @@ function run_test() { } function doUpdate() { - runUpdate(1, STATE_FAILED_WRITE_ERROR, null); + runUpdate(1, STATE_FAILED_WRITE_ERROR_FILE_COPY, null); // Switch the application to the staged application that was updated. gStageUpdate = false; @@ -51,5 +51,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, true, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailureComplete_win.js index b197f143e4..326dac1e0d 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailureComplete_win.js @@ -28,8 +28,8 @@ function run_test() { // Launch an existing file so it is in use during the update. let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -52,5 +52,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, false, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailurePartial_win.js index 77eaeae5fa..7e2ec9ced6 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailurePartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailurePartial_win.js @@ -26,8 +26,8 @@ function run_test() { // Launch an existing file so it is in use during the update. let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -50,5 +50,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, false, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailureComplete_win.js index d7fa3e7463..6cee739c54 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailureComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailureComplete_win.js @@ -28,8 +28,8 @@ function run_test() { // Launch an existing file so it is in use during the update. let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -53,5 +53,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, true, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailurePartial_win.js index 5c9a520da0..78304a9230 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailurePartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailurePartial_win.js @@ -26,8 +26,8 @@ function run_test() { // Launch an existing file so it is in use during the update. let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -51,5 +51,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateFailure(getApplyDirFile, true, false); checkUpdateLogContains(ERR_RENAME_FILE); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js index 5d57cb0337..7e1e9cb10c 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js @@ -25,8 +25,8 @@ function run_test() { // Launch an existing file so it is in use during the update. let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -44,5 +44,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); checkUpdateLogContains(ERR_BACKUP_DISCARD); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js index da4b3a23bc..1f97290085 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js @@ -23,8 +23,8 @@ function run_test() { // Launch an existing file so it is in use during the update. let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); fileInUseProcess.init(fileInUseBin); fileInUseProcess.run(false, args, args.length); @@ -42,5 +42,6 @@ function checkUpdateApplied() { function checkUpdate() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); checkUpdateLogContains(ERR_BACKUP_DISCARD); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js index 12feb4ab6b..73c31d30ea 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js @@ -26,7 +26,7 @@ function run_test() { applyToDir.lastModifiedTime = yesterday; } - runUpdate(1, STATE_FAILED_UNEXPECTED_FILE_OPERATION_ERROR); + runUpdate(1, STATE_FAILED_LOADSOURCE_ERROR_WRONG_SIZE); } /** @@ -41,5 +41,6 @@ function checkUpdateApplied() { checkFilesAfterUpdateFailure(getApplyDirFile, true, false); checkUpdateLogContents(LOG_PARTIAL_FAILURE); + standardInit(); waitForFilesInUse(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js index ab4307ed50..d3e2e4efea 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js @@ -118,13 +118,14 @@ function finishCheckUpdateApplied() { } checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + standardInit(); checkCallbackAppLog(); } function runHelperProcess(args) { let helperBin = getTestDirFile(FILE_HELPER_BIN); - let process = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); + let process = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); process.init(helperBin); logTestInfo("Running " + helperBin.path + " " + args.join(" ")); process.run(true, args, args.length); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js index ef4c407ffc..4c384b2e58 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js @@ -111,5 +111,6 @@ function finishCheckUpdateApplied() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); checkUpdateLogContents(LOG_PARTIAL_SUCCESS, true); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js index a7c6ff3a25..d4d3df602e 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js @@ -91,5 +91,6 @@ function finishCheckUpdateApplied() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js index ad64c6722a..63561bedc7 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js @@ -81,5 +81,6 @@ function finishCheckUpdateApplied() { checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); checkUpdateLogContents(LOG_PARTIAL_SUCCESS); + standardInit(); checkCallbackAppLog(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js b/toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js index 0dce2aa5d3..993b3aec9e 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js @@ -37,5 +37,6 @@ function checkUpdateApplied() { } checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); + standardInit(); doTestFinish(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js index 7552e4ddbb..ee96fe3848 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js +++ b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js @@ -37,5 +37,6 @@ function checkUpdateApplied() { } checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); + standardInit(); doTestFinish(); } diff --git a/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini b/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini index ea9e0d08b5..3bab34c9c1 100644 --- a/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini +++ b/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini @@ -10,7 +10,6 @@ head = head_update.js tail = skip-if = toolkit == 'android' -generated-files = head_update.js [marSuccessComplete.js] [marSuccessPartial.js] diff --git a/toolkit/mozapps/update/tests/unit_service_updater/head_update.js b/toolkit/mozapps/update/tests/unit_service_updater/head_update.js new file mode 100644 index 0000000000..2db27288e6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/head_update.js @@ -0,0 +1,5 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +load("../data/xpcshellUtilsAUS.js"); diff --git a/toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js b/toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js index 9ab331f7de..6a3f7b5b80 100644 --- a/toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js +++ b/toolkit/mozapps/update/tests/unit_timermanager/consumerNotifications.js @@ -7,12 +7,10 @@ 'use strict'; -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cm = Components.manager; -const Cr = Components.results; +const { classes: Cc, interfaces: Ci, manager: Cm, results: Cr, + utils: Cu } = Components; -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); const CATEGORY_UPDATE_TIMER = "update-timer"; @@ -215,7 +213,7 @@ function run_test1thru7() { function finished_test1thru7() { if (TESTS[4].notified && TESTS[5].notified && TESTS[6].notified) { - do_timeout(0, gNextFunc); + do_execute_soon(gNextFunc); } } @@ -270,7 +268,7 @@ function check_test1thru7() { "registered"); do_check_eq(count, 0); - do_timeout(0, run_test8); + do_execute_soon(run_test8); } function run_test8() { @@ -316,9 +314,9 @@ const gTest1TimerCallback = { }; const gTest1Factory = { - createInstance: function (outer, iid) { - if (outer == null) { - return gTest1TimerCallback.QueryInterface(iid); + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gTest1TimerCallback.QueryInterface(aIID); } throw Cr.NS_ERROR_NO_AGGREGATION; } @@ -332,9 +330,9 @@ const gTest2TimerCallback = { }; const gTest2Factory = { - createInstance: function (outer, iid) { - if (outer == null) { - return gTest2TimerCallback.QueryInterface(iid); + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gTest2TimerCallback.QueryInterface(aIID); } throw Cr.NS_ERROR_NO_AGGREGATION; } @@ -348,9 +346,9 @@ const gTest3TimerCallback = { }; const gTest3Factory = { - createInstance: function (outer, iid) { - if (outer == null) { - return gTest3TimerCallback.QueryInterface(iid); + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gTest3TimerCallback.QueryInterface(aIID); } throw Cr.NS_ERROR_NO_AGGREGATION; } @@ -361,9 +359,9 @@ const gTest4TimerCallback = { }; const gTest4Factory = { - createInstance: function (outer, iid) { - if (outer == null) { - return gTest4TimerCallback.QueryInterface(iid); + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gTest4TimerCallback.QueryInterface(aIID); } throw Cr.NS_ERROR_NO_AGGREGATION; } @@ -379,9 +377,9 @@ const gTest5TimerCallback = { }; const gTest5Factory = { - createInstance: function (outer, iid) { - if (outer == null) { - return gTest5TimerCallback.QueryInterface(iid); + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gTest5TimerCallback.QueryInterface(aIID); } throw Cr.NS_ERROR_NO_AGGREGATION; } @@ -397,9 +395,9 @@ const gTest6TimerCallback = { }; const gTest6Factory = { - createInstance: function (outer, iid) { - if (outer == null) { - return gTest6TimerCallback.QueryInterface(iid); + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gTest6TimerCallback.QueryInterface(aIID); } throw Cr.NS_ERROR_NO_AGGREGATION; } @@ -415,9 +413,9 @@ const gTest7TimerCallback = { }; const gTest7Factory = { - createInstance: function (outer, iid) { - if (outer == null) { - return gTest7TimerCallback.QueryInterface(iid); + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gTest7TimerCallback.QueryInterface(aIID); } throw Cr.NS_ERROR_NO_AGGREGATION; } @@ -427,7 +425,7 @@ const gTest8TimerCallback = { notify: function T8CB_notify(aTimer) { TESTS[7].notified = true; TESTS[7].notifyTime = Date.now(); - do_timeout(0, function() { + do_execute_soon(function() { check_test8(gTest8TimerCallback); }); }, @@ -435,9 +433,9 @@ const gTest8TimerCallback = { }; const gTest8Factory = { - createInstance: function (outer, iid) { - if (outer == null) { - return gTest8TimerCallback.QueryInterface(iid); + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gTest8TimerCallback.QueryInterface(aIID); } throw Cr.NS_ERROR_NO_AGGREGATION; } @@ -447,7 +445,7 @@ const gTest9TimerCallback = { notify: function T9CB_notify(aTimer) { TESTS[8].notified = true; TESTS[8].notifyTime = Date.now(); - do_timeout(0, function() { + do_execute_soon(function() { check_test8(gTest9TimerCallback); }); }, @@ -455,9 +453,9 @@ const gTest9TimerCallback = { }; const gTest9Factory = { - createInstance: function (outer, iid) { - if (outer == null) { - return gTest9TimerCallback.QueryInterface(iid); + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return gTest9TimerCallback.QueryInterface(aIID); } throw Cr.NS_ERROR_NO_AGGREGATION; } diff --git a/toolkit/mozapps/update/updater/archivereader.cpp b/toolkit/mozapps/update/updater/archivereader.cpp index f0e6ea33fa..5192f71f0a 100644 --- a/toolkit/mozapps/update/updater/archivereader.cpp +++ b/toolkit/mozapps/update/updater/archivereader.cpp @@ -308,7 +308,7 @@ ArchiveReader::ExtractItemToStream(const MarItem *item, FILE *fp) outlen = outbuf_size - strm.avail_out; if (outlen) { if (fwrite(outbuf, outlen, 1, fp) != 1) { - ret = WRITE_ERROR; + ret = WRITE_ERROR_EXTRACT; break; } } diff --git a/toolkit/mozapps/update/updater/bspatch.cpp b/toolkit/mozapps/update/updater/bspatch.cpp index 64a730280b..e632fe3d3d 100644 --- a/toolkit/mozapps/update/updater/bspatch.cpp +++ b/toolkit/mozapps/update/updater/bspatch.cpp @@ -149,7 +149,7 @@ MBS_ApplyPatch(const MBSPatchHeader *header, FILE* patchFile, diffsrc[i] += fbuffer[i]; } if ((uint32_t) fwrite(diffsrc, 1, ctrlsrc->x, file) != ctrlsrc->x) { - rv = WRITE_ERROR; + rv = WRITE_ERROR_PATCH_FILE; goto end; } fbuffer += ctrlsrc->x; @@ -162,7 +162,7 @@ MBS_ApplyPatch(const MBSPatchHeader *header, FILE* patchFile, goto end; } if ((uint32_t) fwrite(extrasrc, 1, ctrlsrc->y, file) != ctrlsrc->y) { - rv = WRITE_ERROR; + rv = WRITE_ERROR_PATCH_FILE; goto end; } extrasrc += ctrlsrc->y; diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index 204c6c72fe..526a65f632 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -650,9 +650,9 @@ static int ensure_copy(const NS_tchar *path, const NS_tchar *dest) if (!result) { LOG(("ensure_copy: failed to copy the file " LOG_S " over to " LOG_S ", lasterr: %x", path, dest, GetLastError())); - return WRITE_ERROR; + return WRITE_ERROR_FILE_COPY; } - return 0; + return OK; #else struct NS_tstat_t ss; int rv = NS_tlstat(path, &ss); @@ -716,7 +716,7 @@ static int ensure_copy(const NS_tchar *path, const NS_tchar *dest) LOG(("ensure_copy: failed to write the file: " LOG_S ", err: %d", dest, errno)); free(buffer); - return WRITE_ERROR; + return WRITE_ERROR_FILE_COPY; } written += chunkWritten; @@ -832,7 +832,7 @@ static int rename_file(const NS_tchar *spath, const NS_tchar *dpath, if (allowDirs && !S_ISDIR(spathInfo.st_mode)) { LOG(("rename_file: path present, but not a file: " LOG_S ", err: %d", spath, errno)); - return UNEXPECTED_FILE_OPERATION_ERROR; + return RENAME_ERROR_EXPECTED_FILE; } else { LOG(("rename_file: proceeding to rename the directory")); } @@ -842,7 +842,7 @@ static int rename_file(const NS_tchar *spath, const NS_tchar *dpath, if (ensure_remove(dpath)) { LOG(("rename_file: destination file exists and could not be " \ "removed: " LOG_S, dpath)); - return WRITE_ERROR; + return WRITE_ERROR_DELETE_FILE; } } @@ -971,7 +971,7 @@ static int backup_discard(const NS_tchar *path) if (rename_file(backup, path)) { LOG(("backup_discard: failed to rename file:" LOG_S ", dst:" LOG_S, backup, path)); - return WRITE_ERROR; + return WRITE_ERROR_DELETE_BACKUP; } // The MoveFileEx call to remove the file on OS reboot will fail if the // process doesn't have write access to the HKEY_LOCAL_MACHINE registry key @@ -988,7 +988,7 @@ static int backup_discard(const NS_tchar *path) } #else if (rv) - return WRITE_ERROR; + return WRITE_ERROR_DELETE_BACKUP; #endif return OK; @@ -1086,7 +1086,7 @@ RemoveFile::Prepare() if (!S_ISREG(fileInfo.st_mode)) { LOG(("path present, but not a file: " LOG_S, mFile)); - return UNEXPECTED_FILE_OPERATION_ERROR; + return DELETE_ERROR_EXPECTED_FILE; } NS_tchar *slash = (NS_tchar *) NS_tstrrchr(mFile, NS_T('/')); @@ -1100,7 +1100,7 @@ RemoveFile::Prepare() if (rv) { LOG(("access failed: %d", errno)); - return WRITE_ERROR; + return WRITE_ERROR_FILE_ACCESS_DENIED; } return OK; @@ -1195,13 +1195,13 @@ RemoveDir::Prepare() if (!S_ISDIR(dirInfo.st_mode)) { LOG(("path present, but not a directory: " LOG_S, mDir)); - return UNEXPECTED_FILE_OPERATION_ERROR; + return DELETE_ERROR_EXPECTED_DIR; } rv = NS_taccess(mDir, W_OK); if (rv) { LOG(("access failed: %d, %d", rv, errno)); - return WRITE_ERROR; + return WRITE_ERROR_DIR_ACCESS_DENIED; } return OK; @@ -1387,7 +1387,7 @@ PatchFile::LoadSourceFile(FILE* ofile) if (uint32_t(os.st_size) != header.slen) { LOG(("LoadSourceFile: destination file size %d does not match expected size %d", uint32_t(os.st_size), header.slen)); - return UNEXPECTED_FILE_OPERATION_ERROR; + return LOADSOURCE_ERROR_WRONG_SIZE; } buf = (unsigned char *) malloc(header.slen); @@ -1538,7 +1538,7 @@ PatchFile::Execute() // Creating the file, setting the size, and then closing the file handle // lessens fragmentation more than any other method tested. Other methods that // have been tested are: - // 1. _chsize / _chsize_s reduced fragmentation but though not completely. + // 1. _chsize / _chsize_s reduced fragmentation though not completely. // 2. _get_osfhandle and then setting the size reduced fragmentation though // not completely. There are also reports of _get_osfhandle failing on // mingw. @@ -1559,7 +1559,8 @@ PatchFile::Execute() CloseHandle(hfile); } - AutoFile ofile(ensure_open(mFile, shouldTruncate ? NS_T("wb+") : NS_T("rb+"), ss.st_mode)); + AutoFile ofile(ensure_open(mFile, shouldTruncate ? NS_T("wb+") : NS_T("rb+"), + ss.st_mode)); #elif defined(XP_MACOSX) AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode)); // Modified code from FileUtils.cpp @@ -1581,7 +1582,7 @@ PatchFile::Execute() if (ofile == nullptr) { LOG(("unable to create new file: " LOG_S ", err: %d", mFile, errno)); - return WRITE_ERROR; + return WRITE_ERROR_OPEN_PATCH_FILE; } #ifdef XP_WIN @@ -2086,7 +2087,8 @@ ProcessReplaceRequest() // name, so that if the user has used a different case when launching the // application, the installation directory's name does not change. NS_tchar destDir[MAXPATHLEN]; - if (!GetLongPathNameW(gInstallDirPath, destDir, sizeof(destDir)/sizeof(destDir[0]))) { + if (!GetLongPathNameW(gInstallDirPath, destDir, + sizeof(destDir)/sizeof(destDir[0]))) { return NO_INSTALLDIR_ERROR; } #else @@ -2134,6 +2136,8 @@ ProcessReplaceRequest() } #endif if (rv) { + // The status file will have 'pending' written to it so there is no value in + // returning an error specific for this failure. LOG(("Moving destDir to tmpDir failed, err: %d", rv)); return rv; } @@ -2157,6 +2161,8 @@ ProcessReplaceRequest() if (rv2) { LOG(("Moving tmpDir back to destDir failed, err: %d", rv2)); } + // The status file will be have 'pending' written to it so there is no value + // in returning an error specific for this failure. return rv; } @@ -2231,7 +2237,8 @@ ReadMARChannelIDs(const NS_tchar *path, MARChannelStringTable *results) static int GetUpdateFileName(NS_tchar *fileName, int maxChars) { -#if defined(MOZ_WIDGET_GONK) // If an update.link file exists, then it will contain the name +#if defined(MOZ_WIDGET_GONK) + // If an update.link file exists, then it will contain the name // of the update file (terminated by a newline). NS_tchar linkFileName[MAXPATHLEN]; @@ -2373,7 +2380,8 @@ UpdateThreadFunc(void *param) // staged directory as it won't be useful any more. ensure_remove_recursive(gWorkingDirPath); WriteStatusFile("pending"); - putenv(const_cast("MOZ_PROCESS_UPDATES=")); // We need to use --process-updates again in the tests + // We need to use --process-updates again in the tests + putenv(const_cast("MOZ_PROCESS_UPDATES=")); reportRealResults = false; // pretend success } @@ -2593,7 +2601,8 @@ int NS_main(int argc, NS_tchar **argv) fprintf(fs, "%d", oomScoreAdj); fclose(fs); } else { - LOG(("Unable to open /proc/self/oom_score_adj for writing, errno = %d", errno)); + LOG(("Unable to open /proc/self/oom_score_adj for writing, errno = %d", + errno)); } } } @@ -2881,7 +2890,7 @@ int NS_main(int argc, NS_tchar **argv) sizeof(applyDirLongPath)/sizeof(applyDirLongPath[0]))) { LOG(("NS_main: unable to find apply to dir: " LOG_S, gWorkingDirPath)); LogFinish(); - WriteStatusFile(WRITE_ERROR); + WriteStatusFile(WRITE_ERROR_APPLY_DIR_PATH); EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); if (argc > callbackIndex) { LaunchCallbackApp(argv[5], argc - callbackIndex, @@ -2926,14 +2935,15 @@ int NS_main(int argc, NS_tchar **argv) size_t callbackPrefixLength = PathCommonPrefixW(argv[callbackIndex], installDir, nullptr); - NS_tstrncpy(p, argv[callbackIndex] + std::max(callbackPrefixLength, commonPrefixLength), bufferLeft); + NS_tstrncpy(p, argv[callbackIndex] + std::max(callbackPrefixLength, + commonPrefixLength), bufferLeft); targetPath = buffer; } if (!GetLongPathNameW(targetPath, callbackLongPath, sizeof(callbackLongPath)/sizeof(callbackLongPath[0]))) { LOG(("NS_main: unable to find callback file: " LOG_S, targetPath)); LogFinish(); - WriteStatusFile(WRITE_ERROR); + WriteStatusFile(WRITE_ERROR_CALLBACK_PATH); EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); if (argc > callbackIndex) { LaunchCallbackApp(argv[5], @@ -3199,7 +3209,7 @@ ActionList::Prepare() // actually done. See bug 327140. if (mCount == 0) { LOG(("empty action list")); - return UNEXPECTED_MAR_ERROR; + return MAR_ERROR_EMPTY_ACTION_LIST; } Action *a = mFirst; @@ -3309,7 +3319,8 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list) Action *action = new RemoveFile(); rv = action->Parse(quotedpath); if (rv) { - LOG(("add_dir_entries Parse error on recurse: " LOG_S ", err: %d", quotedpath, rv)); + LOG(("add_dir_entries Parse error on recurse: " LOG_S ", err: %d", + quotedpath, rv)); return rv; } @@ -3327,7 +3338,8 @@ int add_dir_entries(const NS_tchar *dirpath, ActionList *list) Action *action = new RemoveDir(); rv = action->Parse(quotedpath); if (rv) - LOG(("add_dir_entries Parse error on close: " LOG_S ", err: %d", quotedpath, rv)); + LOG(("add_dir_entries Parse error on close: " LOG_S ", err: %d", + quotedpath, rv)); else list->Append(action); } diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp index 520c143989..403ee74c68 100644 --- a/toolkit/xre/nsUpdateDriver.cpp +++ b/toolkit/xre/nsUpdateDriver.cpp @@ -1208,11 +1208,7 @@ nsUpdateProcessor::UpdateDone() nsCOMPtr um = do_GetService("@mozilla.org/updates/update-manager;1"); if (um) { - nsCOMPtr update; - um->GetActiveUpdate(getter_AddRefs(update)); - if (update) { - um->RefreshUpdateStatus(update); - } + um->RefreshUpdateStatus(); } ShutdownWatcherThread();