diff --git a/.gitignore b/.gitignore index eddeba9d44f..2f27b29b45e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,11 +13,11 @@ ID .*.sw[a-z] # User files that may appear at the root -.mozconfig -mozconfig -configure -config.cache -config.log +/.mozconfig* +/mozconfig +/configure +/config.cache +/config.log # Empty marker file that's generated when we check out NSS security/manager/.nss.checkout diff --git a/build/automation.py.in b/build/automation.py.in index ad35c6892c6..fdd8e8c896e 100644 --- a/build/automation.py.in +++ b/build/automation.py.in @@ -52,7 +52,6 @@ import sys import threading import tempfile import sqlite3 -import zipfile SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))) sys.path.insert(0, SCRIPT_DIR) @@ -98,69 +97,6 @@ _log.setLevel(logging.INFO) _log.addHandler(handler) -class ZipFileReader(object): - """ - Class to read zip files in Python 2.5 and later. Limited to only what we - actually use. - """ - - def __init__(self, filename): - self._zipfile = zipfile.ZipFile(filename, "r") - - def __del__(self): - self._zipfile.close() - - def _getnormalizedpath(self, path): - """ - Gets a normalized path from 'path' (or the current working directory if - 'path' is None). Also asserts that the path exists. - """ - if path is None: - path = os.curdir - path = os.path.normpath(os.path.expanduser(path)) - assert os.path.isdir(path) - return path - - def _extractname(self, name, path): - """ - Extracts a file with the given name from the zip file to the given path. - Also creates any directories needed along the way. - """ - filename = os.path.normpath(os.path.join(path, name)) - if name.endswith("/"): - os.makedirs(filename) - else: - path = os.path.split(filename)[0] - if not os.path.isdir(path): - os.makedirs(path) - with open(filename, "wb") as dest: - dest.write(self._zipfile.read(name)) - - def namelist(self): - return self._zipfile.namelist() - - def read(self, name): - return self._zipfile.read(name) - - def extract(self, name, path = None): - if hasattr(self._zipfile, "extract"): - return self._zipfile.extract(name, path) - - # This will throw if name is not part of the zip file. - self._zipfile.getinfo(name) - - self._extractname(name, self._getnormalizedpath(path)) - - def extractall(self, path = None): - if hasattr(self._zipfile, "extractall"): - return self._zipfile.extractall(path) - - path = self._getnormalizedpath(path) - - for name in self._zipfile.namelist(): - self._extractname(name, path) - - ################# # PROFILE SETUP # ################# @@ -1053,7 +989,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t os.makedirs(extensionsRootDir) if os.path.isfile(extensionSource): - reader = ZipFileReader(extensionSource) + reader = automationutils.ZipFileReader(extensionSource) for filename in reader.namelist(): # Sanity check the zip file. diff --git a/build/automationutils.py b/build/automationutils.py index 3f52516af8d..7506e3e8fe0 100644 --- a/build/automationutils.py +++ b/build/automationutils.py @@ -36,11 +36,13 @@ # # ***** END LICENSE BLOCK ***** */ -import glob, logging, os, platform, shutil, subprocess, sys +from __future__ import with_statement +import glob, logging, os, platform, shutil, subprocess, sys, tempfile, urllib2, zipfile import re from urlparse import urlparse __all__ = [ + "ZipFileReader", "addCommonOptions", "checkForCrashes", "dumpLeakLog", @@ -70,6 +72,68 @@ DEBUGGER_INFO = { } } +class ZipFileReader(object): + """ + Class to read zip files in Python 2.5 and later. Limited to only what we + actually use. + """ + + def __init__(self, filename): + self._zipfile = zipfile.ZipFile(filename, "r") + + def __del__(self): + self._zipfile.close() + + def _getnormalizedpath(self, path): + """ + Gets a normalized path from 'path' (or the current working directory if + 'path' is None). Also asserts that the path exists. + """ + if path is None: + path = os.curdir + path = os.path.normpath(os.path.expanduser(path)) + assert os.path.isdir(path) + return path + + def _extractname(self, name, path): + """ + Extracts a file with the given name from the zip file to the given path. + Also creates any directories needed along the way. + """ + filename = os.path.normpath(os.path.join(path, name)) + if name.endswith("/"): + os.makedirs(filename) + else: + path = os.path.split(filename)[0] + if not os.path.isdir(path): + os.makedirs(path) + with open(filename, "wb") as dest: + dest.write(self._zipfile.read(name)) + + def namelist(self): + return self._zipfile.namelist() + + def read(self, name): + return self._zipfile.read(name) + + def extract(self, name, path = None): + if hasattr(self._zipfile, "extract"): + return self._zipfile.extract(name, path) + + # This will throw if name is not part of the zip file. + self._zipfile.getinfo(name) + + self._extractname(name, self._getnormalizedpath(path)) + + def extractall(self, path = None): + if hasattr(self._zipfile, "extractall"): + return self._zipfile.extractall(path) + + path = self._getnormalizedpath(path) + + for name in self._zipfile.namelist(): + self._extractname(name, path) + log = logging.getLogger() def isURL(thing): @@ -102,7 +166,6 @@ def addCommonOptions(parser, defaults={}): def checkForCrashes(dumpDir, symbolsPath, testName=None): stackwalkPath = os.environ.get('MINIDUMP_STACKWALK', None) - stackwalkCGI = os.environ.get('MINIDUMP_STACKWALK_CGI', None) # try to get the caller's filename if no test name is given if testName is None: try: @@ -110,70 +173,70 @@ def checkForCrashes(dumpDir, symbolsPath, testName=None): except: testName = "unknown" - foundCrash = False + # Check preconditions dumps = glob.glob(os.path.join(dumpDir, '*.dmp')) - for d in dumps: - log.info("PROCESS-CRASH | %s | application crashed (minidump found)", testName) - print "Crash dump filename: " + d - if symbolsPath and stackwalkPath and os.path.exists(stackwalkPath): - p = subprocess.Popen([stackwalkPath, d, symbolsPath], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - (out, err) = p.communicate() - if len(out) > 3: - # minidump_stackwalk is chatty, so ignore stderr when it succeeds. - print out - else: - print "stderr from minidump_stackwalk:" - print err - if p.returncode != 0: - print "minidump_stackwalk exited with return code %d" % p.returncode - elif stackwalkCGI and symbolsPath and isURL(symbolsPath): - f = None - try: - f = open(d, "rb") - sys.path.append(os.path.join(os.path.dirname(__file__), "poster.zip")) - from poster.encode import multipart_encode - from poster.streaminghttp import register_openers - import urllib2 - register_openers() - datagen, headers = multipart_encode({"minidump": f, - "symbols": symbolsPath}) - request = urllib2.Request(stackwalkCGI, datagen, headers) - result = urllib2.urlopen(request).read() - if len(result) > 3: - print result + if len(dumps) == 0: + return False + + foundCrash = False + removeSymbolsPath = False + + # If our symbols are at a remote URL, download them now + if isURL(symbolsPath): + print "Downloading symbols from: " + symbolsPath + removeSymbolsPath = True + # Get the symbols and write them to a temporary zipfile + data = urllib2.urlopen(symbolsPath) + symbolsFile = tempfile.TemporaryFile() + symbolsFile.write(data.read()) + # extract symbols to a temporary directory (which we'll delete after + # processing all crashes) + symbolsPath = tempfile.mkdtemp() + zfile = ZipFileReader(symbolsFile) + zfile.extractall(symbolsPath) + + try: + for d in dumps: + log.info("PROCESS-CRASH | %s | application crashed (minidump found)", testName) + print "Crash dump filename: " + d + if symbolsPath and stackwalkPath and os.path.exists(stackwalkPath): + # run minidump stackwalk + p = subprocess.Popen([stackwalkPath, d, symbolsPath], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + (out, err) = p.communicate() + if len(out) > 3: + # minidump_stackwalk is chatty, so ignore stderr when it succeeds. + print out else: - print "stackwalkCGI returned nothing." - finally: - if f: - f.close() - else: - if not symbolsPath: - print "No symbols path given, can't process dump." - if not stackwalkPath and not stackwalkCGI: - print "Neither MINIDUMP_STACKWALK nor MINIDUMP_STACKWALK_CGI is set, can't process dump." + print "stderr from minidump_stackwalk:" + print err + if p.returncode != 0: + print "minidump_stackwalk exited with return code %d" % p.returncode else: - if stackwalkPath and not os.path.exists(stackwalkPath): + if not symbolsPath: + print "No symbols path given, can't process dump." + if not stackwalkPath: + print "MINIDUMP_STACKWALK not set, can't process dump." + elif stackwalkPath and not os.path.exists(stackwalkPath): print "MINIDUMP_STACKWALK binary not found: %s" % stackwalkPath - elif stackwalkCGI and not isURL(stackwalkCGI): - print "MINIDUMP_STACKWALK_CGI is not a URL: %s" % stackwalkCGI - elif symbolsPath and not isURL(symbolsPath): - print "symbolsPath is not a URL: %s" % symbolsPath - dumpSavePath = os.environ.get('MINIDUMP_SAVE_PATH', None) - if dumpSavePath: - shutil.move(d, dumpSavePath) - print "Saved dump as %s" % os.path.join(dumpSavePath, - os.path.basename(d)) - else: - os.remove(d) - extra = os.path.splitext(d)[0] + ".extra" - if os.path.exists(extra): - os.remove(extra) - foundCrash = True + dumpSavePath = os.environ.get('MINIDUMP_SAVE_PATH', None) + if dumpSavePath: + shutil.move(d, dumpSavePath) + print "Saved dump as %s" % os.path.join(dumpSavePath, + os.path.basename(d)) + else: + os.remove(d) + extra = os.path.splitext(d)[0] + ".extra" + if os.path.exists(extra): + os.remove(extra) + foundCrash = True + finally: + if removeSymbolsPath: + shutil.rmtree(symbolsPath) return foundCrash - + def getFullPath(directory, path): "Get an absolute path relative to 'directory'." return os.path.normpath(os.path.join(directory, os.path.expanduser(path))) diff --git a/build/poster.zip b/build/poster.zip deleted file mode 100644 index 122b4acd469..00000000000 Binary files a/build/poster.zip and /dev/null differ diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index a20ee77684c..8915d789ec7 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1954,6 +1954,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument) if (tmp->mAnimationController) { tmp->mAnimationController->Unlink(); } + + tmp->mPendingTitleChangeEvent.Revoke(); tmp->mInUnlinkOrDeletion = false; NS_IMPL_CYCLE_COLLECTION_UNLINK_END diff --git a/content/svg/content/src/nsSVGPathElement.cpp b/content/svg/content/src/nsSVGPathElement.cpp index 8b1e258d173..d0063d50355 100644 --- a/content/svg/content/src/nsSVGPathElement.cpp +++ b/content/svg/content/src/nsSVGPathElement.cpp @@ -427,7 +427,7 @@ nsSVGPathElement::ConstructPath(gfxContext *aCtx) } gfxFloat -nsSVGPathElement::GetScale() +nsSVGPathElement::GetPathLengthScale() { if (mPathLength.IsExplicitlySet()) { diff --git a/content/svg/content/src/nsSVGPathElement.h b/content/svg/content/src/nsSVGPathElement.h index 742f6206000..e5c011d8a7a 100644 --- a/content/svg/content/src/nsSVGPathElement.h +++ b/content/svg/content/src/nsSVGPathElement.h @@ -98,7 +98,12 @@ public: return nsGkAtoms::d; } - gfxFloat GetScale(); + /** + * Gets the ratio of the actual path length to the content author's estimated + * length (as provided by the element's 'pathLength' attribute). This + * is used to scale stroke dashing, and to scale offsets along a textPath. + */ + gfxFloat GetPathLengthScale(); protected: diff --git a/dom/src/storage/nsDOMStorage.cpp b/dom/src/storage/nsDOMStorage.cpp index 9de9633ec36..87feb60f253 100644 --- a/dom/src/storage/nsDOMStorage.cpp +++ b/dom/src/storage/nsDOMStorage.cpp @@ -287,16 +287,27 @@ nsDOMStorageManager::Initialize() if (!os) return NS_OK; - os->AddObserver(gStorageManager, "cookie-changed", false); - os->AddObserver(gStorageManager, "offline-app-removed", false); - os->AddObserver(gStorageManager, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false); - os->AddObserver(gStorageManager, "profile-after-change", false); - os->AddObserver(gStorageManager, "perm-changed", false); - os->AddObserver(gStorageManager, "browser:purge-domain-data", false); + nsresult rv; + rv = os->AddObserver(gStorageManager, "cookie-changed", false); + NS_ENSURE_SUCCESS(rv, rv); + rv = os->AddObserver(gStorageManager, "offline-app-removed", false); + NS_ENSURE_SUCCESS(rv, rv); + rv = os->AddObserver(gStorageManager, NS_PRIVATE_BROWSING_SWITCH_TOPIC, + false); + NS_ENSURE_SUCCESS(rv, rv); + rv = os->AddObserver(gStorageManager, "profile-after-change", false); + NS_ENSURE_SUCCESS(rv, rv); + rv = os->AddObserver(gStorageManager, "perm-changed", false); + NS_ENSURE_SUCCESS(rv, rv); + rv = os->AddObserver(gStorageManager, "browser:purge-domain-data", false); + NS_ENSURE_SUCCESS(rv, rv); // Used for temporary table flushing - os->AddObserver(gStorageManager, "profile-before-change", false); - os->AddObserver(gStorageManager, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - os->AddObserver(gStorageManager, NS_DOMSTORAGE_FLUSH_TIMER_TOPIC, false); + rv = os->AddObserver(gStorageManager, "profile-before-change", false); + NS_ENSURE_SUCCESS(rv, rv); + rv = os->AddObserver(gStorageManager, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); + NS_ENSURE_SUCCESS(rv, rv); + rv = os->AddObserver(gStorageManager, NS_DOMSTORAGE_FLUSH_TIMER_TOPIC, false); + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } diff --git a/embedding/android/GeckoApp.java b/embedding/android/GeckoApp.java index c1897058d45..dc8d5d52ecb 100644 --- a/embedding/android/GeckoApp.java +++ b/embedding/android/GeckoApp.java @@ -1095,7 +1095,9 @@ abstract public class GeckoApp } catch (Exception e) { Log.e(LOG_NAME, "top level exception", e); StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); GeckoAppShell.reportJavaCrash(sw.toString()); } // resetting this is kinda pointless, but oh well diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 8c730cf238c..3b656ce3aa2 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -346,7 +346,7 @@ RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect) // If animation mode is "loop once", it's time to stop animating if (mAnimationMode == kLoopOnceAnimMode || mLoopCount == 0) { - mAnimationFinished = PR_TRUE; + mAnimationFinished = true; EvaluateAnimation(); } @@ -383,7 +383,7 @@ RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect) } if (!(timeout > 0)) { - mAnimationFinished = PR_TRUE; + mAnimationFinished = true; EvaluateAnimation(); } @@ -404,13 +404,13 @@ RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect) nextFrame, nextFrameIndex))) { // something went wrong, move on to next NS_WARNING("RasterImage::AdvanceFrame(): Compositing of frame failed"); - nextFrame->SetCompositingFailed(PR_TRUE); + nextFrame->SetCompositingFailed(true); mAnim->currentAnimationFrameIndex = nextFrameIndex; mAnim->currentAnimationFrameTime = aTime; return false; } - nextFrame->SetCompositingFailed(PR_FALSE); + nextFrame->SetCompositingFailed(false); } // Set currentAnimationFrameIndex at the last possible moment diff --git a/js/jsd/jsd_hook.c b/js/jsd/jsd_hook.c index 45c6be8e597..1cef8f8a241 100644 --- a/js/jsd/jsd_hook.c +++ b/js/jsd/jsd_hook.c @@ -124,10 +124,10 @@ jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, void* hookData; if( ! jsdc || ! jsdc->inited ) - return JSD_HOOK_RETURN_CONTINUE_THROW; + return JSTRAP_CONTINUE; if( JSD_IS_DANGEROUS_THREAD(jsdc) ) - return JSD_HOOK_RETURN_CONTINUE_THROW; + return JSTRAP_CONTINUE; /* local in case jsdc->throwHook gets cleared on another thread */ JSD_LOCK(); @@ -135,13 +135,13 @@ jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, hookData = jsdc->throwHookData; JSD_UNLOCK(); if (!hook) - return JSD_HOOK_RETURN_CONTINUE_THROW; + return JSTRAP_CONTINUE; JSD_LOCK_SCRIPTS(jsdc); jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, NULL); JSD_UNLOCK_SCRIPTS(jsdc); if( ! jsdscript ) - return JSD_HOOK_RETURN_CONTINUE_THROW; + return JSTRAP_CONTINUE; JS_GetPendingException(cx, rval); diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 1a18cf5069c..3b6634254e9 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -49,6 +49,8 @@ #include "nsImageFrame.h" #include "nsRenderingContext.h" +#include "mozilla/Preferences.h" + #ifdef DEBUG #include #endif @@ -470,6 +472,27 @@ FrameLayerBuilder::DisplayItemDataEntry::HasNonEmptyContainerLayer() return false; } +void +FrameLayerBuilder::FlashPaint(gfxContext *aContext) +{ + static bool sPaintFlashingEnabled; + static bool sPaintFlashingPrefCached = false; + + if (!sPaintFlashingPrefCached) { + sPaintFlashingPrefCached = true; + mozilla::Preferences::AddBoolVarCache(&sPaintFlashingEnabled, + "nglayout.debug.paint_flashing"); + } + + if (sPaintFlashingEnabled) { + float r = float(rand()) / RAND_MAX; + float g = float(rand()) / RAND_MAX; + float b = float(rand()) / RAND_MAX; + aContext->SetColor(gfxRGBA(r, g, b, 0.2)); + aContext->Paint(); + } +} + /* static */ nsTArray* FrameLayerBuilder::GetDisplayItemDataArrayForFrame(nsIFrame* aFrame) { @@ -2127,6 +2150,8 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, if (setClipRect) { aContext->Restore(); } + + FlashPaint(aContext); } bool diff --git a/layout/base/FrameLayerBuilder.h b/layout/base/FrameLayerBuilder.h index da2082a6f60..99a2e6dd47f 100644 --- a/layout/base/FrameLayerBuilder.h +++ b/layout/base/FrameLayerBuilder.h @@ -441,6 +441,9 @@ protected: // LayerManagerData needs to see DisplayItemDataEntry. friend class LayerManagerData; + // Flash the area within the context clip if paint flashing is enabled. + static void FlashPaint(gfxContext *aContext); + /* * Get the DisplayItemData array associated with this frame, or null if one * doesn't exist. diff --git a/layout/svg/base/src/nsSVGGeometryFrame.cpp b/layout/svg/base/src/nsSVGGeometryFrame.cpp index 53d130335b6..c40254f66c1 100644 --- a/layout/svg/base/src/nsSVGGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGGeometryFrame.cpp @@ -120,7 +120,8 @@ nsSVGGeometryFrame::GetStrokeDashArray(gfxFloat **aDashes, PRUint32 *aCount) gfxFloat pathScale = 1.0; if (mContent->Tag() == nsGkAtoms::path) { - pathScale = static_cast(mContent)->GetScale(); + pathScale = + static_cast(mContent)->GetPathLengthScale(); if (pathScale <= 0) { return NS_OK; } diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index f661a3c16a6..bc75a44b90f 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -751,7 +751,7 @@ nsSVGGlyphFrame::GetCharacterPositions(nsTArray* aCharacterPo if (!aCharacterPositions->SetLength(strLength)) return false; - gfxFloat pathScale = textPath->GetPathScale(); + gfxFloat pathScale = textPath->GetOffsetScale(); CharacterPosition *cp = aCharacterPositions->Elements(); @@ -877,7 +877,7 @@ nsSVGGlyphFrame::GetSubStringAdvance(PRUint32 aCharnum, gfxFloat pathScale = 1.0; nsSVGTextPathFrame *textPath = FindTextPathParent(); if (textPath) - pathScale = textPath->GetPathScale(); + pathScale = textPath->GetOffsetScale(); if (dxcount > aFragmentChars) dxcount = aFragmentChars; for (PRUint32 i = aCharnum; i < dxcount; i++) { @@ -1101,7 +1101,7 @@ nsSVGGlyphFrame::SetGlyphPosition(gfxPoint *aPosition, bool aForceGlobalTransfor gfxFloat pathScale = 1.0; if (textPath) - pathScale = textPath->GetPathScale(); + pathScale = textPath->GetOffsetScale(); nsTArray dxList, dyList; GetEffectiveDxDy(strLength, dxList, dyList); diff --git a/layout/svg/base/src/nsSVGTextPathFrame.cpp b/layout/svg/base/src/nsSVGTextPathFrame.cpp index e5649d8b7eb..eaf00e10841 100644 --- a/layout/svg/base/src/nsSVGTextPathFrame.cpp +++ b/layout/svg/base/src/nsSVGTextPathFrame.cpp @@ -166,17 +166,18 @@ nsSVGTextPathFrame::GetStartOffset() nsRefPtr data = GetFlattenedPath(); return data ? (val * data->GetLength() / 100.0) : 0.0; } - return val * GetPathScale(); + return val * GetOffsetScale(); } gfxFloat -nsSVGTextPathFrame::GetPathScale() +nsSVGTextPathFrame::GetOffsetScale() { nsIFrame *pathFrame = GetPathFrame(); if (!pathFrame) return 1.0; - return static_cast(pathFrame->GetContent())->GetScale(); + return static_cast(pathFrame->GetContent())-> + GetPathLengthScale(); } //---------------------------------------------------------------------- diff --git a/layout/svg/base/src/nsSVGTextPathFrame.h b/layout/svg/base/src/nsSVGTextPathFrame.h index 992817aebe1..94ce2ae51e7 100644 --- a/layout/svg/base/src/nsSVGTextPathFrame.h +++ b/layout/svg/base/src/nsSVGTextPathFrame.h @@ -84,8 +84,20 @@ public: already_AddRefed GetFlattenedPath(); nsIFrame *GetPathFrame(); + /** + * Gets the scale by which offsets along this textPath must be scaled. This + * scaling is due to the user provided 'pathLength' attribute on the + * element, which is a user provided estimate of the path length. + */ + gfxFloat GetOffsetScale(); + + /** + * Gets the offset from the start of the path at which the first character + * should be positioned. The value returned already takes GetOffsetScale + * into account. + */ gfxFloat GetStartOffset(); - gfxFloat GetPathScale(); + protected: virtual void GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY); diff --git a/layout/tools/reftest/Makefile.in b/layout/tools/reftest/Makefile.in index 7d589259262..94b0ddba4a2 100644 --- a/layout/tools/reftest/Makefile.in +++ b/layout/tools/reftest/Makefile.in @@ -84,7 +84,6 @@ _HARNESS_FILES = \ $(topsrcdir)/build/mobile/devicemanagerADB.py \ $(topsrcdir)/build/mobile/devicemanagerSUT.py \ $(topsrcdir)/build/automationutils.py \ - $(topsrcdir)/build/poster.zip \ $(topsrcdir)/build/mobile/remoteautomation.py \ $(topsrcdir)/testing/mochitest/server.js \ $(topsrcdir)/build/pgo/server-locations.txt \ diff --git a/layout/xul/base/src/tree/src/nsITreeImageListener.h b/layout/xul/base/src/tree/src/nsITreeImageListener.h deleted file mode 100644 index 7fe9538eeb1..00000000000 --- a/layout/xul/base/src/tree/src/nsITreeImageListener.h +++ /dev/null @@ -1,64 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dave Hyatt (Original Author) - * Jan Varga - * Scott Johnson , Mozilla Corporation - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef nsITreeImageListener_h__ -#define nsITreeImageListener_h__ - -// The interface for our image listener. -// {90586540-2D50-403e-8DCE-981CAA778444} -#define NS_ITREEIMAGELISTENER_IID \ -{ 0x90586540, 0x2d50, 0x403e, { 0x8d, 0xce, 0x98, 0x1c, 0xaa, 0x77, 0x84, 0x44 } } - -class nsITreeImageListener : public nsISupports -{ -public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITREEIMAGELISTENER_IID) - - NS_IMETHOD AddCell(PRInt32 aIndex, nsITreeColumn* aCol) = 0; - - /** - * Clear the internal frame pointer to prevent dereferencing an object - * that no longer exists. - */ - NS_IMETHOD ClearFrame() = 0; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsITreeImageListener, NS_ITREEIMAGELISTENER_IID) - -#endif diff --git a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp index 73e635e6d8b..8e3c73aac7d 100644 --- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp +++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp @@ -2157,9 +2157,11 @@ nsTreeBodyFrame::GetImage(PRInt32 aRowIndex, nsTreeColumn* aCol, bool aUseContex // We either aren't done loading, or we're animating. Add our row as a listener for invalidations. nsCOMPtr obs; imgReq->GetDecoderObserver(getter_AddRefs(obs)); - nsCOMPtr listener(do_QueryInterface(obs)); - if (listener) - listener->AddCell(aRowIndex, aCol); + + if (obs) { + static_cast (obs.get())->AddCell(aRowIndex, aCol); + } + return NS_OK; } } diff --git a/layout/xul/base/src/tree/src/nsTreeBodyFrame.h b/layout/xul/base/src/tree/src/nsTreeBodyFrame.h index 4a0bfea577d..69127614a90 100644 --- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.h +++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.h @@ -61,7 +61,6 @@ #include "nsScrollbarFrame.h" #include "nsThreadUtils.h" #include "mozilla/LookAndFeel.h" -#include "nsITreeImageListener.h" class nsOverflowChecker; class nsTreeImageListener; diff --git a/layout/xul/base/src/tree/src/nsTreeImageListener.cpp b/layout/xul/base/src/tree/src/nsTreeImageListener.cpp index eb16264847e..3155f5d9224 100644 --- a/layout/xul/base/src/tree/src/nsTreeImageListener.cpp +++ b/layout/xul/base/src/tree/src/nsTreeImageListener.cpp @@ -42,7 +42,7 @@ #include "imgIRequest.h" #include "imgIContainer.h" -NS_IMPL_ISUPPORTS3(nsTreeImageListener, imgIDecoderObserver, imgIContainerObserver, nsITreeImageListener) +NS_IMPL_ISUPPORTS2(nsTreeImageListener, imgIDecoderObserver, imgIContainerObserver) nsTreeImageListener::nsTreeImageListener(nsTreeBodyFrame* aTreeFrame) : mTreeFrame(aTreeFrame), @@ -92,7 +92,7 @@ NS_IMETHODIMP nsTreeImageListener::FrameChanged(imgIContainer *aContainer, } -NS_IMETHODIMP +void nsTreeImageListener::AddCell(PRInt32 aIndex, nsITreeColumn* aCol) { if (!mInvalidationArea) { @@ -114,8 +114,6 @@ nsTreeImageListener::AddCell(PRInt32 aIndex, nsITreeColumn* aCol) mInvalidationArea->AddRow(aIndex); } } - - return NS_OK; } diff --git a/layout/xul/base/src/tree/src/nsTreeImageListener.h b/layout/xul/base/src/tree/src/nsTreeImageListener.h index c32501b38cf..e0beba4d915 100644 --- a/layout/xul/base/src/tree/src/nsTreeImageListener.h +++ b/layout/xul/base/src/tree/src/nsTreeImageListener.h @@ -45,10 +45,9 @@ #include "nsITreeColumns.h" #include "nsStubImageDecoderObserver.h" #include "nsTreeBodyFrame.h" -#include "nsITreeImageListener.h" // This class handles image load observation. -class nsTreeImageListener : public nsStubImageDecoderObserver, public nsITreeImageListener +class nsTreeImageListener : public nsStubImageDecoderObserver { public: nsTreeImageListener(nsTreeBodyFrame *aTreeFrame); @@ -64,7 +63,6 @@ public: NS_IMETHOD FrameChanged(imgIContainer *aContainer, const nsIntRect *aDirtyRect); - NS_IMETHOD AddCell(PRInt32 aIndex, nsITreeColumn* aCol); NS_IMETHOD ClearFrame(); friend class nsTreeBodyFrame; @@ -72,6 +70,7 @@ public: protected: void UnsuppressInvalidation() { mInvalidationSuppressed = false; } void Invalidate(); + void AddCell(PRInt32 aIndex, nsITreeColumn* aCol); private: nsTreeBodyFrame* mTreeFrame; diff --git a/netwerk/protocol/http/nsHttpPipeline.cpp b/netwerk/protocol/http/nsHttpPipeline.cpp index 46eeb8cf5b5..1ed0b907551 100644 --- a/netwerk/protocol/http/nsHttpPipeline.cpp +++ b/netwerk/protocol/http/nsHttpPipeline.cpp @@ -166,7 +166,8 @@ nsHttpPipeline::OnHeadersAvailable(nsAHttpTransaction *trans, nsresult nsHttpPipeline::ResumeSend() { - NS_NOTREACHED("nsHttpPipeline::ResumeSend"); + if (mConnection) + return mConnection->ResumeSend(); return NS_ERROR_UNEXPECTED; } @@ -411,7 +412,17 @@ nsHttpPipeline::OnTransportStatus(nsITransport* transport, bool nsHttpPipeline::IsDone() { - return (mRequestQ.Length() == 0) && (mResponseQ.Length() == 0); + bool done = true; + + PRUint32 i, count = mRequestQ.Length(); + for (i = 0; done && (i < count); i++) + done = Request(i)->IsDone(); + + count = mResponseQ.Length(); + for (i = 0; done && (i < count); i++) + done = Response(i)->IsDone(); + + return done; } nsresult diff --git a/services/sync/tests/tps/all_tests.json b/services/sync/tests/tps/all_tests.json index 9e0178bed88..43f4bedea21 100644 --- a/services/sync/tests/tps/all_tests.json +++ b/services/sync/tests/tps/all_tests.json @@ -21,8 +21,7 @@ "test_privbrw_tabs.js", "test_bookmarks_in_same_named_folder.js", "test_client_wipe.js", - "test_special_tabs.js", - "test_mozmill_sanity.js" + "test_special_tabs.js" ] } diff --git a/services/sync/tests/tps/test_addon_sanity.js b/services/sync/tests/tps/test_addon_sanity.js new file mode 100644 index 00000000000..78d56f4908d --- /dev/null +++ b/services/sync/tests/tps/test_addon_sanity.js @@ -0,0 +1,50 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * The list of phases mapped to their corresponding profiles. The object + * here must be in strict JSON format, as it will get parsed by the Python + * testrunner (no single quotes, extra comma's, etc). + */ + +var phases = { "phase1": "profile1", + "phase2": "profile1", + "phase3": "profile1", + "phase4": "profile1", + "phase5": "profile1" }; + +/* + * Test phases + */ + +Phase('phase1', [ + [Addons.install, ['unsigned-1.0.xml']], + [Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_DISABLED], + [Sync, SYNC_WIPE_SERVER], +]); + +Phase('phase2', [ + [Sync], + [Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_ENABLED], + [Addons.setState, ['unsigned-xpi@tests.mozilla.org'], STATE_DISABLED], + [Sync], +]); + +Phase('phase3', [ + [Sync], + [Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_DISABLED], + [Addons.setState, ['unsigned-xpi@tests.mozilla.org'], STATE_ENABLED], + [Sync], +]); + +Phase('phase4', [ + [Sync], + [Addons.verify, ['unsigned-xpi@tests.mozilla.org'], STATE_ENABLED], + [Addons.uninstall, ['unsigned-xpi@tests.mozilla.org']], + [Sync], +]); + +Phase('phase5', [ + [Sync], + [Addons.verifyNot, ['unsigned-xpi@tests.mozilla.org']], +]); diff --git a/services/sync/tests/tps/unsigned-1.0.xml b/services/sync/tests/tps/unsigned-1.0.xml new file mode 100644 index 00000000000..e311f47ddcc --- /dev/null +++ b/services/sync/tests/tps/unsigned-1.0.xml @@ -0,0 +1,27 @@ + + + + Unsigned Test XPI + Extension + unsigned-xpi@tests.mozilla.org + unsigned-xpi + 1.0 + + + Firefox + 1 + 3.6 + * + {ec8030f7-c20a-464f-9b0e-13a3a9e97384} + + ALL + + http://127.0.0.1:4567/unsigned-1.0.xpi + + 2009-09-14T04:47:42Z + + + 2011-09-05T20:42:09Z + + + \ No newline at end of file diff --git a/services/sync/tests/tps/unsigned-1.0.xpi b/services/sync/tests/tps/unsigned-1.0.xpi new file mode 100644 index 00000000000..51b00475a96 Binary files /dev/null and b/services/sync/tests/tps/unsigned-1.0.xpi differ diff --git a/services/sync/tests/unit/xpcshell.ini b/services/sync/tests/unit/xpcshell.ini index 30a5cd83751..f8cc583e624 100644 --- a/services/sync/tests/unit/xpcshell.ini +++ b/services/sync/tests/unit/xpcshell.ini @@ -30,9 +30,8 @@ tail = # Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini) skip-if = os == "android" [test_errorhandler_sync_checkServerError.js] -# Bug 604565: this test intermittently hangs on OS X debug builds. # Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini) -skip-if = (os == "mac" && debug) || os == "android" +skip-if = os == "android" [test_forms_store.js] [test_forms_tracker.js] [test_history_engine.js] @@ -80,13 +79,11 @@ skip-if = os == "win" || os == "android" [test_service_sync_401.js] [test_service_sync_locked.js] [test_service_sync_remoteSetup.js] -# Bug 604565: this test intermittently hangs on OS X debug builds. # Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini) -skip-if = (os == "mac" && debug) || os == "android" +skip-if = os == "android" [test_service_sync_updateEnabledEngines.js] -# Bug 604565: this test intermittently hangs on OS X debug builds. # Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini) -skip-if = (os == "mac" && debug) || os == "android" +skip-if = os == "android" [test_service_verifyLogin.js] [test_service_wipeClient.js] [test_service_wipeServer.js] @@ -94,9 +91,8 @@ skip-if = (os == "mac" && debug) || os == "android" [test_status_checkSetup.js] [test_syncengine.js] [test_syncengine_sync.js] -# Bug 604565: this test intermittently hangs on OS X debug builds. # Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini) -skip-if = (os == "mac" && debug) || os == "android" +skip-if = os == "android" [test_syncscheduler.js] [test_syncstoragerequest.js] [test_tab_engine.js] diff --git a/services/sync/tps/extensions/tps/modules/addons.jsm b/services/sync/tps/extensions/tps/modules/addons.jsm new file mode 100644 index 00000000000..9324b7a0fad --- /dev/null +++ b/services/sync/tps/extensions/tps/modules/addons.jsm @@ -0,0 +1,252 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Crossweave. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jonathan Griffin + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +var EXPORTED_SYMBOLS = ["Addon", "STATE_ENABLED", "STATE_DISABLED"]; + +const CC = Components.classes; +const CI = Components.interfaces; +const CU = Components.utils; + +CU.import("resource://gre/modules/AddonManager.jsm"); +CU.import("resource://gre/modules/AddonRepository.jsm"); +CU.import("resource://gre/modules/Services.jsm"); +CU.import("resource://services-sync/async.js"); +CU.import("resource://services-sync/util.js"); +CU.import("resource://tps/logger.jsm"); +var XPIProvider = CU.import("resource://gre/modules/XPIProvider.jsm") + .XPIProvider; + +const ADDONSGETURL = 'http://127.0.0.1:4567/'; +const STATE_ENABLED = 1; +const STATE_DISABLED = 2; + +function GetFileAsText(file) +{ + let channel = Services.io.newChannel(file, null, null); + let inputStream = channel.open(); + if (channel instanceof CI.nsIHttpChannel && + channel.responseStatus != 200) { + return ""; + } + + let streamBuf = ""; + let sis = CC["@mozilla.org/scriptableinputstream;1"] + .createInstance(CI.nsIScriptableInputStream); + sis.init(inputStream); + + let available; + while ((available = sis.available()) != 0) { + streamBuf += sis.read(available); + } + + inputStream.close(); + return streamBuf; +} + +function Addon(TPS, id) { + this.TPS = TPS; + this.id = id; +} + +Addon.prototype = { + _addons_requiring_restart: [], + _addons_pending_install: [], + + Delete: function() { + // find our addon locally + let cb = Async.makeSyncCallback(); + XPIProvider.getAddonsByTypes(null, cb); + let results = Async.waitForSyncCallback(cb); + var addon; + var id = this.id; + results.forEach(function(result) { + if (result.id == id) { + addon = result; + } + }); + Logger.AssertTrue(!!addon, 'could not find addon ' + this.id + ' to uninstall'); + addon.uninstall(); + }, + + Find: function(state) { + let cb = Async.makeSyncCallback(); + let addon_found = false; + var that = this; + + var log_addon = function(addon) { + that.addon = addon; + Logger.logInfo('addon ' + addon.id + ' found, isActive: ' + addon.isActive); + if (state == STATE_ENABLED || state == STATE_DISABLED) { + Logger.AssertEqual(addon.isActive, + state == STATE_ENABLED ? true : false, + "addon " + that.id + " has an incorrect enabled state"); + } + }; + + // first look in the list of all addons + XPIProvider.getAddonsByTypes(null, cb); + let addonlist = Async.waitForSyncCallback(cb); + addonlist.forEach(function(addon) { + if (addon.id == that.id) { + addon_found = true; + log_addon.call(that, addon); + } + }); + + if (!addon_found) { + // then look in the list of recent installs + cb = Async.makeSyncCallback(); + XPIProvider.getInstallsByTypes(null, cb); + addonlist = Async.waitForSyncCallback(cb); + for (var i in addonlist) { + if (addonlist[i].addon && addonlist[i].addon.id == that.id && + addonlist[i].state == AddonManager.STATE_INSTALLED) { + addon_found = true; + log_addon.call(that, addonlist[i].addon); + } + } + } + + return addon_found; + }, + + Install: function() { + // For Install, the id parameter initially passed is really the filename + // for the addon's install .xml; we'll read the actual id from the .xml. + let url = this.id; + + // set the url used by getAddonsByIDs + var prefs = CC["@mozilla.org/preferences-service;1"] + .getService(CI.nsIPrefBranch); + prefs.setCharPref('extensions.getAddons.get.url', ADDONSGETURL + url); + + // read the XML and find the addon id + xml = GetFileAsText(ADDONSGETURL + url); + Logger.AssertTrue(xml.indexOf("") > -1, 'guid not found in ' + url); + this.id = xml.substring(xml.indexOf("") + 6, xml.indexOf(" -1, + "onInstallEnded received for unexpected addon " + addon.addon.id); + this._addons_pending_install.splice( + this._addons_pending_install.indexOf(addon.addon.id), + 1); + } + catch(e) { + // We can't throw during a callback, as it will just get eaten by + // the callback's caller. + Utils.nextTick(function() { + this.DumpError(e); + }, this); + return; + } + this.TPS.FinishAsyncOperation(); + }, + + onInstallFailed: function(addon) { + Logger.logInfo('--------- event observed: addon onInstallFailed'); + Utils.nextTick(function() { + this.DumpError('Installation failed for addon ' + + (addon.addon && addon.addon.id ? addon.addon.id : 'unknown')); + }, this); + }, + + onDownloadFailed: function(addon) { + Logger.logInfo('--------- event observed: addon onDownloadFailed'); + Utils.nextTick(function() { + this.DumpError('Download failed for addon ' + + (addon.addon && addon.addon.id ? addon.addon.id : 'unknown')); + }, this); + }, + +}; diff --git a/services/sync/tps/extensions/tps/modules/tps.jsm b/services/sync/tps/extensions/tps/modules/tps.jsm index d9c20014a4e..3824405b7a0 100644 --- a/services/sync/tps/extensions/tps/modules/tps.jsm +++ b/services/sync/tps/extensions/tps/modules/tps.jsm @@ -48,9 +48,11 @@ const CU = Components.utils; CU.import("resource://services-sync/service.js"); CU.import("resource://services-sync/constants.js"); +CU.import("resource://services-sync/async.js"); CU.import("resource://services-sync/util.js"); CU.import("resource://gre/modules/XPCOMUtils.jsm"); CU.import("resource://gre/modules/Services.jsm"); +CU.import("resource://tps/addons.jsm"); CU.import("resource://tps/bookmarks.jsm"); CU.import("resource://tps/logger.jsm"); CU.import("resource://tps/passwords.jsm"); @@ -61,6 +63,8 @@ CU.import("resource://tps/tabs.jsm"); var hh = CC["@mozilla.org/network/protocol;1?name=http"] .getService(CI.nsIHttpProtocolHandler); +var prefs = CC["@mozilla.org/preferences-service;1"] + .getService(CI.nsIPrefBranch); var mozmillInit = {}; CU.import('resource://mozmill/modules/init.js', mozmillInit); @@ -73,37 +77,16 @@ const ACTION_SYNC = "sync"; const ACTION_DELETE = "delete"; const ACTION_PRIVATE_BROWSING = "private-browsing"; const ACTION_WIPE_SERVER = "wipe-server"; +const ACTION_SETSTATE = "set-state"; const ACTIONS = [ACTION_ADD, ACTION_VERIFY, ACTION_VERIFY_NOT, ACTION_MODIFY, ACTION_SYNC, ACTION_DELETE, - ACTION_PRIVATE_BROWSING, ACTION_WIPE_SERVER]; + ACTION_PRIVATE_BROWSING, ACTION_WIPE_SERVER, + ACTION_SETSTATE]; const SYNC_WIPE_SERVER = "wipe-server"; const SYNC_RESET_CLIENT = "reset-client"; const SYNC_WIPE_CLIENT = "wipe-client"; -function GetFileAsText(file) -{ - let channel = Services.io.newChannel(file, null, null); - let inputStream = channel.open(); - if (channel instanceof CI.nsIHttpChannel && - channel.responseStatus != 200) { - return ""; - } - - let streamBuf = ""; - let sis = CC["@mozilla.org/scriptableinputstream;1"] - .createInstance(CI.nsIScriptableInputStream); - sis.init(inputStream); - - let available; - while ((available = sis.available()) != 0) { - streamBuf += sis.read(available); - } - - inputStream.close(); - return streamBuf; -} - var TPS = { _waitingForSync: false, @@ -351,6 +334,33 @@ var TPS = } }, + HandleAddons: function (addons, action, state) { + for (var i in addons) { + Logger.logInfo("executing action " + action.toUpperCase() + + " on addon " + JSON.stringify(addons[i])); + var addon = new Addon(this, addons[i]); + switch(action) { + case ACTION_ADD: + addon.Install(); + break; + case ACTION_DELETE: + addon.Delete(); + break; + case ACTION_VERIFY: + Logger.AssertTrue(addon.Find(state), 'addon ' + addon.id + ' not found'); + break; + case ACTION_VERIFY_NOT: + Logger.AssertTrue(!addon.Find(state), 'addon ' + addon.id + " is present, but it shouldn't be"); + break; + case ACTION_SETSTATE: + Logger.AssertTrue(addon.SetState(state), 'addon ' + addon.id + ' not found'); + break; + } + } + Logger.logPass("executing action " + action.toUpperCase() + + " on addons"); + }, + HandleBookmarks: function (bookmarks, action) { try { let items = []; @@ -460,7 +470,7 @@ var TPS = let phase = this._phaselist["phase" + this._currentPhase]; let action = phase[this._currentAction]; Logger.logInfo("starting action: " + JSON.stringify(action)); - action[0].call(this, action[1]); + action[0].apply(this, action.slice(1)); // if we're in an async operation, don't continue on to the next action if (this._operations_pending) @@ -517,8 +527,6 @@ var TPS = // Store account details as prefs so they're accessible to the mozmill // framework. - let prefs = CC["@mozilla.org/preferences-service;1"] - .getService(CI.nsIPrefBranch); prefs.setCharPref('tps.account.username', this.config.account.username); prefs.setCharPref('tps.account.password', this.config.account.password); prefs.setCharPref('tps.account.passphrase', this.config.account.passphrase); @@ -634,6 +642,24 @@ var TPS = }, }; +var Addons = { + install: function Addons__install(addons) { + TPS.HandleAddons(addons, ACTION_ADD); + }, + setState: function Addons__setState(addons, state) { + TPS.HandleAddons(addons, ACTION_SETSTATE, state); + }, + uninstall: function Addons__uninstall(addons) { + TPS.HandleAddons(addons, ACTION_DELETE); + }, + verify: function Addons__verify(addons, state) { + TPS.HandleAddons(addons, ACTION_VERIFY, state); + }, + verifyNot: function Addons__verifyNot(addons) { + TPS.HandleAddons(addons, ACTION_VERIFY_NOT); + }, +}; + var Bookmarks = { add: function Bookmarks__add(bookmarks) { TPS.HandleBookmarks(bookmarks, ACTION_ADD); diff --git a/testing/mochitest/Makefile.in b/testing/mochitest/Makefile.in index 2a8eb7dd21a..6e38bc9c433 100644 --- a/testing/mochitest/Makefile.in +++ b/testing/mochitest/Makefile.in @@ -82,7 +82,6 @@ _SERV_FILES = \ $(topsrcdir)/build/mobile/devicemanagerADB.py \ $(topsrcdir)/build/mobile/devicemanagerSUT.py \ $(topsrcdir)/build/automationutils.py \ - $(topsrcdir)/build/poster.zip \ $(topsrcdir)/build/mobile/remoteautomation.py \ gen_template.pl \ server.js \ diff --git a/testing/tps/tps/__init__.py b/testing/tps/tps/__init__.py index 6d710ca4ce5..a9ad3167302 100644 --- a/testing/tps/tps/__init__.py +++ b/testing/tps/tps/__init__.py @@ -38,4 +38,5 @@ from firefoxrunner import TPSFirefoxRunner from pulse import TPSPulseMonitor from testrunner import TPSTestRunner +from mozhttpd import MozHttpd diff --git a/testing/tps/tps/mozhttpd.py b/testing/tps/tps/mozhttpd.py new file mode 100644 index 00000000000..daccf8ff41a --- /dev/null +++ b/testing/tps/tps/mozhttpd.py @@ -0,0 +1,111 @@ +#!/usr/bin/python +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2011 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Joel Maher +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +import BaseHTTPServer +import SimpleHTTPServer +import threading +import sys +import os +import urllib +import re +from urlparse import urlparse +from SocketServer import ThreadingMixIn + +DOCROOT = '.' + +class EasyServer(ThreadingMixIn, BaseHTTPServer.HTTPServer): + allow_reuse_address = True + +class MozRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + def translate_path(self, path): + # It appears that the default path is '/' and os.path.join makes the '/' + o = urlparse(path) + return "%s%s" % ('' if sys.platform == 'win32' else '/', '/'.join([i.strip('/') for i in (DOCROOT, o.path)])) + + # I found on my local network that calls to this were timing out + # I believe all of these calls are from log_message + def address_string(self): + return "a.b.c.d" + + # This produces a LOT of noise + def log_message(self, format, *args): + pass + +class MozHttpd(object): + def __init__(self, host="127.0.0.1", port=8888, docroot='.'): + global DOCROOT + self.host = host + self.port = int(port) + DOCROOT = docroot + + def start(self): + self.httpd = EasyServer((self.host, self.port), MozRequestHandler) + self.server = threading.Thread(target=self.httpd.serve_forever) + self.server.setDaemon(True) # don't hang on exit + self.server.start() + #self.testServer() + + #TODO: figure this out + def testServer(self): + fileList = os.listdir(DOCROOT) + filehandle = urllib.urlopen('http://%s:%s' % (self.host, self.port)) + data = filehandle.readlines(); + filehandle.close() + + for line in data: + found = False + # '@' denotes a symlink and we need to ignore it. + webline = re.sub('\<[a-zA-Z0-9\-\_\.\=\"\'\/\\\%\!\@\#\$\^\&\*\(\) ]*\>', '', line.strip('\n')).strip('/').strip().strip('@') + if webline != "": + if webline == "Directory listing for": + found = True + else: + for fileName in fileList: + if fileName == webline: + found = True + + if (found == False): + print "NOT FOUND: " + webline.strip() + + def stop(self): + if self.httpd: + self.httpd.shutdown() + + __del__ = stop + diff --git a/testing/tps/tps/testrunner.py b/testing/tps/tps/testrunner.py index bf107b83d6d..4ecf5287677 100644 --- a/testing/tps/tps/testrunner.py +++ b/testing/tps/tps/testrunner.py @@ -53,7 +53,7 @@ from mozprofile import Profile from tps.firefoxrunner import TPSFirefoxRunner from tps.phase import TPSTestPhase - +from tps.mozhttpd import MozHttpd class TempFile(object): """Class for temporary files that delete themselves when garbage-collected. @@ -397,6 +397,9 @@ class TPSTestRunner(object): testlist = [os.path.basename(self.testfile)] testdir = os.path.dirname(self.testfile) + self.mozhttpd = MozHttpd(port=4567, docroot=testdir) + self.mozhttpd.start() + # run each test, and save the results for test in testlist: result = self.run_single_test(testdir, test) @@ -415,6 +418,8 @@ class TPSTestRunner(object): else: self.numfailed += 1 + self.mozhttpd.stop() + # generate the postdata we'll use to post the results to the db self.postdata = { 'tests': self.results, 'os':os_string, @@ -440,7 +445,7 @@ class TPSTestRunner(object): self.numpassed, self.numfailed, self.config['account']['serverURL'], - self.buildUrl) + buildUrl) subj = "TPS Report: " if self.numfailed == 0 and self.numpassed > 0: diff --git a/testing/xpcshell/Makefile.in b/testing/xpcshell/Makefile.in index 8528c3dba1b..d1a37405526 100644 --- a/testing/xpcshell/Makefile.in +++ b/testing/xpcshell/Makefile.in @@ -65,7 +65,6 @@ EXTRA_BUILD_FILES := \ automationutils.py \ manifestparser.py \ mozinfo.py \ - poster.zip \ $(NULL) # And files for running xpcshell remotely from $(topsrcdir)/build/mobile