This commit is contained in:
Doug Turner 2011-11-15 11:18:06 -08:00
Родитель 4fbd70a78b 4c050d1ea6
Коммит 56609ba3d8
36 изменённых файлов: 747 добавлений и 277 удалений

10
.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

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

@ -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.

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

@ -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)))

Двоичные данные
build/poster.zip

Двоичный файл не отображается.

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

@ -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

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

@ -427,7 +427,7 @@ nsSVGPathElement::ConstructPath(gfxContext *aCtx)
}
gfxFloat
nsSVGPathElement::GetScale()
nsSVGPathElement::GetPathLengthScale()
{
if (mPathLength.IsExplicitlySet()) {

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

@ -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 <path> element's 'pathLength' attribute). This
* is used to scale stroke dashing, and to scale offsets along a textPath.
*/
gfxFloat GetPathLengthScale();
protected:

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

@ -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;
}

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

@ -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

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

@ -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

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

@ -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);

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

@ -49,6 +49,8 @@
#include "nsImageFrame.h"
#include "nsRenderingContext.h"
#include "mozilla/Preferences.h"
#ifdef DEBUG
#include <stdio.h>
#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::DisplayItemData>*
FrameLayerBuilder::GetDisplayItemDataArrayForFrame(nsIFrame* aFrame)
{
@ -2127,6 +2150,8 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
if (setClipRect) {
aContext->Restore();
}
FlashPaint(aContext);
}
bool

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

@ -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.

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

@ -120,7 +120,8 @@ nsSVGGeometryFrame::GetStrokeDashArray(gfxFloat **aDashes, PRUint32 *aCount)
gfxFloat pathScale = 1.0;
if (mContent->Tag() == nsGkAtoms::path) {
pathScale = static_cast<nsSVGPathElement*>(mContent)->GetScale();
pathScale =
static_cast<nsSVGPathElement*>(mContent)->GetPathLengthScale();
if (pathScale <= 0) {
return NS_OK;
}

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

@ -751,7 +751,7 @@ nsSVGGlyphFrame::GetCharacterPositions(nsTArray<CharacterPosition>* 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<float> dxList, dyList;
GetEffectiveDxDy(strLength, dxList, dyList);

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

@ -166,17 +166,18 @@ nsSVGTextPathFrame::GetStartOffset()
nsRefPtr<gfxFlattenedPath> 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<nsSVGPathElement*>(pathFrame->GetContent())->GetScale();
return static_cast<nsSVGPathElement*>(pathFrame->GetContent())->
GetPathLengthScale();
}
//----------------------------------------------------------------------

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

@ -84,8 +84,20 @@ public:
already_AddRefed<gfxFlattenedPath> 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 <path>
* 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);

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

@ -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 \

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

@ -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 <hyatt@mozilla.org> (Original Author)
* Jan Varga <varga@ku.sk>
* Scott Johnson <sjohnson@mozilla.com>, 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

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

@ -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<imgIDecoderObserver> obs;
imgReq->GetDecoderObserver(getter_AddRefs(obs));
nsCOMPtr<nsITreeImageListener> listener(do_QueryInterface(obs));
if (listener)
listener->AddCell(aRowIndex, aCol);
if (obs) {
static_cast<nsTreeImageListener*> (obs.get())->AddCell(aRowIndex, aCol);
}
return NS_OK;
}
}

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

@ -61,7 +61,6 @@
#include "nsScrollbarFrame.h"
#include "nsThreadUtils.h"
#include "mozilla/LookAndFeel.h"
#include "nsITreeImageListener.h"
class nsOverflowChecker;
class nsTreeImageListener;

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

@ -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;
}

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

@ -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;

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

@ -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

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

@ -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"
]
}

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

@ -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']],
]);

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

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<searchresults total_results="1">
<addon id="5612">
<name>Unsigned Test XPI</name>
<type id="1">Extension</type>
<guid>unsigned-xpi@tests.mozilla.org</guid>
<slug>unsigned-xpi</slug>
<version>1.0</version>
<compatible_applications><application>
<name>Firefox</name>
<application_id>1</application_id>
<min_version>3.6</min_version>
<max_version>*</max_version>
<appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
</application></compatible_applications>
<all_compatible_os><os>ALL</os></all_compatible_os>
<install os="ALL" size="452">http://127.0.0.1:4567/unsigned-1.0.xpi</install>
<created epoch="1252903662">
2009-09-14T04:47:42Z
</created>
<last_updated epoch="1315255329">
2011-09-05T20:42:09Z
</last_updated>
</addon>
</searchresults>

Двоичные данные
services/sync/tests/tps/unsigned-1.0.xpi Normal file

Двоичный файл не отображается.

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

@ -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]

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

@ -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 <jgriffin@mozilla.com>
*
* 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("<guid>") > -1, 'guid not found in ' + url);
this.id = xml.substring(xml.indexOf("<guid>") + 6, xml.indexOf("</guid"));
Logger.logInfo('addon XML = ' + this.id);
// find our addon on 'AMO'
let cb = Async.makeSyncCallback();
AddonRepository.getAddonsByIDs([this.id], {
searchSucceeded: cb,
searchFailed: cb
}, false);
// Result will be array of addons on searchSucceeded or undefined on
// searchFailed.
let install_addons = Async.waitForSyncCallback(cb);
Logger.AssertTrue(install_addons,
"no addons found for id " + this.id);
Logger.AssertEqual(install_addons.length,
1,
"multiple addons found for id " + this.id);
let addon = install_addons[0];
Logger.logInfo(JSON.stringify(addon), null, ' ');
if (XPIProvider.installRequiresRestart(addon)) {
this._addons_requiring_restart.push(addon.id);
}
// Start installing the addon asynchronously; finish up in
// onInstallEnded(), onInstallFailed(), or onDownloadFailed().
this._addons_pending_install.push(addon.id);
this.TPS.StartAsyncOperation();
Utils.nextTick(function() {
let callback = function(aInstall) {
addon.install = aInstall;
Logger.logInfo("addon install: " + addon.install);
Logger.AssertTrue(addon.install,
"could not get install object for id " + this.id);
addon.install.addListener(this);
addon.install.install();
};
AddonManager.getInstallForURL(addon.sourceURI.spec,
callback.bind(this),
"application/x-xpinstall");
}, this);
},
SetState: function(state) {
if (!this.Find())
return false;
this.addon.userDisabled = state == STATE_ENABLED ? false : true;
return true;
},
// addon installation callbacks
onInstallEnded: function(addon) {
try {
Logger.logInfo('--------- event observed: addon onInstallEnded');
Logger.AssertTrue(addon.addon,
"No addon object in addon instance passed to onInstallEnded");
Logger.AssertTrue(this._addons_pending_install.indexOf(addon.addon.id) > -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);
},
};

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

@ -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);

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

@ -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 \

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

@ -38,4 +38,5 @@
from firefoxrunner import TPSFirefoxRunner
from pulse import TPSPulseMonitor
from testrunner import TPSTestRunner
from mozhttpd import MozHttpd

111
testing/tps/tps/mozhttpd.py Normal file
Просмотреть файл

@ -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 <joel.maher@gmail.com>
#
# 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

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

@ -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:

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

@ -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